From ad11c991b9fefd5b840567215673f2e976e7d532 Mon Sep 17 00:00:00 2001 From: lukasamd Date: Thu, 19 Feb 2015 08:43:42 +0100 Subject: [PATCH] Wersja 1.8.3 - Pliki Polskiej Paczki MyBB 1.8.3 --- Upload/admin/backups/index.html | 8 + Upload/admin/inc/class_form.php | 1054 ++ Upload/admin/inc/class_page.php | 1166 ++ Upload/admin/inc/class_table.php | 297 + Upload/admin/inc/functions.php | 798 + Upload/admin/inc/functions_themes.php | 1535 ++ Upload/admin/inc/functions_view_manager.php | 668 + Upload/admin/inc/index.html | 8 + Upload/admin/index.php | 598 + Upload/admin/jscripts/admincp.js | 23 + Upload/admin/jscripts/codemirror/LICENSE | 19 + .../codemirror/addon/comment/comment.js | 172 + .../addon/comment/continuecomment.js | 85 + .../codemirror/addon/dialog/dialog-mybb.css | 32 + .../codemirror/addon/dialog/dialog.css | 32 + .../codemirror/addon/dialog/dialog.js | 137 + .../codemirror/addon/dialog/index.html | 8 + .../codemirror/addon/display/fullscreen.css | 6 + .../codemirror/addon/display/fullscreen.js | 41 + .../codemirror/addon/display/placeholder.js | 58 + .../codemirror/addon/display/rulers.js | 64 + .../codemirror/addon/edit/closebrackets.js | 143 + .../codemirror/addon/edit/closetag.js | 141 + .../codemirror/addon/edit/continuelist.js | 38 + .../codemirror/addon/edit/matchbrackets.js | 120 + .../codemirror/addon/edit/matchtags.js | 66 + .../codemirror/addon/edit/trailingspace.js | 27 + .../codemirror/addon/fold/brace-fold.js | 105 + .../codemirror/addon/fold/comment-fold.js | 57 + .../codemirror/addon/fold/foldcode.js | 145 + .../codemirror/addon/fold/foldgutter.css | 20 + .../codemirror/addon/fold/foldgutter.js | 134 + .../codemirror/addon/fold/indent-fold.js | 44 + .../codemirror/addon/fold/markdown-fold.js | 49 + .../codemirror/addon/fold/xml-fold.js | 181 + .../codemirror/addon/hint/anyword-hint.js | 42 + .../codemirror/addon/hint/css-hint.js | 56 + .../codemirror/addon/hint/html-hint.js | 348 + .../codemirror/addon/hint/javascript-hint.js | 141 + .../codemirror/addon/hint/python-hint.js | 102 + .../codemirror/addon/hint/show-hint.css | 38 + .../codemirror/addon/hint/show-hint.js | 389 + .../codemirror/addon/hint/sql-hint.js | 164 + .../codemirror/addon/hint/xml-hint.js | 103 + .../jscripts/codemirror/addon/index.html | 8 + .../addon/lint/coffeescript-lint.js | 41 + .../codemirror/addon/lint/css-lint.js | 35 + .../codemirror/addon/lint/javascript-lint.js | 136 + .../codemirror/addon/lint/json-lint.js | 31 + .../jscripts/codemirror/addon/lint/lint.css | 73 + .../jscripts/codemirror/addon/lint/lint.js | 210 + .../codemirror/addon/lint/yaml-lint.js | 28 + .../jscripts/codemirror/addon/merge/merge.css | 92 + .../jscripts/codemirror/addon/merge/merge.js | 513 + .../codemirror/addon/mode/loadmode.js | 61 + .../codemirror/addon/mode/multiplex.js | 118 + .../codemirror/addon/mode/multiplex_test.js | 33 + .../jscripts/codemirror/addon/mode/overlay.js | 85 + .../codemirror/addon/runmode/colorize.js | 40 + .../addon/runmode/runmode-standalone.js | 153 + .../codemirror/addon/runmode/runmode.js | 72 + .../codemirror/addon/runmode/runmode.node.js | 122 + .../codemirror/addon/scroll/scrollpastend.js | 46 + .../codemirror/addon/search/index.html | 8 + .../addon/search/match-highlighter.js | 104 + .../codemirror/addon/search/search.js | 158 + .../codemirror/addon/search/searchcursor.js | 189 + .../codemirror/addon/selection/active-line.js | 71 + .../addon/selection/mark-selection.js | 118 + .../jscripts/codemirror/addon/tern/tern.css | 86 + .../jscripts/codemirror/addon/tern/tern.js | 668 + .../jscripts/codemirror/addon/tern/worker.js | 44 + .../codemirror/addon/wrap/hardwrap.js | 139 + Upload/admin/jscripts/codemirror/index.html | 8 + .../admin/jscripts/codemirror/keymap/emacs.js | 402 + .../jscripts/codemirror/keymap/sublime.js | 520 + .../admin/jscripts/codemirror/keymap/vim.js | 4466 +++++ .../jscripts/codemirror/lib/codemirror.css | 301 + .../jscripts/codemirror/lib/codemirror.js | 7638 +++++++++ .../admin/jscripts/codemirror/lib/index.html | 8 + .../admin/jscripts/codemirror/mode/css/css.js | 717 + .../jscripts/codemirror/mode/css/index.html | 70 + .../jscripts/codemirror/mode/css/less.html | 152 + .../jscripts/codemirror/mode/css/less_test.js | 51 + .../jscripts/codemirror/mode/css/scss.html | 157 + .../jscripts/codemirror/mode/css/scss_test.js | 110 + .../jscripts/codemirror/mode/css/test.js | 135 + .../codemirror/mode/htmlmixed/htmlmixed.js | 120 + .../codemirror/mode/htmlmixed/index.html | 85 + .../codemirror/mode/javascript/index.html | 109 + .../codemirror/mode/javascript/javascript.js | 683 + .../codemirror/mode/javascript/json-ld.html | 72 + .../codemirror/mode/javascript/test.js | 181 + .../mode/javascript/typescript.html | 61 + .../jscripts/codemirror/mode/xml/index.html | 57 + .../jscripts/codemirror/mode/xml/test.js | 51 + .../admin/jscripts/codemirror/mode/xml/xml.js | 384 + .../jscripts/codemirror/theme/3024-day.css | 38 + .../jscripts/codemirror/theme/3024-night.css | 37 + .../codemirror/theme/ambiance-mobile.css | 5 + .../jscripts/codemirror/theme/ambiance.css | 77 + .../jscripts/codemirror/theme/base16-dark.css | 36 + .../codemirror/theme/base16-light.css | 36 + .../jscripts/codemirror/theme/blackboard.css | 30 + .../jscripts/codemirror/theme/cobalt.css | 23 + .../jscripts/codemirror/theme/eclipse.css | 23 + .../jscripts/codemirror/theme/elegant.css | 13 + .../jscripts/codemirror/theme/erlang-dark.css | 32 + .../jscripts/codemirror/theme/index.html | 110 + .../jscripts/codemirror/theme/lesser-dark.css | 45 + .../admin/jscripts/codemirror/theme/mbo.css | 39 + .../jscripts/codemirror/theme/mdn-like.css | 44 + .../jscripts/codemirror/theme/midnight.css | 45 + .../jscripts/codemirror/theme/monokai.css | 31 + .../admin/jscripts/codemirror/theme/mybb.css | 41 + .../admin/jscripts/codemirror/theme/neat.css | 12 + .../admin/jscripts/codemirror/theme/neo.css | 43 + .../admin/jscripts/codemirror/theme/night.css | 26 + .../codemirror/theme/paraiso-dark.css | 36 + .../codemirror/theme/paraiso-light.css | 36 + .../codemirror/theme/pastel-on-dark.css | 50 + .../jscripts/codemirror/theme/rubyblue.css | 23 + .../jscripts/codemirror/theme/solarized.css | 170 + .../jscripts/codemirror/theme/the-matrix.css | 28 + .../theme/tomorrow-night-eighties.css | 36 + .../jscripts/codemirror/theme/twilight.css | 30 + .../jscripts/codemirror/theme/vibrant-ink.css | 32 + .../jscripts/codemirror/theme/xq-dark.css | 51 + .../jscripts/codemirror/theme/xq-light.css | 43 + Upload/admin/jscripts/index.html | 8 + .../css/redmond/images/animated-overlay.gif | Bin 0 -> 1738 bytes .../images/ui-bg_flat_0_aaaaaa_40x100.png | Bin 0 -> 212 bytes .../images/ui-bg_flat_55_fbec88_40x100.png | Bin 0 -> 206 bytes .../images/ui-bg_glass_75_d0e5f5_1x400.png | Bin 0 -> 336 bytes .../images/ui-bg_glass_85_dfeffc_1x400.png | Bin 0 -> 341 bytes .../images/ui-bg_glass_95_fef1ec_1x400.png | Bin 0 -> 332 bytes .../ui-bg_gloss-wave_55_5c9ccc_500x100.png | Bin 0 -> 5824 bytes .../ui-bg_inset-hard_100_f5f8f9_1x100.png | Bin 0 -> 333 bytes .../ui-bg_inset-hard_100_fcfdfd_1x100.png | Bin 0 -> 292 bytes .../images/ui-icons_217bc0_256x240.png | Bin 0 -> 4549 bytes .../images/ui-icons_2e83ff_256x240.png | Bin 0 -> 4549 bytes .../images/ui-icons_469bdd_256x240.png | Bin 0 -> 4549 bytes .../images/ui-icons_6da8d5_256x240.png | Bin 0 -> 4549 bytes .../images/ui-icons_cd0a0a_256x240.png | Bin 0 -> 4549 bytes .../images/ui-icons_d8e7f3_256x240.png | Bin 0 -> 4549 bytes .../images/ui-icons_f9bd01_256x240.png | Bin 0 -> 4549 bytes .../jqueryui/css/redmond/jquery-ui.min.css | 7 + .../css/redmond/jquery-ui.structure.min.css | 5 + .../css/redmond/jquery-ui.theme.min.css | 5 + .../jscripts/jqueryui/js/jquery-ui.min.js | 7 + Upload/admin/jscripts/mycode_sandbox.js | 57 + Upload/admin/jscripts/peeker.js | 101 + Upload/admin/jscripts/quick_perm_editor.js | 63 + Upload/admin/jscripts/search.js | 74 + Upload/admin/jscripts/tabs.js | 36 + Upload/admin/jscripts/theme_properties.js | 87 + Upload/admin/jscripts/themes.js | 353 + Upload/admin/jscripts/users.js | 13 + Upload/admin/jscripts/view_manager.js | 53 + .../admin/modules/config/attachment_types.php | 350 + Upload/admin/modules/config/badwords.php | 269 + Upload/admin/modules/config/banning.php | 294 + Upload/admin/modules/config/calendars.php | 486 + .../admin/modules/config/help_documents.php | 624 + Upload/admin/modules/config/index.html | 8 + Upload/admin/modules/config/languages.php | 1052 ++ Upload/admin/modules/config/mod_tools.php | 2362 +++ Upload/admin/modules/config/module_meta.php | 114 + Upload/admin/modules/config/mycode.php | 437 + Upload/admin/modules/config/plugins.php | 709 + Upload/admin/modules/config/post_icons.php | 499 + .../admin/modules/config/profile_fields.php | 795 + Upload/admin/modules/config/questions.php | 347 + Upload/admin/modules/config/settings.php | 1640 ++ Upload/admin/modules/config/smilies.php | 757 + Upload/admin/modules/config/spiders.php | 307 + .../admin/modules/config/thread_prefixes.php | 536 + Upload/admin/modules/config/warning.php | 774 + Upload/admin/modules/forum/announcements.php | 947 ++ Upload/admin/modules/forum/attachments.php | 945 ++ Upload/admin/modules/forum/index.html | 8 + Upload/admin/modules/forum/management.php | 2894 ++++ .../admin/modules/forum/moderation_queue.php | 567 + Upload/admin/modules/forum/module_meta.php | 76 + Upload/admin/modules/home/credits.php | 148 + Upload/admin/modules/home/index.html | 8 + Upload/admin/modules/home/index.php | 374 + Upload/admin/modules/home/module_meta.php | 173 + Upload/admin/modules/home/preferences.php | 107 + Upload/admin/modules/index.html | 8 + Upload/admin/modules/style/index.html | 8 + Upload/admin/modules/style/module_meta.php | 68 + Upload/admin/modules/style/templates.php | 1962 +++ Upload/admin/modules/style/themes.php | 2980 ++++ Upload/admin/modules/tools/adminlog.php | 580 + Upload/admin/modules/tools/backupdb.php | 473 + Upload/admin/modules/tools/cache.php | 276 + .../admin/modules/tools/file_verification.php | 128 + Upload/admin/modules/tools/index.html | 8 + Upload/admin/modules/tools/mailerrors.php | 265 + Upload/admin/modules/tools/maillogs.php | 453 + Upload/admin/modules/tools/modlog.php | 340 + Upload/admin/modules/tools/module_meta.php | 122 + Upload/admin/modules/tools/optimizedb.php | 112 + Upload/admin/modules/tools/php_info.php | 42 + .../admin/modules/tools/recount_rebuild.php | 716 + Upload/admin/modules/tools/spamlog.php | 297 + Upload/admin/modules/tools/statistics.php | 273 + Upload/admin/modules/tools/system_health.php | 971 ++ Upload/admin/modules/tools/tasks.php | 770 + Upload/admin/modules/tools/warninglog.php | 480 + .../admin/modules/user/admin_permissions.php | 530 + Upload/admin/modules/user/banning.php | 605 + .../admin/modules/user/group_promotions.php | 725 + Upload/admin/modules/user/groups.php | 1473 ++ Upload/admin/modules/user/index.html | 8 + Upload/admin/modules/user/mass_mail.php | 1704 ++ Upload/admin/modules/user/module_meta.php | 83 + Upload/admin/modules/user/titles.php | 280 + Upload/admin/modules/user/users.php | 4114 +++++ Upload/admin/styles/default/config.css | 77 + Upload/admin/styles/default/forum.css | 76 + Upload/admin/styles/default/home.css | 15 + Upload/admin/styles/default/images/close.png | Bin 0 -> 1910 bytes .../default/images/icons/bullet_off.png | Bin 0 -> 608 bytes .../styles/default/images/icons/bullet_on.png | Bin 0 -> 630 bytes .../styles/default/images/icons/cross.png | Bin 0 -> 461 bytes .../styles/default/images/icons/custom.png | Bin 0 -> 625 bytes .../styles/default/images/icons/decrease.png | Bin 0 -> 357 bytes .../styles/default/images/icons/default.png | Bin 0 -> 364 bytes .../styles/default/images/icons/delete.png | Bin 0 -> 695 bytes .../styles/default/images/icons/error.png | Bin 0 -> 647 bytes .../styles/default/images/icons/find.png | Bin 0 -> 653 bytes .../styles/default/images/icons/group.png | Bin 0 -> 805 bytes .../styles/default/images/icons/increase.png | Bin 0 -> 354 bytes .../styles/default/images/icons/index.html | 8 + .../styles/default/images/icons/logout.png | Bin 0 -> 455 bytes .../default/images/icons/maillogs_contact.png | Bin 0 -> 681 bytes .../default/images/icons/maillogs_thread.png | Bin 0 -> 430 bytes .../default/images/icons/maillogs_user.png | Bin 0 -> 628 bytes .../default/images/icons/make_default.png | Bin 0 -> 455 bytes .../default/images/icons/mobile_user.png | Bin 0 -> 499 bytes .../styles/default/images/icons/no_change.png | Bin 0 -> 258 bytes .../styles/default/images/icons/run_task.png | Bin 0 -> 767 bytes .../styles/default/images/icons/search.png | Bin 0 -> 603 bytes .../styles/default/images/icons/success.png | Bin 0 -> 668 bytes .../styles/default/images/icons/tick.png | Bin 0 -> 616 bytes .../styles/default/images/icons/user.png | Bin 0 -> 628 bytes .../styles/default/images/icons/warning.png | Bin 0 -> 612 bytes .../styles/default/images/icons/world.png | Bin 0 -> 880 bytes Upload/admin/styles/default/images/index.html | 8 + .../styles/default/images/login_logo.png | Bin 0 -> 6299 bytes Upload/admin/styles/default/images/logo.png | Bin 0 -> 10108 bytes .../admin/styles/default/images/spinner.gif | Bin 0 -> 1542 bytes .../styles/default/images/spinner_big.gif | Bin 0 -> 6586 bytes .../admin/styles/default/images/submit_bg.png | Bin 0 -> 337 bytes Upload/admin/styles/default/images/tcat.png | Bin 0 -> 251 bytes Upload/admin/styles/default/images/thead.png | Bin 0 -> 2042 bytes Upload/admin/styles/default/index.html | 8 + Upload/admin/styles/default/login.css | 191 + Upload/admin/styles/default/main.css | 1236 ++ Upload/admin/styles/default/modal.css | 45 + Upload/admin/styles/default/popup.css | 32 + Upload/admin/styles/default/style.css | 42 + Upload/admin/styles/default/style.php | 82 + Upload/admin/styles/default/user.css | 57 + Upload/admin/styles/index.html | 8 + Upload/announcements.php | 126 + Upload/archive/global.php | 222 + Upload/archive/index.php | 515 + Upload/archive/print.css | 144 + Upload/archive/screen.css | 144 + Upload/attachment.php | 187 + Upload/cache/index.html | 8 + Upload/cache/themes/index.html | 8 + Upload/calendar.php | 2490 +++ Upload/captcha.php | 312 + Upload/contact.php | 284 + Upload/css.php | 40 + Upload/editpost.php | 920 + Upload/forumdisplay.php | 1480 ++ Upload/global.php | 1019 ++ Upload/htaccess-nginx.txt | 17 + Upload/htaccess.txt | 61 + Upload/images/arrow_down.png | Bin 0 -> 344 bytes Upload/images/attachtypes/blank.png | Bin 0 -> 482 bytes Upload/images/attachtypes/css.png | Bin 0 -> 533 bytes Upload/images/attachtypes/doc.png | Bin 0 -> 645 bytes Upload/images/attachtypes/html.png | Bin 0 -> 566 bytes Upload/images/attachtypes/image.png | Bin 0 -> 555 bytes Upload/images/attachtypes/pdf.png | Bin 0 -> 661 bytes Upload/images/attachtypes/php.png | Bin 0 -> 666 bytes Upload/images/attachtypes/ppt.png | Bin 0 -> 653 bytes Upload/images/attachtypes/psd.png | Bin 0 -> 480 bytes Upload/images/attachtypes/tar.png | Bin 0 -> 470 bytes Upload/images/attachtypes/txt.png | Bin 0 -> 580 bytes Upload/images/attachtypes/unknown.png | Bin 0 -> 606 bytes Upload/images/attachtypes/xls.png | Bin 0 -> 630 bytes Upload/images/attachtypes/zip.png | Bin 0 -> 493 bytes Upload/images/buddies.png | Bin 0 -> 797 bytes Upload/images/buddy_away.png | Bin 0 -> 391 bytes Upload/images/buddy_delete.png | Bin 0 -> 651 bytes Upload/images/buddy_offline.png | Bin 0 -> 388 bytes Upload/images/buddy_online.png | Bin 0 -> 376 bytes Upload/images/buttons_bg.png | Bin 0 -> 126 bytes Upload/images/buttons_sprite.png | Bin 0 -> 3629 bytes Upload/images/close.png | Bin 0 -> 950 bytes Upload/images/collapse.png | Bin 0 -> 414 bytes Upload/images/collapse_collapsed.png | Bin 0 -> 453 bytes Upload/images/colors/black_header.png | Bin 0 -> 249 bytes Upload/images/colors/black_tcat.png | Bin 0 -> 182 bytes Upload/images/colors/black_thead.png | Bin 0 -> 191 bytes Upload/images/colors/calm_header.png | Bin 0 -> 272 bytes Upload/images/colors/calm_tcat.png | Bin 0 -> 160 bytes Upload/images/colors/calm_thead.png | Bin 0 -> 173 bytes Upload/images/colors/dawn_header.png | Bin 0 -> 250 bytes Upload/images/colors/dawn_tcat.png | Bin 0 -> 160 bytes Upload/images/colors/dawn_thead.png | Bin 0 -> 197 bytes Upload/images/colors/earth_header.png | Bin 0 -> 249 bytes Upload/images/colors/earth_tcat.png | Bin 0 -> 160 bytes Upload/images/colors/earth_thead.png | Bin 0 -> 196 bytes Upload/images/colors/flame_header.png | Bin 0 -> 202 bytes Upload/images/colors/flame_tcat.png | Bin 0 -> 160 bytes Upload/images/colors/flame_thead.png | Bin 0 -> 169 bytes Upload/images/colors/leaf_header.png | Bin 0 -> 278 bytes Upload/images/colors/leaf_tcat.png | Bin 0 -> 160 bytes Upload/images/colors/leaf_thead.png | Bin 0 -> 198 bytes Upload/images/colors/night_header.png | Bin 0 -> 255 bytes Upload/images/colors/night_tcat.png | Bin 0 -> 160 bytes Upload/images/colors/night_thead.png | Bin 0 -> 188 bytes Upload/images/colors/sun_header.png | Bin 0 -> 242 bytes Upload/images/colors/sun_tcat.png | Bin 0 -> 160 bytes Upload/images/colors/sun_thead.png | Bin 0 -> 178 bytes Upload/images/colors/twilight_header.png | Bin 0 -> 266 bytes Upload/images/colors/twilight_tcat.png | Bin 0 -> 160 bytes Upload/images/colors/twilight_thead.png | Bin 0 -> 191 bytes Upload/images/colors/water_header.png | Bin 0 -> 255 bytes Upload/images/colors/water_tcat.png | Bin 0 -> 160 bytes Upload/images/colors/water_thead.png | Bin 0 -> 196 bytes Upload/images/default_avatar.png | Bin 0 -> 2068 bytes Upload/images/dismiss_notice.png | Bin 0 -> 298 bytes Upload/images/error.png | Bin 0 -> 623 bytes Upload/images/folders_sprite.png | Bin 0 -> 4624 bytes Upload/images/forum_icon_sprite.png | Bin 0 -> 1130 bytes Upload/images/fw_pm.png | Bin 0 -> 791 bytes .../english/team-administrator.png | Bin 0 -> 1300 bytes .../groupimages/english/team-designer.png | Bin 0 -> 1524 bytes .../groupimages/english/team-developer.png | Bin 0 -> 999 bytes .../groupimages/english/team-management.png | Bin 0 -> 1342 bytes .../images/groupimages/english/team-mod.png | Bin 0 -> 990 bytes .../groupimages/english/team-supermod.png | Bin 0 -> 1219 bytes .../groupimages/english/team-support.png | Bin 0 -> 1443 bytes .../groupimages/english/team-tester.png | Bin 0 -> 1311 bytes Upload/images/headerlinks_sprite.png | Bin 0 -> 2302 bytes Upload/images/icons/bell.png | Bin 0 -> 759 bytes Upload/images/icons/biggrin.png | Bin 0 -> 706 bytes Upload/images/icons/brick.png | Bin 0 -> 539 bytes Upload/images/icons/bug.png | Bin 0 -> 651 bytes Upload/images/icons/car.png | Bin 0 -> 648 bytes Upload/images/icons/exclamation.png | Bin 0 -> 647 bytes Upload/images/icons/game.png | Bin 0 -> 502 bytes Upload/images/icons/heart.png | Bin 0 -> 714 bytes Upload/images/icons/information.png | Bin 0 -> 701 bytes Upload/images/icons/lightbulb.png | Bin 0 -> 719 bytes Upload/images/icons/lightning.png | Bin 0 -> 638 bytes Upload/images/icons/music.png | Bin 0 -> 709 bytes Upload/images/icons/pencil.png | Bin 0 -> 1506 bytes Upload/images/icons/photo.png | Bin 0 -> 555 bytes Upload/images/icons/question.png | Bin 0 -> 709 bytes Upload/images/icons/rainbow.png | Bin 0 -> 666 bytes Upload/images/icons/sad.png | Bin 0 -> 711 bytes Upload/images/icons/shield.png | Bin 0 -> 704 bytes Upload/images/icons/shocked.png | Bin 0 -> 735 bytes Upload/images/icons/smile.png | Bin 0 -> 724 bytes Upload/images/icons/sport.png | Bin 0 -> 1504 bytes Upload/images/icons/star.png | Bin 0 -> 680 bytes Upload/images/icons/thumbsdown.png | Bin 0 -> 797 bytes Upload/images/icons/thumbsup.png | Bin 0 -> 745 bytes Upload/images/icons/tongue.png | Bin 0 -> 723 bytes Upload/images/icons/user.png | Bin 0 -> 628 bytes Upload/images/icons/video.png | Bin 0 -> 632 bytes Upload/images/icons/wink.png | Bin 0 -> 760 bytes Upload/images/index.html | 8 + Upload/images/invalid.png | Bin 0 -> 404 bytes Upload/images/jump.png | Bin 0 -> 334 bytes Upload/images/logo.png | Bin 0 -> 10286 bytes Upload/images/logo_white.png | Bin 0 -> 8603 bytes Upload/images/mini_status_sprite.png | Bin 0 -> 557 bytes Upload/images/modcp_sprite.png | Bin 0 -> 5209 bytes Upload/images/nav_bit.png | Bin 0 -> 111 bytes Upload/images/new_pm.png | Bin 0 -> 446 bytes Upload/images/old_pm.png | Bin 0 -> 681 bytes Upload/images/paperclip.png | Bin 0 -> 593 bytes Upload/images/pollbar.png | Bin 0 -> 2433 bytes Upload/images/printable.png | Bin 0 -> 701 bytes Upload/images/re_pm.png | Bin 0 -> 781 bytes Upload/images/send.png | Bin 0 -> 446 bytes Upload/images/showthread_sprite.png | Bin 0 -> 1455 bytes Upload/images/smilies/angel.gif | Bin 0 -> 7785 bytes Upload/images/smilies/angry.gif | Bin 0 -> 1245 bytes Upload/images/smilies/arrow.png | Bin 0 -> 659 bytes Upload/images/smilies/at.png | Bin 0 -> 719 bytes Upload/images/smilies/biggrin.gif | Bin 0 -> 1144 bytes Upload/images/smilies/blank.gif | Bin 0 -> 1130 bytes Upload/images/smilies/blush.gif | Bin 0 -> 1200 bytes Upload/images/smilies/confused.gif | Bin 0 -> 1154 bytes Upload/images/smilies/cool.gif | Bin 0 -> 722 bytes Upload/images/smilies/cry.png | Bin 0 -> 610 bytes Upload/images/smilies/cyklop.gif | Bin 0 -> 731 bytes Upload/images/smilies/devil.gif | Bin 0 -> 823 bytes Upload/images/smilies/dodgy.gif | Bin 0 -> 1140 bytes Upload/images/smilies/exclamation.png | Bin 0 -> 619 bytes Upload/images/smilies/facepalm.gif | Bin 0 -> 672 bytes Upload/images/smilies/ff.gif | Bin 0 -> 859 bytes Upload/images/smilies/happy.gif | Bin 0 -> 734 bytes Upload/images/smilies/heart.gif | Bin 0 -> 1166 bytes Upload/images/smilies/huh.gif | Bin 0 -> 1169 bytes Upload/images/smilies/lightbulb.png | Bin 0 -> 617 bytes Upload/images/smilies/my.png | Bin 0 -> 685 bytes Upload/images/smilies/ninja.gif | Bin 0 -> 652 bytes Upload/images/smilies/opera.gif | Bin 0 -> 881 bytes Upload/images/smilies/plask.gif | Bin 0 -> 1473 bytes Upload/images/smilies/rolleyes.gif | Bin 0 -> 1155 bytes Upload/images/smilies/sad.gif | Bin 0 -> 1147 bytes Upload/images/smilies/shamefaced.gif | Bin 0 -> 1179 bytes Upload/images/smilies/shy.gif | Bin 0 -> 1409 bytes Upload/images/smilies/sick.png | Bin 0 -> 611 bytes Upload/images/smilies/sleepy.gif | Bin 0 -> 1144 bytes Upload/images/smilies/smile.gif | Bin 0 -> 1146 bytes Upload/images/smilies/szczerbol.gif | Bin 0 -> 735 bytes Upload/images/smilies/szczerbol2.gif | Bin 0 -> 736 bytes Upload/images/smilies/tongue.gif | Bin 0 -> 1144 bytes Upload/images/smilies/undecided.gif | Bin 0 -> 1155 bytes Upload/images/smilies/wall.gif | Bin 0 -> 5612 bytes Upload/images/smilies/wink.gif | Bin 0 -> 1145 bytes Upload/images/smilies/wow.gif | Bin 0 -> 715 bytes Upload/images/smilies/wub.gif | Bin 0 -> 1025 bytes Upload/images/smilies/xd.gif | Bin 0 -> 727 bytes Upload/images/spinner.gif | Bin 0 -> 1542 bytes Upload/images/spinner_big.gif | Bin 0 -> 6820 bytes Upload/images/star.png | Bin 0 -> 648 bytes Upload/images/star_rating.png | Bin 0 -> 4205 bytes Upload/images/tcat.png | Bin 0 -> 140 bytes Upload/images/thead.png | Bin 0 -> 170 bytes Upload/images/usercp_sprite.png | Bin 0 -> 9876 bytes Upload/images/valid.png | Bin 0 -> 547 bytes Upload/inc/3rdparty/ayah/ayah.php | 482 + Upload/inc/3rdparty/ayah/index.html | 8 + Upload/inc/3rdparty/diff/Diff.php | 261 + .../inc/3rdparty/diff/Diff/Engine/Native.php | 442 + .../inc/3rdparty/diff/Diff/Engine/Shell.php | 165 + .../inc/3rdparty/diff/Diff/Engine/String.php | 254 + .../inc/3rdparty/diff/Diff/Engine/Xdiff.php | 74 + .../inc/3rdparty/diff/Diff/Engine/index.html | 8 + Upload/inc/3rdparty/diff/Diff/Exception.php | 24 + Upload/inc/3rdparty/diff/Diff/Mapped.php | 59 + Upload/inc/3rdparty/diff/Diff/Op/Add.php | 34 + Upload/inc/3rdparty/diff/Diff/Op/Base.php | 38 + Upload/inc/3rdparty/diff/Diff/Op/Change.php | 34 + Upload/inc/3rdparty/diff/Diff/Op/Copy.php | 37 + Upload/inc/3rdparty/diff/Diff/Op/Delete.php | 34 + Upload/inc/3rdparty/diff/Diff/Op/index.html | 8 + Upload/inc/3rdparty/diff/Diff/Renderer.php | 241 + .../3rdparty/diff/Diff/Renderer/Context.php | 75 + .../3rdparty/diff/Diff/Renderer/Inline.php | 200 + .../3rdparty/diff/Diff/Renderer/Unified.php | 64 + .../3rdparty/diff/Diff/Renderer/index.html | 8 + Upload/inc/3rdparty/diff/Diff/String.php | 778 + Upload/inc/3rdparty/diff/Diff/ThreeWay.php | 150 + .../diff/Diff/ThreeWay/BlockBuilder.php | 71 + .../3rdparty/diff/Diff/ThreeWay/Op/Base.php | 48 + .../3rdparty/diff/Diff/ThreeWay/Op/Copy.php | 36 + .../3rdparty/diff/Diff/ThreeWay/Op/index.html | 8 + .../3rdparty/diff/Diff/ThreeWay/index.html | 8 + Upload/inc/3rdparty/diff/Diff/index.html | 8 + Upload/inc/3rdparty/diff/index.html | 8 + Upload/inc/3rdparty/index.html | 8 + Upload/inc/3rdparty/json/index.html | 8 + Upload/inc/3rdparty/json/json.php | 816 + Upload/inc/adminfunctions_templates.php | 108 + Upload/inc/cachehandlers/apc.php | 108 + Upload/inc/cachehandlers/disk.php | 133 + Upload/inc/cachehandlers/eaccelerator.php | 112 + Upload/inc/cachehandlers/index.html | 8 + Upload/inc/cachehandlers/memcache.php | 150 + Upload/inc/cachehandlers/memcached.php | 150 + Upload/inc/cachehandlers/xcache.php | 106 + Upload/inc/captcha_fonts/MINYN___.ttf | Bin 0 -> 84264 bytes Upload/inc/captcha_fonts/edmunds.ttf | Bin 0 -> 48092 bytes Upload/inc/captcha_fonts/index.html | 8 + Upload/inc/captcha_fonts/read_me.html | 253 + Upload/inc/class_captcha.php | 461 + Upload/inc/class_core.php | 622 + Upload/inc/class_custommoderation.php | 498 + Upload/inc/class_datacache.php | 1308 ++ Upload/inc/class_error.php | 607 + Upload/inc/class_feedgeneration.php | 224 + Upload/inc/class_feedparser.php | 240 + Upload/inc/class_graph.php | 337 + Upload/inc/class_language.php | 237 + Upload/inc/class_mailhandler.php | 410 + Upload/inc/class_moderation.php | 3767 +++++ Upload/inc/class_parser.php | 1671 ++ Upload/inc/class_plugins.php | 245 + Upload/inc/class_session.php | 557 + Upload/inc/class_stopforumspamchecker.php | 160 + Upload/inc/class_templates.php | 160 + Upload/inc/class_timers.php | 132 + Upload/inc/class_xml.php | 168 + Upload/inc/config.default.php | 0 Upload/inc/datahandler.php | 215 + Upload/inc/datahandlers/event.php | 635 + Upload/inc/datahandlers/index.html | 8 + Upload/inc/datahandlers/login.php | 302 + Upload/inc/datahandlers/pm.php | 752 + Upload/inc/datahandlers/post.php | 1903 +++ Upload/inc/datahandlers/user.php | 1680 ++ Upload/inc/datahandlers/warnings.php | 754 + Upload/inc/db_mysql.php | 1538 ++ Upload/inc/db_mysqli.php | 1520 ++ Upload/inc/db_pdo.php | 239 + Upload/inc/db_pgsql.php | 1546 ++ Upload/inc/db_sqlite.php | 1460 ++ Upload/inc/functions.php | 7852 +++++++++ Upload/inc/functions_archive.php | 269 + Upload/inc/functions_calendar.php | 1100 ++ Upload/inc/functions_forumlist.php | 588 + Upload/inc/functions_image.php | 257 + Upload/inc/functions_indicators.php | 326 + Upload/inc/functions_massmail.php | 221 + Upload/inc/functions_modcp.php | 284 + Upload/inc/functions_online.php | 1186 ++ Upload/inc/functions_post.php | 928 + Upload/inc/functions_posting.php | 219 + Upload/inc/functions_rebuild.php | 134 + Upload/inc/functions_search.php | 1740 ++ Upload/inc/functions_serverstats.php | 333 + Upload/inc/functions_task.php | 370 + Upload/inc/functions_time.php | 878 + Upload/inc/functions_upload.php | 771 + Upload/inc/functions_user.php | 732 + Upload/inc/functions_warnings.php | 120 + Upload/inc/index.html | 8 + Upload/inc/init.php | 299 + Upload/inc/languages/index.html | 8 + Upload/inc/languages/polish.php | 31 + .../admin/config_attachment_types.lang.php | 44 + .../polish/admin/config_badwords.lang.php | 35 + .../polish/admin/config_banning.lang.php | 45 + .../polish/admin/config_calendars.lang.php | 68 + .../admin/config_help_documents.lang.php | 60 + .../polish/admin/config_languages.lang.php | 65 + .../polish/admin/config_mod_tools.lang.php | 133 + .../polish/admin/config_module_meta.lang.php | 45 + .../polish/admin/config_mycode.lang.php | 58 + .../polish/admin/config_plugins.lang.php | 53 + .../polish/admin/config_post_icons.lang.php | 47 + .../admin/config_profile_fields.lang.php | 77 + .../polish/admin/config_questions.lang.php | 41 + .../polish/admin/config_settings.lang.php | 835 + .../polish/admin/config_smilies.lang.php | 64 + .../polish/admin/config_spiders.lang.php | 42 + .../admin/config_thread_prefixes.lang.php | 42 + .../polish/admin/config_warning.lang.php | 80 + .../polish/admin/forum_announcements.lang.php | 55 + .../polish/admin/forum_attachments.lang.php | 107 + .../polish/admin/forum_management.lang.php | 280 + .../admin/forum_moderation_queue.lang.php | 49 + .../polish/admin/forum_module_meta.lang.php | 19 + .../languages/polish/admin/global.lang.php | 361 + .../polish/admin/home_credits.lang.php | 14 + .../polish/admin/home_dashboard.lang.php | 55 + .../polish/admin/home_module_meta.lang.php | 24 + .../polish/admin/home_preferences.lang.php | 24 + Upload/inc/languages/polish/admin/index.html | 8 + .../polish/admin/style_module_meta.lang.php | 15 + .../polish/admin/style_templates.lang.php | 178 + .../polish/admin/style_themes.lang.php | 221 + .../polish/admin/tools_adminlog.lang.php | 292 + .../polish/admin/tools_backupdb.lang.php | 58 + .../polish/admin/tools_cache.lang.php | 22 + .../admin/tools_file_verification.lang.php | 20 + .../polish/admin/tools_mailerrors.lang.php | 31 + .../polish/admin/tools_maillogs.lang.php | 37 + .../polish/admin/tools_modlog.lang.php | 50 + .../polish/admin/tools_module_meta.lang.php | 45 + .../polish/admin/tools_optimizedb.lang.php | 20 + .../polish/admin/tools_php_info.lang.php | 10 + .../admin/tools_recount_rebuild.lang.php | 51 + .../polish/admin/tools_spamlog.lang.php | 33 + .../polish/admin/tools_statistics.lang.php | 28 + .../polish/admin/tools_system_health.lang.php | 91 + .../polish/admin/tools_tasks.lang.php | 76 + .../polish/admin/tools_warninglog.lang.php | 52 + .../admin/user_admin_permissions.lang.php | 46 + .../polish/admin/user_banning.lang.php | 64 + .../admin/user_group_promotions.lang.php | 91 + .../polish/admin/user_groups.lang.php | 220 + .../polish/admin/user_mass_mail.lang.php | 120 + .../polish/admin/user_module_meta.lang.php | 25 + .../polish/admin/user_titles.lang.php | 37 + .../polish/admin/user_users.lang.php | 409 + .../languages/polish/announcements.lang.php | 16 + Upload/inc/languages/polish/archive.lang.php | 18 + Upload/inc/languages/polish/calendar.lang.php | 144 + Upload/inc/languages/polish/contact.lang.php | 30 + .../languages/polish/customhelpdocs.lang.php | 16 + .../polish/customhelpsections.lang.php | 15 + .../polish/datahandler_event.lang.php | 35 + .../polish/datahandler_login.lang.php | 14 + .../languages/polish/datahandler_pm.lang.php | 22 + .../polish/datahandler_post.lang.php | 29 + .../polish/datahandler_user.lang.php | 43 + .../polish/datahandler_warnings.lang.php | 19 + Upload/inc/languages/polish/editpost.lang.php | 55 + .../languages/polish/forumdisplay.lang.php | 100 + Upload/inc/languages/polish/global.lang.php | 553 + Upload/inc/languages/polish/helpdocs.lang.php | 71 + .../languages/polish/helpsections.lang.php | 15 + Upload/inc/languages/polish/index.html | 8 + Upload/inc/languages/polish/index.lang.php | 42 + .../inc/languages/polish/mailhandler.lang.php | 17 + .../inc/languages/polish/managegroup.lang.php | 65 + Upload/inc/languages/polish/member.lang.php | 258 + .../inc/languages/polish/memberlist.lang.php | 80 + Upload/inc/languages/polish/messages.lang.php | 473 + Upload/inc/languages/polish/misc.lang.php | 96 + Upload/inc/languages/polish/modcp.lang.php | 330 + .../inc/languages/polish/moderation.lang.php | 221 + Upload/inc/languages/polish/newreply.lang.php | 55 + .../inc/languages/polish/newthread.lang.php | 57 + Upload/inc/languages/polish/online.lang.php | 136 + Upload/inc/languages/polish/polls.lang.php | 60 + Upload/inc/languages/polish/portal.lang.php | 53 + .../inc/languages/polish/printthread.lang.php | 12 + Upload/inc/languages/polish/private.lang.php | 202 + .../inc/languages/polish/ratethread.lang.php | 21 + Upload/inc/languages/polish/report.lang.php | 31 + .../inc/languages/polish/reputation.lang.php | 82 + Upload/inc/languages/polish/search.lang.php | 111 + .../inc/languages/polish/sendthread.lang.php | 20 + Upload/inc/languages/polish/showteam.lang.php | 25 + .../inc/languages/polish/showthread.lang.php | 112 + Upload/inc/languages/polish/stats.lang.php | 37 + .../inc/languages/polish/syndication.lang.php | 13 + Upload/inc/languages/polish/usercp.lang.php | 426 + .../inc/languages/polish/usercpnav.lang.php | 34 + Upload/inc/languages/polish/warnings.lang.php | 98 + Upload/inc/languages/polish/xmlhttp.lang.php | 46 + Upload/inc/mailhandlers/index.html | 8 + Upload/inc/mailhandlers/php.php | 73 + Upload/inc/mailhandlers/smtp.php | 552 + Upload/inc/mybb_group.php | 17 + Upload/inc/plugins/hello.php | 109 + Upload/inc/plugins/index.html | 8 + Upload/inc/settings.php | 0 Upload/inc/tasks/backupdb.php | 147 + Upload/inc/tasks/checktables.php | 87 + Upload/inc/tasks/dailycleanup.php | 92 + Upload/inc/tasks/delayedmoderation.php | 258 + Upload/inc/tasks/hourlycleanup.php | 53 + Upload/inc/tasks/index.html | 8 + Upload/inc/tasks/logcleanup.php | 63 + Upload/inc/tasks/massmail.php | 150 + Upload/inc/tasks/promotions.php | 255 + Upload/inc/tasks/recachestylesheets.php | 39 + Upload/inc/tasks/threadviews.php | 35 + Upload/inc/tasks/usercleanup.php | 74 + Upload/inc/tasks/userpruning.php | 84 + Upload/inc/tasks/versioncheck.php | 99 + Upload/index.php | 390 + Upload/install/images/active.png | Bin 0 -> 5495 bytes Upload/install/images/inactive.png | Bin 0 -> 4501 bytes Upload/install/images/index.html | 8 + Upload/install/images/logo.png | Bin 0 -> 10286 bytes Upload/install/images/submit_bg.png | Bin 0 -> 337 bytes Upload/install/images/tcat.png | Bin 0 -> 251 bytes Upload/install/images/thead.png | Bin 0 -> 170 bytes Upload/install/index.php | 2500 +++ Upload/install/resources/adminoptions.xml | 201 + Upload/install/resources/adminviews.xml | 19 + Upload/install/resources/index.html | 8 + Upload/install/resources/language.lang.php | 373 + Upload/install/resources/mybb_theme.xml | 13947 ++++++++++++++++ .../install/resources/mybb_theme_colors.xml | 519 + Upload/install/resources/mysql_db_inserts.php | 177 + Upload/install/resources/mysql_db_tables.php | 1165 ++ Upload/install/resources/output.php | 155 + Upload/install/resources/pgsql_db_tables.php | 1123 ++ Upload/install/resources/settings.xml | 2434 +++ Upload/install/resources/sqlite_db_tables.php | 1040 ++ Upload/install/resources/tasks.xml | 159 + Upload/install/resources/upgrade1.php | 408 + Upload/install/resources/upgrade10.php | 39 + Upload/install/resources/upgrade11.php | 73 + Upload/install/resources/upgrade12.php | 1992 +++ Upload/install/resources/upgrade13.php | 237 + Upload/install/resources/upgrade14.php | 216 + Upload/install/resources/upgrade15.php | 151 + Upload/install/resources/upgrade16.php | 25 + Upload/install/resources/upgrade17.php | 961 ++ Upload/install/resources/upgrade18.php | 58 + Upload/install/resources/upgrade19.php | 24 + Upload/install/resources/upgrade2.php | 290 + Upload/install/resources/upgrade20.php | 51 + Upload/install/resources/upgrade21.php | 104 + Upload/install/resources/upgrade22.php | 25 + Upload/install/resources/upgrade23.php | 58 + Upload/install/resources/upgrade24.php | 23 + Upload/install/resources/upgrade25.php | 23 + Upload/install/resources/upgrade26.php | 48 + Upload/install/resources/upgrade27.php | 24 + Upload/install/resources/upgrade28.php | 23 + Upload/install/resources/upgrade29.php | 24 + Upload/install/resources/upgrade3.php | 826 + Upload/install/resources/upgrade30.php | 2508 +++ Upload/install/resources/upgrade31.php | 60 + Upload/install/resources/upgrade4.php | 81 + Upload/install/resources/upgrade5.php | 620 + Upload/install/resources/upgrade6.php | 41 + Upload/install/resources/upgrade7.php | 26 + Upload/install/resources/upgrade8.php | 50 + Upload/install/resources/upgrade9.php | 25 + Upload/install/resources/usergroups.xml | 613 + Upload/install/stylesheet.css | 387 + Upload/install/upgrade.php | 1094 ++ Upload/jscripts/bbcodes_sceditor.js | 600 + Upload/jscripts/captcha.js | 50 + Upload/jscripts/general.js | 634 + Upload/jscripts/index.html | 8 + Upload/jscripts/inline_edit.js | 94 + Upload/jscripts/inline_moderation.js | 448 + Upload/jscripts/jeditable/jeditable.min.js | 38 + Upload/jscripts/jquery.js | 4 + Upload/jscripts/jquery.plugins.js | 1343 ++ Upload/jscripts/jquery.plugins.min.js | 1 + Upload/jscripts/post.js | 126 + Upload/jscripts/question.js | 51 + Upload/jscripts/rating.js | 135 + Upload/jscripts/report.js | 48 + .../sceditor/editor_plugins/bbcode.js | 2 + .../sceditor/editor_plugins/format.js | 2 + .../sceditor/editor_plugins/index.html | 8 + .../jscripts/sceditor/editor_plugins/xhtml.js | 2 + .../sceditor/editor_themes/buttons.css | 752 + .../sceditor/editor_themes/default.css | 559 + .../editor_themes/emoticons/alien.png | Bin 0 -> 962 bytes .../editor_themes/emoticons/angel.png | Bin 0 -> 1254 bytes .../editor_themes/emoticons/angry.png | Bin 0 -> 1037 bytes .../editor_themes/emoticons/blink.png | Bin 0 -> 1066 bytes .../editor_themes/emoticons/blush.png | Bin 0 -> 1120 bytes .../editor_themes/emoticons/cheerful.png | Bin 0 -> 975 bytes .../sceditor/editor_themes/emoticons/cool.png | Bin 0 -> 1062 bytes .../editor_themes/emoticons/credits.txt | 9 + .../sceditor/editor_themes/emoticons/cwy.png | Bin 0 -> 1011 bytes .../editor_themes/emoticons/devil.png | Bin 0 -> 1133 bytes .../editor_themes/emoticons/dizzy.png | Bin 0 -> 1056 bytes .../sceditor/editor_themes/emoticons/ermm.png | Bin 0 -> 1041 bytes .../sceditor/editor_themes/emoticons/face.png | Bin 0 -> 997 bytes .../editor_themes/emoticons/getlost.png | Bin 0 -> 1026 bytes .../sceditor/editor_themes/emoticons/grin.png | Bin 0 -> 973 bytes .../editor_themes/emoticons/happy.png | Bin 0 -> 1062 bytes .../editor_themes/emoticons/heart.png | Bin 0 -> 852 bytes .../editor_themes/emoticons/kissing.png | Bin 0 -> 1008 bytes .../editor_themes/emoticons/laughing.png | Bin 0 -> 989 bytes .../editor_themes/emoticons/ninja.png | Bin 0 -> 878 bytes .../editor_themes/emoticons/pinch.png | Bin 0 -> 1054 bytes .../editor_themes/emoticons/pouty.png | Bin 0 -> 1028 bytes .../sceditor/editor_themes/emoticons/sad.png | Bin 0 -> 1044 bytes .../editor_themes/emoticons/shocked.png | Bin 0 -> 1032 bytes .../sceditor/editor_themes/emoticons/sick.png | Bin 0 -> 1041 bytes .../editor_themes/emoticons/sideways.png | Bin 0 -> 1030 bytes .../editor_themes/emoticons/silly.png | Bin 0 -> 1025 bytes .../editor_themes/emoticons/sleeping.png | Bin 0 -> 1132 bytes .../editor_themes/emoticons/smile.png | Bin 0 -> 1042 bytes .../editor_themes/emoticons/tongue.png | Bin 0 -> 1046 bytes .../editor_themes/emoticons/unsure.png | Bin 0 -> 1012 bytes .../sceditor/editor_themes/emoticons/w00t.png | Bin 0 -> 873 bytes .../editor_themes/emoticons/wassat.png | Bin 0 -> 1057 bytes .../editor_themes/emoticons/whistling.png | Bin 0 -> 1126 bytes .../sceditor/editor_themes/emoticons/wink.png | Bin 0 -> 1045 bytes .../sceditor/editor_themes/emoticons/wub.png | Bin 0 -> 1159 bytes .../sceditor/editor_themes/famfamfam.png | Bin 0 -> 11720 bytes .../sceditor/editor_themes/index.html | 8 + .../sceditor/editor_themes/modern.css | 650 + .../sceditor/editor_themes/monocons.css | 716 + .../editor_themes/monocons/monocons.eot | Bin 0 -> 8028 bytes .../editor_themes/monocons/monocons.ttf | Bin 0 -> 7860 bytes .../jscripts/sceditor/editor_themes/mybb.css | 585 + .../sceditor/editor_themes/office-toolbar.css | 705 + .../sceditor/editor_themes/office.css | 734 + .../jscripts/sceditor/editor_themes/php.png | Bin 0 -> 538 bytes .../sceditor/editor_themes/square.css | 668 + .../jscripts/sceditor/editor_themes/video.png | Bin 0 -> 632 bytes .../sceditor/jquery.sceditor.bbcode.min.js | 4 + .../sceditor/jquery.sceditor.default.min.css | 1 + .../jscripts/sceditor/jquery.sceditor.min.js | 3 + .../sceditor/jquery.sceditor.xhtml.min.js | 3 + .../jquery.sceditor.buttons.css | 115 + .../jquery.sceditor.default.css | 115 + .../jquery.sceditor.modern.css | 115 + .../jquery.sceditor.monocons.css | 115 + .../textarea_styles/jquery.sceditor.mybb.css | 115 + .../jquery.sceditor.office-toolbar.css | 115 + .../jquery.sceditor.office.css | 115 + .../jquery.sceditor.square.css | 115 + Upload/jscripts/select2/select2-spinner.gif | Bin 0 -> 1849 bytes Upload/jscripts/select2/select2.css | 704 + Upload/jscripts/select2/select2.min.js | 23 + Upload/jscripts/select2/select2.png | Bin 0 -> 613 bytes Upload/jscripts/select2/select2x2.png | Bin 0 -> 845 bytes Upload/jscripts/thread.js | 569 + Upload/jscripts/usercp.js | 258 + .../validate/additional-methods.min.js | 4 + .../jscripts/validate/jquery.validate.min.js | 4 + Upload/managegroup.php | 421 + Upload/member.php | 2999 ++++ Upload/memberlist.php | 440 + Upload/misc.php | 1033 ++ Upload/modcp.php | 4712 ++++++ Upload/moderation.php | 3250 ++++ Upload/newreply.php | 1524 ++ Upload/newthread.php | 1155 ++ Upload/online.php | 284 + Upload/polls.php | 1186 ++ Upload/portal.php | 708 + Upload/printthread.php | 255 + Upload/private.php | 2468 +++ Upload/ratethread.php | 163 + Upload/report.php | 260 + Upload/reputation.php | 997 ++ Upload/rss.php | 19 + Upload/search.php | 1630 ++ Upload/sendthread.php | 292 + Upload/showteam.php | 204 + Upload/showthread.php | 1563 ++ Upload/stats.php | 207 + Upload/syndication.php | 235 + Upload/task.php | 73 + Upload/uploads/avatars/index.html | 8 + Upload/uploads/index.html | 8 + Upload/usercp.php | 4196 +++++ Upload/usercp2.php | 271 + Upload/warnings.php | 848 + Upload/xmlhttp.php | 1026 ++ 845 files changed, 220779 insertions(+) create mode 100644 Upload/admin/backups/index.html create mode 100644 Upload/admin/inc/class_form.php create mode 100644 Upload/admin/inc/class_page.php create mode 100644 Upload/admin/inc/class_table.php create mode 100644 Upload/admin/inc/functions.php create mode 100644 Upload/admin/inc/functions_themes.php create mode 100644 Upload/admin/inc/functions_view_manager.php create mode 100644 Upload/admin/inc/index.html create mode 100644 Upload/admin/index.php create mode 100644 Upload/admin/jscripts/admincp.js create mode 100644 Upload/admin/jscripts/codemirror/LICENSE create mode 100644 Upload/admin/jscripts/codemirror/addon/comment/comment.js create mode 100644 Upload/admin/jscripts/codemirror/addon/comment/continuecomment.js create mode 100644 Upload/admin/jscripts/codemirror/addon/dialog/dialog-mybb.css create mode 100644 Upload/admin/jscripts/codemirror/addon/dialog/dialog.css create mode 100644 Upload/admin/jscripts/codemirror/addon/dialog/dialog.js create mode 100644 Upload/admin/jscripts/codemirror/addon/dialog/index.html create mode 100644 Upload/admin/jscripts/codemirror/addon/display/fullscreen.css create mode 100644 Upload/admin/jscripts/codemirror/addon/display/fullscreen.js create mode 100644 Upload/admin/jscripts/codemirror/addon/display/placeholder.js create mode 100644 Upload/admin/jscripts/codemirror/addon/display/rulers.js create mode 100644 Upload/admin/jscripts/codemirror/addon/edit/closebrackets.js create mode 100644 Upload/admin/jscripts/codemirror/addon/edit/closetag.js create mode 100644 Upload/admin/jscripts/codemirror/addon/edit/continuelist.js create mode 100644 Upload/admin/jscripts/codemirror/addon/edit/matchbrackets.js create mode 100644 Upload/admin/jscripts/codemirror/addon/edit/matchtags.js create mode 100644 Upload/admin/jscripts/codemirror/addon/edit/trailingspace.js create mode 100644 Upload/admin/jscripts/codemirror/addon/fold/brace-fold.js create mode 100644 Upload/admin/jscripts/codemirror/addon/fold/comment-fold.js create mode 100644 Upload/admin/jscripts/codemirror/addon/fold/foldcode.js create mode 100644 Upload/admin/jscripts/codemirror/addon/fold/foldgutter.css create mode 100644 Upload/admin/jscripts/codemirror/addon/fold/foldgutter.js create mode 100644 Upload/admin/jscripts/codemirror/addon/fold/indent-fold.js create mode 100644 Upload/admin/jscripts/codemirror/addon/fold/markdown-fold.js create mode 100644 Upload/admin/jscripts/codemirror/addon/fold/xml-fold.js create mode 100644 Upload/admin/jscripts/codemirror/addon/hint/anyword-hint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/hint/css-hint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/hint/html-hint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/hint/javascript-hint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/hint/python-hint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/hint/show-hint.css create mode 100644 Upload/admin/jscripts/codemirror/addon/hint/show-hint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/hint/sql-hint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/hint/xml-hint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/index.html create mode 100644 Upload/admin/jscripts/codemirror/addon/lint/coffeescript-lint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/lint/css-lint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/lint/javascript-lint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/lint/json-lint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/lint/lint.css create mode 100644 Upload/admin/jscripts/codemirror/addon/lint/lint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/lint/yaml-lint.js create mode 100644 Upload/admin/jscripts/codemirror/addon/merge/merge.css create mode 100644 Upload/admin/jscripts/codemirror/addon/merge/merge.js create mode 100644 Upload/admin/jscripts/codemirror/addon/mode/loadmode.js create mode 100644 Upload/admin/jscripts/codemirror/addon/mode/multiplex.js create mode 100644 Upload/admin/jscripts/codemirror/addon/mode/multiplex_test.js create mode 100644 Upload/admin/jscripts/codemirror/addon/mode/overlay.js create mode 100644 Upload/admin/jscripts/codemirror/addon/runmode/colorize.js create mode 100644 Upload/admin/jscripts/codemirror/addon/runmode/runmode-standalone.js create mode 100644 Upload/admin/jscripts/codemirror/addon/runmode/runmode.js create mode 100644 Upload/admin/jscripts/codemirror/addon/runmode/runmode.node.js create mode 100644 Upload/admin/jscripts/codemirror/addon/scroll/scrollpastend.js create mode 100644 Upload/admin/jscripts/codemirror/addon/search/index.html create mode 100644 Upload/admin/jscripts/codemirror/addon/search/match-highlighter.js create mode 100644 Upload/admin/jscripts/codemirror/addon/search/search.js create mode 100644 Upload/admin/jscripts/codemirror/addon/search/searchcursor.js create mode 100644 Upload/admin/jscripts/codemirror/addon/selection/active-line.js create mode 100644 Upload/admin/jscripts/codemirror/addon/selection/mark-selection.js create mode 100644 Upload/admin/jscripts/codemirror/addon/tern/tern.css create mode 100644 Upload/admin/jscripts/codemirror/addon/tern/tern.js create mode 100644 Upload/admin/jscripts/codemirror/addon/tern/worker.js create mode 100644 Upload/admin/jscripts/codemirror/addon/wrap/hardwrap.js create mode 100644 Upload/admin/jscripts/codemirror/index.html create mode 100644 Upload/admin/jscripts/codemirror/keymap/emacs.js create mode 100644 Upload/admin/jscripts/codemirror/keymap/sublime.js create mode 100644 Upload/admin/jscripts/codemirror/keymap/vim.js create mode 100644 Upload/admin/jscripts/codemirror/lib/codemirror.css create mode 100644 Upload/admin/jscripts/codemirror/lib/codemirror.js create mode 100644 Upload/admin/jscripts/codemirror/lib/index.html create mode 100644 Upload/admin/jscripts/codemirror/mode/css/css.js create mode 100644 Upload/admin/jscripts/codemirror/mode/css/index.html create mode 100644 Upload/admin/jscripts/codemirror/mode/css/less.html create mode 100644 Upload/admin/jscripts/codemirror/mode/css/less_test.js create mode 100644 Upload/admin/jscripts/codemirror/mode/css/scss.html create mode 100644 Upload/admin/jscripts/codemirror/mode/css/scss_test.js create mode 100644 Upload/admin/jscripts/codemirror/mode/css/test.js create mode 100644 Upload/admin/jscripts/codemirror/mode/htmlmixed/htmlmixed.js create mode 100644 Upload/admin/jscripts/codemirror/mode/htmlmixed/index.html create mode 100644 Upload/admin/jscripts/codemirror/mode/javascript/index.html create mode 100644 Upload/admin/jscripts/codemirror/mode/javascript/javascript.js create mode 100644 Upload/admin/jscripts/codemirror/mode/javascript/json-ld.html create mode 100644 Upload/admin/jscripts/codemirror/mode/javascript/test.js create mode 100644 Upload/admin/jscripts/codemirror/mode/javascript/typescript.html create mode 100644 Upload/admin/jscripts/codemirror/mode/xml/index.html create mode 100644 Upload/admin/jscripts/codemirror/mode/xml/test.js create mode 100644 Upload/admin/jscripts/codemirror/mode/xml/xml.js create mode 100644 Upload/admin/jscripts/codemirror/theme/3024-day.css create mode 100644 Upload/admin/jscripts/codemirror/theme/3024-night.css create mode 100644 Upload/admin/jscripts/codemirror/theme/ambiance-mobile.css create mode 100644 Upload/admin/jscripts/codemirror/theme/ambiance.css create mode 100644 Upload/admin/jscripts/codemirror/theme/base16-dark.css create mode 100644 Upload/admin/jscripts/codemirror/theme/base16-light.css create mode 100644 Upload/admin/jscripts/codemirror/theme/blackboard.css create mode 100644 Upload/admin/jscripts/codemirror/theme/cobalt.css create mode 100644 Upload/admin/jscripts/codemirror/theme/eclipse.css create mode 100644 Upload/admin/jscripts/codemirror/theme/elegant.css create mode 100644 Upload/admin/jscripts/codemirror/theme/erlang-dark.css create mode 100644 Upload/admin/jscripts/codemirror/theme/index.html create mode 100644 Upload/admin/jscripts/codemirror/theme/lesser-dark.css create mode 100644 Upload/admin/jscripts/codemirror/theme/mbo.css create mode 100644 Upload/admin/jscripts/codemirror/theme/mdn-like.css create mode 100644 Upload/admin/jscripts/codemirror/theme/midnight.css create mode 100644 Upload/admin/jscripts/codemirror/theme/monokai.css create mode 100644 Upload/admin/jscripts/codemirror/theme/mybb.css create mode 100644 Upload/admin/jscripts/codemirror/theme/neat.css create mode 100644 Upload/admin/jscripts/codemirror/theme/neo.css create mode 100644 Upload/admin/jscripts/codemirror/theme/night.css create mode 100644 Upload/admin/jscripts/codemirror/theme/paraiso-dark.css create mode 100644 Upload/admin/jscripts/codemirror/theme/paraiso-light.css create mode 100644 Upload/admin/jscripts/codemirror/theme/pastel-on-dark.css create mode 100644 Upload/admin/jscripts/codemirror/theme/rubyblue.css create mode 100644 Upload/admin/jscripts/codemirror/theme/solarized.css create mode 100644 Upload/admin/jscripts/codemirror/theme/the-matrix.css create mode 100644 Upload/admin/jscripts/codemirror/theme/tomorrow-night-eighties.css create mode 100644 Upload/admin/jscripts/codemirror/theme/twilight.css create mode 100644 Upload/admin/jscripts/codemirror/theme/vibrant-ink.css create mode 100644 Upload/admin/jscripts/codemirror/theme/xq-dark.css create mode 100644 Upload/admin/jscripts/codemirror/theme/xq-light.css create mode 100644 Upload/admin/jscripts/index.html create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/animated-overlay.gif create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_flat_55_fbec88_40x100.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_glass_85_dfeffc_1x400.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_glass_95_fef1ec_1x400.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_217bc0_256x240.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_2e83ff_256x240.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_469bdd_256x240.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_6da8d5_256x240.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_cd0a0a_256x240.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_d8e7f3_256x240.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_f9bd01_256x240.png create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/jquery-ui.min.css create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/jquery-ui.structure.min.css create mode 100644 Upload/admin/jscripts/jqueryui/css/redmond/jquery-ui.theme.min.css create mode 100644 Upload/admin/jscripts/jqueryui/js/jquery-ui.min.js create mode 100644 Upload/admin/jscripts/mycode_sandbox.js create mode 100644 Upload/admin/jscripts/peeker.js create mode 100644 Upload/admin/jscripts/quick_perm_editor.js create mode 100644 Upload/admin/jscripts/search.js create mode 100644 Upload/admin/jscripts/tabs.js create mode 100644 Upload/admin/jscripts/theme_properties.js create mode 100644 Upload/admin/jscripts/themes.js create mode 100644 Upload/admin/jscripts/users.js create mode 100644 Upload/admin/jscripts/view_manager.js create mode 100644 Upload/admin/modules/config/attachment_types.php create mode 100644 Upload/admin/modules/config/badwords.php create mode 100644 Upload/admin/modules/config/banning.php create mode 100644 Upload/admin/modules/config/calendars.php create mode 100644 Upload/admin/modules/config/help_documents.php create mode 100644 Upload/admin/modules/config/index.html create mode 100644 Upload/admin/modules/config/languages.php create mode 100644 Upload/admin/modules/config/mod_tools.php create mode 100644 Upload/admin/modules/config/module_meta.php create mode 100644 Upload/admin/modules/config/mycode.php create mode 100644 Upload/admin/modules/config/plugins.php create mode 100644 Upload/admin/modules/config/post_icons.php create mode 100644 Upload/admin/modules/config/profile_fields.php create mode 100644 Upload/admin/modules/config/questions.php create mode 100644 Upload/admin/modules/config/settings.php create mode 100644 Upload/admin/modules/config/smilies.php create mode 100644 Upload/admin/modules/config/spiders.php create mode 100644 Upload/admin/modules/config/thread_prefixes.php create mode 100644 Upload/admin/modules/config/warning.php create mode 100644 Upload/admin/modules/forum/announcements.php create mode 100644 Upload/admin/modules/forum/attachments.php create mode 100644 Upload/admin/modules/forum/index.html create mode 100644 Upload/admin/modules/forum/management.php create mode 100644 Upload/admin/modules/forum/moderation_queue.php create mode 100644 Upload/admin/modules/forum/module_meta.php create mode 100644 Upload/admin/modules/home/credits.php create mode 100644 Upload/admin/modules/home/index.html create mode 100644 Upload/admin/modules/home/index.php create mode 100644 Upload/admin/modules/home/module_meta.php create mode 100644 Upload/admin/modules/home/preferences.php create mode 100644 Upload/admin/modules/index.html create mode 100644 Upload/admin/modules/style/index.html create mode 100644 Upload/admin/modules/style/module_meta.php create mode 100644 Upload/admin/modules/style/templates.php create mode 100644 Upload/admin/modules/style/themes.php create mode 100644 Upload/admin/modules/tools/adminlog.php create mode 100644 Upload/admin/modules/tools/backupdb.php create mode 100644 Upload/admin/modules/tools/cache.php create mode 100644 Upload/admin/modules/tools/file_verification.php create mode 100644 Upload/admin/modules/tools/index.html create mode 100644 Upload/admin/modules/tools/mailerrors.php create mode 100644 Upload/admin/modules/tools/maillogs.php create mode 100644 Upload/admin/modules/tools/modlog.php create mode 100644 Upload/admin/modules/tools/module_meta.php create mode 100644 Upload/admin/modules/tools/optimizedb.php create mode 100644 Upload/admin/modules/tools/php_info.php create mode 100644 Upload/admin/modules/tools/recount_rebuild.php create mode 100644 Upload/admin/modules/tools/spamlog.php create mode 100644 Upload/admin/modules/tools/statistics.php create mode 100644 Upload/admin/modules/tools/system_health.php create mode 100644 Upload/admin/modules/tools/tasks.php create mode 100644 Upload/admin/modules/tools/warninglog.php create mode 100644 Upload/admin/modules/user/admin_permissions.php create mode 100644 Upload/admin/modules/user/banning.php create mode 100644 Upload/admin/modules/user/group_promotions.php create mode 100644 Upload/admin/modules/user/groups.php create mode 100644 Upload/admin/modules/user/index.html create mode 100644 Upload/admin/modules/user/mass_mail.php create mode 100644 Upload/admin/modules/user/module_meta.php create mode 100644 Upload/admin/modules/user/titles.php create mode 100644 Upload/admin/modules/user/users.php create mode 100644 Upload/admin/styles/default/config.css create mode 100644 Upload/admin/styles/default/forum.css create mode 100644 Upload/admin/styles/default/home.css create mode 100644 Upload/admin/styles/default/images/close.png create mode 100644 Upload/admin/styles/default/images/icons/bullet_off.png create mode 100644 Upload/admin/styles/default/images/icons/bullet_on.png create mode 100644 Upload/admin/styles/default/images/icons/cross.png create mode 100644 Upload/admin/styles/default/images/icons/custom.png create mode 100644 Upload/admin/styles/default/images/icons/decrease.png create mode 100644 Upload/admin/styles/default/images/icons/default.png create mode 100644 Upload/admin/styles/default/images/icons/delete.png create mode 100644 Upload/admin/styles/default/images/icons/error.png create mode 100644 Upload/admin/styles/default/images/icons/find.png create mode 100644 Upload/admin/styles/default/images/icons/group.png create mode 100644 Upload/admin/styles/default/images/icons/increase.png create mode 100644 Upload/admin/styles/default/images/icons/index.html create mode 100644 Upload/admin/styles/default/images/icons/logout.png create mode 100644 Upload/admin/styles/default/images/icons/maillogs_contact.png create mode 100644 Upload/admin/styles/default/images/icons/maillogs_thread.png create mode 100644 Upload/admin/styles/default/images/icons/maillogs_user.png create mode 100644 Upload/admin/styles/default/images/icons/make_default.png create mode 100644 Upload/admin/styles/default/images/icons/mobile_user.png create mode 100644 Upload/admin/styles/default/images/icons/no_change.png create mode 100644 Upload/admin/styles/default/images/icons/run_task.png create mode 100644 Upload/admin/styles/default/images/icons/search.png create mode 100644 Upload/admin/styles/default/images/icons/success.png create mode 100644 Upload/admin/styles/default/images/icons/tick.png create mode 100644 Upload/admin/styles/default/images/icons/user.png create mode 100644 Upload/admin/styles/default/images/icons/warning.png create mode 100644 Upload/admin/styles/default/images/icons/world.png create mode 100644 Upload/admin/styles/default/images/index.html create mode 100644 Upload/admin/styles/default/images/login_logo.png create mode 100644 Upload/admin/styles/default/images/logo.png create mode 100644 Upload/admin/styles/default/images/spinner.gif create mode 100644 Upload/admin/styles/default/images/spinner_big.gif create mode 100644 Upload/admin/styles/default/images/submit_bg.png create mode 100644 Upload/admin/styles/default/images/tcat.png create mode 100644 Upload/admin/styles/default/images/thead.png create mode 100644 Upload/admin/styles/default/index.html create mode 100644 Upload/admin/styles/default/login.css create mode 100644 Upload/admin/styles/default/main.css create mode 100644 Upload/admin/styles/default/modal.css create mode 100644 Upload/admin/styles/default/popup.css create mode 100644 Upload/admin/styles/default/style.css create mode 100644 Upload/admin/styles/default/style.php create mode 100644 Upload/admin/styles/default/user.css create mode 100644 Upload/admin/styles/index.html create mode 100644 Upload/announcements.php create mode 100644 Upload/archive/global.php create mode 100644 Upload/archive/index.php create mode 100644 Upload/archive/print.css create mode 100644 Upload/archive/screen.css create mode 100644 Upload/attachment.php create mode 100644 Upload/cache/index.html create mode 100644 Upload/cache/themes/index.html create mode 100644 Upload/calendar.php create mode 100644 Upload/captcha.php create mode 100644 Upload/contact.php create mode 100644 Upload/css.php create mode 100644 Upload/editpost.php create mode 100644 Upload/forumdisplay.php create mode 100644 Upload/global.php create mode 100644 Upload/htaccess-nginx.txt create mode 100644 Upload/htaccess.txt create mode 100644 Upload/images/arrow_down.png create mode 100644 Upload/images/attachtypes/blank.png create mode 100644 Upload/images/attachtypes/css.png create mode 100644 Upload/images/attachtypes/doc.png create mode 100644 Upload/images/attachtypes/html.png create mode 100644 Upload/images/attachtypes/image.png create mode 100644 Upload/images/attachtypes/pdf.png create mode 100644 Upload/images/attachtypes/php.png create mode 100644 Upload/images/attachtypes/ppt.png create mode 100644 Upload/images/attachtypes/psd.png create mode 100644 Upload/images/attachtypes/tar.png create mode 100644 Upload/images/attachtypes/txt.png create mode 100644 Upload/images/attachtypes/unknown.png create mode 100644 Upload/images/attachtypes/xls.png create mode 100644 Upload/images/attachtypes/zip.png create mode 100644 Upload/images/buddies.png create mode 100644 Upload/images/buddy_away.png create mode 100644 Upload/images/buddy_delete.png create mode 100644 Upload/images/buddy_offline.png create mode 100644 Upload/images/buddy_online.png create mode 100644 Upload/images/buttons_bg.png create mode 100644 Upload/images/buttons_sprite.png create mode 100644 Upload/images/close.png create mode 100644 Upload/images/collapse.png create mode 100644 Upload/images/collapse_collapsed.png create mode 100644 Upload/images/colors/black_header.png create mode 100644 Upload/images/colors/black_tcat.png create mode 100644 Upload/images/colors/black_thead.png create mode 100644 Upload/images/colors/calm_header.png create mode 100644 Upload/images/colors/calm_tcat.png create mode 100644 Upload/images/colors/calm_thead.png create mode 100644 Upload/images/colors/dawn_header.png create mode 100644 Upload/images/colors/dawn_tcat.png create mode 100644 Upload/images/colors/dawn_thead.png create mode 100644 Upload/images/colors/earth_header.png create mode 100644 Upload/images/colors/earth_tcat.png create mode 100644 Upload/images/colors/earth_thead.png create mode 100644 Upload/images/colors/flame_header.png create mode 100644 Upload/images/colors/flame_tcat.png create mode 100644 Upload/images/colors/flame_thead.png create mode 100644 Upload/images/colors/leaf_header.png create mode 100644 Upload/images/colors/leaf_tcat.png create mode 100644 Upload/images/colors/leaf_thead.png create mode 100644 Upload/images/colors/night_header.png create mode 100644 Upload/images/colors/night_tcat.png create mode 100644 Upload/images/colors/night_thead.png create mode 100644 Upload/images/colors/sun_header.png create mode 100644 Upload/images/colors/sun_tcat.png create mode 100644 Upload/images/colors/sun_thead.png create mode 100644 Upload/images/colors/twilight_header.png create mode 100644 Upload/images/colors/twilight_tcat.png create mode 100644 Upload/images/colors/twilight_thead.png create mode 100644 Upload/images/colors/water_header.png create mode 100644 Upload/images/colors/water_tcat.png create mode 100644 Upload/images/colors/water_thead.png create mode 100644 Upload/images/default_avatar.png create mode 100644 Upload/images/dismiss_notice.png create mode 100644 Upload/images/error.png create mode 100644 Upload/images/folders_sprite.png create mode 100644 Upload/images/forum_icon_sprite.png create mode 100644 Upload/images/fw_pm.png create mode 100644 Upload/images/groupimages/english/team-administrator.png create mode 100644 Upload/images/groupimages/english/team-designer.png create mode 100644 Upload/images/groupimages/english/team-developer.png create mode 100644 Upload/images/groupimages/english/team-management.png create mode 100644 Upload/images/groupimages/english/team-mod.png create mode 100644 Upload/images/groupimages/english/team-supermod.png create mode 100644 Upload/images/groupimages/english/team-support.png create mode 100644 Upload/images/groupimages/english/team-tester.png create mode 100644 Upload/images/headerlinks_sprite.png create mode 100644 Upload/images/icons/bell.png create mode 100644 Upload/images/icons/biggrin.png create mode 100644 Upload/images/icons/brick.png create mode 100644 Upload/images/icons/bug.png create mode 100644 Upload/images/icons/car.png create mode 100644 Upload/images/icons/exclamation.png create mode 100644 Upload/images/icons/game.png create mode 100644 Upload/images/icons/heart.png create mode 100644 Upload/images/icons/information.png create mode 100644 Upload/images/icons/lightbulb.png create mode 100644 Upload/images/icons/lightning.png create mode 100644 Upload/images/icons/music.png create mode 100644 Upload/images/icons/pencil.png create mode 100644 Upload/images/icons/photo.png create mode 100644 Upload/images/icons/question.png create mode 100644 Upload/images/icons/rainbow.png create mode 100644 Upload/images/icons/sad.png create mode 100644 Upload/images/icons/shield.png create mode 100644 Upload/images/icons/shocked.png create mode 100644 Upload/images/icons/smile.png create mode 100644 Upload/images/icons/sport.png create mode 100644 Upload/images/icons/star.png create mode 100644 Upload/images/icons/thumbsdown.png create mode 100644 Upload/images/icons/thumbsup.png create mode 100644 Upload/images/icons/tongue.png create mode 100644 Upload/images/icons/user.png create mode 100644 Upload/images/icons/video.png create mode 100644 Upload/images/icons/wink.png create mode 100644 Upload/images/index.html create mode 100644 Upload/images/invalid.png create mode 100644 Upload/images/jump.png create mode 100644 Upload/images/logo.png create mode 100644 Upload/images/logo_white.png create mode 100644 Upload/images/mini_status_sprite.png create mode 100644 Upload/images/modcp_sprite.png create mode 100644 Upload/images/nav_bit.png create mode 100644 Upload/images/new_pm.png create mode 100644 Upload/images/old_pm.png create mode 100644 Upload/images/paperclip.png create mode 100644 Upload/images/pollbar.png create mode 100644 Upload/images/printable.png create mode 100644 Upload/images/re_pm.png create mode 100644 Upload/images/send.png create mode 100644 Upload/images/showthread_sprite.png create mode 100644 Upload/images/smilies/angel.gif create mode 100644 Upload/images/smilies/angry.gif create mode 100644 Upload/images/smilies/arrow.png create mode 100644 Upload/images/smilies/at.png create mode 100644 Upload/images/smilies/biggrin.gif create mode 100644 Upload/images/smilies/blank.gif create mode 100644 Upload/images/smilies/blush.gif create mode 100644 Upload/images/smilies/confused.gif create mode 100644 Upload/images/smilies/cool.gif create mode 100644 Upload/images/smilies/cry.png create mode 100644 Upload/images/smilies/cyklop.gif create mode 100644 Upload/images/smilies/devil.gif create mode 100644 Upload/images/smilies/dodgy.gif create mode 100644 Upload/images/smilies/exclamation.png create mode 100644 Upload/images/smilies/facepalm.gif create mode 100644 Upload/images/smilies/ff.gif create mode 100644 Upload/images/smilies/happy.gif create mode 100644 Upload/images/smilies/heart.gif create mode 100644 Upload/images/smilies/huh.gif create mode 100644 Upload/images/smilies/lightbulb.png create mode 100644 Upload/images/smilies/my.png create mode 100644 Upload/images/smilies/ninja.gif create mode 100644 Upload/images/smilies/opera.gif create mode 100644 Upload/images/smilies/plask.gif create mode 100644 Upload/images/smilies/rolleyes.gif create mode 100644 Upload/images/smilies/sad.gif create mode 100644 Upload/images/smilies/shamefaced.gif create mode 100644 Upload/images/smilies/shy.gif create mode 100644 Upload/images/smilies/sick.png create mode 100644 Upload/images/smilies/sleepy.gif create mode 100644 Upload/images/smilies/smile.gif create mode 100644 Upload/images/smilies/szczerbol.gif create mode 100644 Upload/images/smilies/szczerbol2.gif create mode 100644 Upload/images/smilies/tongue.gif create mode 100644 Upload/images/smilies/undecided.gif create mode 100644 Upload/images/smilies/wall.gif create mode 100644 Upload/images/smilies/wink.gif create mode 100644 Upload/images/smilies/wow.gif create mode 100644 Upload/images/smilies/wub.gif create mode 100644 Upload/images/smilies/xd.gif create mode 100644 Upload/images/spinner.gif create mode 100644 Upload/images/spinner_big.gif create mode 100644 Upload/images/star.png create mode 100644 Upload/images/star_rating.png create mode 100644 Upload/images/tcat.png create mode 100644 Upload/images/thead.png create mode 100644 Upload/images/usercp_sprite.png create mode 100644 Upload/images/valid.png create mode 100644 Upload/inc/3rdparty/ayah/ayah.php create mode 100644 Upload/inc/3rdparty/ayah/index.html create mode 100644 Upload/inc/3rdparty/diff/Diff.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Engine/Native.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Engine/Shell.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Engine/String.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Engine/Xdiff.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Engine/index.html create mode 100644 Upload/inc/3rdparty/diff/Diff/Exception.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Mapped.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Op/Add.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Op/Base.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Op/Change.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Op/Copy.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Op/Delete.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Op/index.html create mode 100644 Upload/inc/3rdparty/diff/Diff/Renderer.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Renderer/Context.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Renderer/Inline.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Renderer/Unified.php create mode 100644 Upload/inc/3rdparty/diff/Diff/Renderer/index.html create mode 100644 Upload/inc/3rdparty/diff/Diff/String.php create mode 100644 Upload/inc/3rdparty/diff/Diff/ThreeWay.php create mode 100644 Upload/inc/3rdparty/diff/Diff/ThreeWay/BlockBuilder.php create mode 100644 Upload/inc/3rdparty/diff/Diff/ThreeWay/Op/Base.php create mode 100644 Upload/inc/3rdparty/diff/Diff/ThreeWay/Op/Copy.php create mode 100644 Upload/inc/3rdparty/diff/Diff/ThreeWay/Op/index.html create mode 100644 Upload/inc/3rdparty/diff/Diff/ThreeWay/index.html create mode 100644 Upload/inc/3rdparty/diff/Diff/index.html create mode 100644 Upload/inc/3rdparty/diff/index.html create mode 100644 Upload/inc/3rdparty/index.html create mode 100644 Upload/inc/3rdparty/json/index.html create mode 100644 Upload/inc/3rdparty/json/json.php create mode 100644 Upload/inc/adminfunctions_templates.php create mode 100644 Upload/inc/cachehandlers/apc.php create mode 100644 Upload/inc/cachehandlers/disk.php create mode 100644 Upload/inc/cachehandlers/eaccelerator.php create mode 100644 Upload/inc/cachehandlers/index.html create mode 100644 Upload/inc/cachehandlers/memcache.php create mode 100644 Upload/inc/cachehandlers/memcached.php create mode 100644 Upload/inc/cachehandlers/xcache.php create mode 100644 Upload/inc/captcha_fonts/MINYN___.ttf create mode 100644 Upload/inc/captcha_fonts/edmunds.ttf create mode 100644 Upload/inc/captcha_fonts/index.html create mode 100644 Upload/inc/captcha_fonts/read_me.html create mode 100644 Upload/inc/class_captcha.php create mode 100644 Upload/inc/class_core.php create mode 100644 Upload/inc/class_custommoderation.php create mode 100644 Upload/inc/class_datacache.php create mode 100644 Upload/inc/class_error.php create mode 100644 Upload/inc/class_feedgeneration.php create mode 100644 Upload/inc/class_feedparser.php create mode 100644 Upload/inc/class_graph.php create mode 100644 Upload/inc/class_language.php create mode 100644 Upload/inc/class_mailhandler.php create mode 100644 Upload/inc/class_moderation.php create mode 100644 Upload/inc/class_parser.php create mode 100644 Upload/inc/class_plugins.php create mode 100644 Upload/inc/class_session.php create mode 100644 Upload/inc/class_stopforumspamchecker.php create mode 100644 Upload/inc/class_templates.php create mode 100644 Upload/inc/class_timers.php create mode 100644 Upload/inc/class_xml.php create mode 100644 Upload/inc/config.default.php create mode 100644 Upload/inc/datahandler.php create mode 100644 Upload/inc/datahandlers/event.php create mode 100644 Upload/inc/datahandlers/index.html create mode 100644 Upload/inc/datahandlers/login.php create mode 100644 Upload/inc/datahandlers/pm.php create mode 100644 Upload/inc/datahandlers/post.php create mode 100644 Upload/inc/datahandlers/user.php create mode 100644 Upload/inc/datahandlers/warnings.php create mode 100644 Upload/inc/db_mysql.php create mode 100644 Upload/inc/db_mysqli.php create mode 100644 Upload/inc/db_pdo.php create mode 100644 Upload/inc/db_pgsql.php create mode 100644 Upload/inc/db_sqlite.php create mode 100644 Upload/inc/functions.php create mode 100644 Upload/inc/functions_archive.php create mode 100644 Upload/inc/functions_calendar.php create mode 100644 Upload/inc/functions_forumlist.php create mode 100644 Upload/inc/functions_image.php create mode 100644 Upload/inc/functions_indicators.php create mode 100644 Upload/inc/functions_massmail.php create mode 100644 Upload/inc/functions_modcp.php create mode 100644 Upload/inc/functions_online.php create mode 100644 Upload/inc/functions_post.php create mode 100644 Upload/inc/functions_posting.php create mode 100644 Upload/inc/functions_rebuild.php create mode 100644 Upload/inc/functions_search.php create mode 100644 Upload/inc/functions_serverstats.php create mode 100644 Upload/inc/functions_task.php create mode 100644 Upload/inc/functions_time.php create mode 100644 Upload/inc/functions_upload.php create mode 100644 Upload/inc/functions_user.php create mode 100644 Upload/inc/functions_warnings.php create mode 100644 Upload/inc/index.html create mode 100644 Upload/inc/init.php create mode 100644 Upload/inc/languages/index.html create mode 100644 Upload/inc/languages/polish.php create mode 100644 Upload/inc/languages/polish/admin/config_attachment_types.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_badwords.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_banning.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_calendars.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_help_documents.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_languages.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_mod_tools.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_module_meta.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_mycode.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_plugins.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_post_icons.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_profile_fields.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_questions.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_settings.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_smilies.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_spiders.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_thread_prefixes.lang.php create mode 100644 Upload/inc/languages/polish/admin/config_warning.lang.php create mode 100644 Upload/inc/languages/polish/admin/forum_announcements.lang.php create mode 100644 Upload/inc/languages/polish/admin/forum_attachments.lang.php create mode 100644 Upload/inc/languages/polish/admin/forum_management.lang.php create mode 100644 Upload/inc/languages/polish/admin/forum_moderation_queue.lang.php create mode 100644 Upload/inc/languages/polish/admin/forum_module_meta.lang.php create mode 100644 Upload/inc/languages/polish/admin/global.lang.php create mode 100644 Upload/inc/languages/polish/admin/home_credits.lang.php create mode 100644 Upload/inc/languages/polish/admin/home_dashboard.lang.php create mode 100644 Upload/inc/languages/polish/admin/home_module_meta.lang.php create mode 100644 Upload/inc/languages/polish/admin/home_preferences.lang.php create mode 100644 Upload/inc/languages/polish/admin/index.html create mode 100644 Upload/inc/languages/polish/admin/style_module_meta.lang.php create mode 100644 Upload/inc/languages/polish/admin/style_templates.lang.php create mode 100644 Upload/inc/languages/polish/admin/style_themes.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_adminlog.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_backupdb.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_cache.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_file_verification.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_mailerrors.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_maillogs.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_modlog.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_module_meta.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_optimizedb.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_php_info.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_recount_rebuild.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_spamlog.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_statistics.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_system_health.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_tasks.lang.php create mode 100644 Upload/inc/languages/polish/admin/tools_warninglog.lang.php create mode 100644 Upload/inc/languages/polish/admin/user_admin_permissions.lang.php create mode 100644 Upload/inc/languages/polish/admin/user_banning.lang.php create mode 100644 Upload/inc/languages/polish/admin/user_group_promotions.lang.php create mode 100644 Upload/inc/languages/polish/admin/user_groups.lang.php create mode 100644 Upload/inc/languages/polish/admin/user_mass_mail.lang.php create mode 100644 Upload/inc/languages/polish/admin/user_module_meta.lang.php create mode 100644 Upload/inc/languages/polish/admin/user_titles.lang.php create mode 100644 Upload/inc/languages/polish/admin/user_users.lang.php create mode 100644 Upload/inc/languages/polish/announcements.lang.php create mode 100644 Upload/inc/languages/polish/archive.lang.php create mode 100644 Upload/inc/languages/polish/calendar.lang.php create mode 100644 Upload/inc/languages/polish/contact.lang.php create mode 100644 Upload/inc/languages/polish/customhelpdocs.lang.php create mode 100644 Upload/inc/languages/polish/customhelpsections.lang.php create mode 100644 Upload/inc/languages/polish/datahandler_event.lang.php create mode 100644 Upload/inc/languages/polish/datahandler_login.lang.php create mode 100644 Upload/inc/languages/polish/datahandler_pm.lang.php create mode 100644 Upload/inc/languages/polish/datahandler_post.lang.php create mode 100644 Upload/inc/languages/polish/datahandler_user.lang.php create mode 100644 Upload/inc/languages/polish/datahandler_warnings.lang.php create mode 100644 Upload/inc/languages/polish/editpost.lang.php create mode 100644 Upload/inc/languages/polish/forumdisplay.lang.php create mode 100644 Upload/inc/languages/polish/global.lang.php create mode 100644 Upload/inc/languages/polish/helpdocs.lang.php create mode 100644 Upload/inc/languages/polish/helpsections.lang.php create mode 100644 Upload/inc/languages/polish/index.html create mode 100644 Upload/inc/languages/polish/index.lang.php create mode 100644 Upload/inc/languages/polish/mailhandler.lang.php create mode 100644 Upload/inc/languages/polish/managegroup.lang.php create mode 100644 Upload/inc/languages/polish/member.lang.php create mode 100644 Upload/inc/languages/polish/memberlist.lang.php create mode 100644 Upload/inc/languages/polish/messages.lang.php create mode 100644 Upload/inc/languages/polish/misc.lang.php create mode 100644 Upload/inc/languages/polish/modcp.lang.php create mode 100644 Upload/inc/languages/polish/moderation.lang.php create mode 100644 Upload/inc/languages/polish/newreply.lang.php create mode 100644 Upload/inc/languages/polish/newthread.lang.php create mode 100644 Upload/inc/languages/polish/online.lang.php create mode 100644 Upload/inc/languages/polish/polls.lang.php create mode 100644 Upload/inc/languages/polish/portal.lang.php create mode 100644 Upload/inc/languages/polish/printthread.lang.php create mode 100644 Upload/inc/languages/polish/private.lang.php create mode 100644 Upload/inc/languages/polish/ratethread.lang.php create mode 100644 Upload/inc/languages/polish/report.lang.php create mode 100644 Upload/inc/languages/polish/reputation.lang.php create mode 100644 Upload/inc/languages/polish/search.lang.php create mode 100644 Upload/inc/languages/polish/sendthread.lang.php create mode 100644 Upload/inc/languages/polish/showteam.lang.php create mode 100644 Upload/inc/languages/polish/showthread.lang.php create mode 100644 Upload/inc/languages/polish/stats.lang.php create mode 100644 Upload/inc/languages/polish/syndication.lang.php create mode 100644 Upload/inc/languages/polish/usercp.lang.php create mode 100644 Upload/inc/languages/polish/usercpnav.lang.php create mode 100644 Upload/inc/languages/polish/warnings.lang.php create mode 100644 Upload/inc/languages/polish/xmlhttp.lang.php create mode 100644 Upload/inc/mailhandlers/index.html create mode 100644 Upload/inc/mailhandlers/php.php create mode 100644 Upload/inc/mailhandlers/smtp.php create mode 100644 Upload/inc/mybb_group.php create mode 100644 Upload/inc/plugins/hello.php create mode 100644 Upload/inc/plugins/index.html create mode 100644 Upload/inc/settings.php create mode 100644 Upload/inc/tasks/backupdb.php create mode 100644 Upload/inc/tasks/checktables.php create mode 100644 Upload/inc/tasks/dailycleanup.php create mode 100644 Upload/inc/tasks/delayedmoderation.php create mode 100644 Upload/inc/tasks/hourlycleanup.php create mode 100644 Upload/inc/tasks/index.html create mode 100644 Upload/inc/tasks/logcleanup.php create mode 100644 Upload/inc/tasks/massmail.php create mode 100644 Upload/inc/tasks/promotions.php create mode 100644 Upload/inc/tasks/recachestylesheets.php create mode 100644 Upload/inc/tasks/threadviews.php create mode 100644 Upload/inc/tasks/usercleanup.php create mode 100644 Upload/inc/tasks/userpruning.php create mode 100644 Upload/inc/tasks/versioncheck.php create mode 100644 Upload/index.php create mode 100644 Upload/install/images/active.png create mode 100644 Upload/install/images/inactive.png create mode 100644 Upload/install/images/index.html create mode 100644 Upload/install/images/logo.png create mode 100644 Upload/install/images/submit_bg.png create mode 100644 Upload/install/images/tcat.png create mode 100644 Upload/install/images/thead.png create mode 100644 Upload/install/index.php create mode 100644 Upload/install/resources/adminoptions.xml create mode 100644 Upload/install/resources/adminviews.xml create mode 100644 Upload/install/resources/index.html create mode 100644 Upload/install/resources/language.lang.php create mode 100644 Upload/install/resources/mybb_theme.xml create mode 100644 Upload/install/resources/mybb_theme_colors.xml create mode 100644 Upload/install/resources/mysql_db_inserts.php create mode 100644 Upload/install/resources/mysql_db_tables.php create mode 100644 Upload/install/resources/output.php create mode 100644 Upload/install/resources/pgsql_db_tables.php create mode 100644 Upload/install/resources/settings.xml create mode 100644 Upload/install/resources/sqlite_db_tables.php create mode 100644 Upload/install/resources/tasks.xml create mode 100644 Upload/install/resources/upgrade1.php create mode 100644 Upload/install/resources/upgrade10.php create mode 100644 Upload/install/resources/upgrade11.php create mode 100644 Upload/install/resources/upgrade12.php create mode 100644 Upload/install/resources/upgrade13.php create mode 100644 Upload/install/resources/upgrade14.php create mode 100644 Upload/install/resources/upgrade15.php create mode 100644 Upload/install/resources/upgrade16.php create mode 100644 Upload/install/resources/upgrade17.php create mode 100644 Upload/install/resources/upgrade18.php create mode 100644 Upload/install/resources/upgrade19.php create mode 100644 Upload/install/resources/upgrade2.php create mode 100644 Upload/install/resources/upgrade20.php create mode 100644 Upload/install/resources/upgrade21.php create mode 100644 Upload/install/resources/upgrade22.php create mode 100644 Upload/install/resources/upgrade23.php create mode 100644 Upload/install/resources/upgrade24.php create mode 100644 Upload/install/resources/upgrade25.php create mode 100644 Upload/install/resources/upgrade26.php create mode 100644 Upload/install/resources/upgrade27.php create mode 100644 Upload/install/resources/upgrade28.php create mode 100644 Upload/install/resources/upgrade29.php create mode 100644 Upload/install/resources/upgrade3.php create mode 100644 Upload/install/resources/upgrade30.php create mode 100644 Upload/install/resources/upgrade31.php create mode 100644 Upload/install/resources/upgrade4.php create mode 100644 Upload/install/resources/upgrade5.php create mode 100644 Upload/install/resources/upgrade6.php create mode 100644 Upload/install/resources/upgrade7.php create mode 100644 Upload/install/resources/upgrade8.php create mode 100644 Upload/install/resources/upgrade9.php create mode 100644 Upload/install/resources/usergroups.xml create mode 100644 Upload/install/stylesheet.css create mode 100644 Upload/install/upgrade.php create mode 100644 Upload/jscripts/bbcodes_sceditor.js create mode 100644 Upload/jscripts/captcha.js create mode 100644 Upload/jscripts/general.js create mode 100644 Upload/jscripts/index.html create mode 100644 Upload/jscripts/inline_edit.js create mode 100644 Upload/jscripts/inline_moderation.js create mode 100644 Upload/jscripts/jeditable/jeditable.min.js create mode 100644 Upload/jscripts/jquery.js create mode 100644 Upload/jscripts/jquery.plugins.js create mode 100644 Upload/jscripts/jquery.plugins.min.js create mode 100644 Upload/jscripts/post.js create mode 100644 Upload/jscripts/question.js create mode 100644 Upload/jscripts/rating.js create mode 100644 Upload/jscripts/report.js create mode 100644 Upload/jscripts/sceditor/editor_plugins/bbcode.js create mode 100644 Upload/jscripts/sceditor/editor_plugins/format.js create mode 100644 Upload/jscripts/sceditor/editor_plugins/index.html create mode 100644 Upload/jscripts/sceditor/editor_plugins/xhtml.js create mode 100644 Upload/jscripts/sceditor/editor_themes/buttons.css create mode 100644 Upload/jscripts/sceditor/editor_themes/default.css create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/alien.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/angel.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/angry.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/blink.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/blush.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/cheerful.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/cool.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/credits.txt create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/cwy.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/devil.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/dizzy.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/ermm.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/face.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/getlost.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/grin.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/happy.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/heart.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/kissing.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/laughing.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/ninja.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/pinch.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/pouty.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/sad.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/shocked.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/sick.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/sideways.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/silly.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/sleeping.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/smile.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/tongue.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/unsure.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/w00t.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/wassat.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/whistling.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/wink.png create mode 100644 Upload/jscripts/sceditor/editor_themes/emoticons/wub.png create mode 100644 Upload/jscripts/sceditor/editor_themes/famfamfam.png create mode 100644 Upload/jscripts/sceditor/editor_themes/index.html create mode 100644 Upload/jscripts/sceditor/editor_themes/modern.css create mode 100644 Upload/jscripts/sceditor/editor_themes/monocons.css create mode 100644 Upload/jscripts/sceditor/editor_themes/monocons/monocons.eot create mode 100644 Upload/jscripts/sceditor/editor_themes/monocons/monocons.ttf create mode 100644 Upload/jscripts/sceditor/editor_themes/mybb.css create mode 100644 Upload/jscripts/sceditor/editor_themes/office-toolbar.css create mode 100644 Upload/jscripts/sceditor/editor_themes/office.css create mode 100644 Upload/jscripts/sceditor/editor_themes/php.png create mode 100644 Upload/jscripts/sceditor/editor_themes/square.css create mode 100644 Upload/jscripts/sceditor/editor_themes/video.png create mode 100644 Upload/jscripts/sceditor/jquery.sceditor.bbcode.min.js create mode 100644 Upload/jscripts/sceditor/jquery.sceditor.default.min.css create mode 100644 Upload/jscripts/sceditor/jquery.sceditor.min.js create mode 100644 Upload/jscripts/sceditor/jquery.sceditor.xhtml.min.js create mode 100644 Upload/jscripts/sceditor/textarea_styles/jquery.sceditor.buttons.css create mode 100644 Upload/jscripts/sceditor/textarea_styles/jquery.sceditor.default.css create mode 100644 Upload/jscripts/sceditor/textarea_styles/jquery.sceditor.modern.css create mode 100644 Upload/jscripts/sceditor/textarea_styles/jquery.sceditor.monocons.css create mode 100644 Upload/jscripts/sceditor/textarea_styles/jquery.sceditor.mybb.css create mode 100644 Upload/jscripts/sceditor/textarea_styles/jquery.sceditor.office-toolbar.css create mode 100644 Upload/jscripts/sceditor/textarea_styles/jquery.sceditor.office.css create mode 100644 Upload/jscripts/sceditor/textarea_styles/jquery.sceditor.square.css create mode 100644 Upload/jscripts/select2/select2-spinner.gif create mode 100644 Upload/jscripts/select2/select2.css create mode 100644 Upload/jscripts/select2/select2.min.js create mode 100644 Upload/jscripts/select2/select2.png create mode 100644 Upload/jscripts/select2/select2x2.png create mode 100644 Upload/jscripts/thread.js create mode 100644 Upload/jscripts/usercp.js create mode 100644 Upload/jscripts/validate/additional-methods.min.js create mode 100644 Upload/jscripts/validate/jquery.validate.min.js create mode 100644 Upload/managegroup.php create mode 100644 Upload/member.php create mode 100644 Upload/memberlist.php create mode 100644 Upload/misc.php create mode 100644 Upload/modcp.php create mode 100644 Upload/moderation.php create mode 100644 Upload/newreply.php create mode 100644 Upload/newthread.php create mode 100644 Upload/online.php create mode 100644 Upload/polls.php create mode 100644 Upload/portal.php create mode 100644 Upload/printthread.php create mode 100644 Upload/private.php create mode 100644 Upload/ratethread.php create mode 100644 Upload/report.php create mode 100644 Upload/reputation.php create mode 100644 Upload/rss.php create mode 100644 Upload/search.php create mode 100644 Upload/sendthread.php create mode 100644 Upload/showteam.php create mode 100644 Upload/showthread.php create mode 100644 Upload/stats.php create mode 100644 Upload/syndication.php create mode 100644 Upload/task.php create mode 100644 Upload/uploads/avatars/index.html create mode 100644 Upload/uploads/index.html create mode 100644 Upload/usercp.php create mode 100644 Upload/usercp2.php create mode 100644 Upload/warnings.php create mode 100644 Upload/xmlhttp.php diff --git a/Upload/admin/backups/index.html b/Upload/admin/backups/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/backups/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/inc/class_form.php b/Upload/admin/inc/class_form.php new file mode 100644 index 0000000..c666a06 --- /dev/null +++ b/Upload/admin/inc/class_form.php @@ -0,0 +1,1054 @@ +\n"; + $form .= $this->generate_hidden_field("my_post_key", $mybb->post_code)."\n"; + if($return == false) + { + echo $form; + } + else + { + $this->_return = true; + $this->construct_return = $form; + } + } + + /** + * Generate and return a hidden field. + * + * @param string The name of the hidden field. + * @param string The value of the hidden field. + * @param array Optional array of options (id) + * @return string The generated hidden + */ + function generate_hidden_field($name, $value, $options=array()) + { + $input = ""; + $textarea .= htmlspecialchars_uni($value); + $textarea .= ""; + return $textarea; + } + + /** + * Generate a radio button. + * + * @param string The name of the radio button. + * @param string The value of the radio button + * @param string The label of the radio button if there is one. + * @param array Array of options for the radio button (id, class, checked) + * @return string The generated radio button. + */ + function generate_radio_button($name, $value="", $label="", $options=array()) + { + $input = " val format. + * @param mixed Either a string containing the selected item or an array containing multiple selected items (options['multiple'] must be true) + * @param array Array of options for the select box (multiple, class, id, size) + * @return string The select box. + */ + function generate_select_box($name, $option_list, $selected=array(), $options=array()) + { + if(!isset($options['multiple'])) + { + $select = "\n"; + return $select; + } + + /** + * Generate a forum selection box. + * + * @param string The name of the selection box. + * @param mixed Array/string of the selected items. + * @param array Array of options (pid, main_option, multiple) + * @param boolean Is this our first iteration of this function? + * @return string The built select box. + */ + function generate_forum_select($name, $selected, $options=array(), $is_first=1) + { + global $fselectcache, $forum_cache, $selectoptions; + + if(!$selectoptions) + { + $selectoptions = ''; + } + + if(!isset($options['depth'])) + { + $options['depth'] = 0; + } + + $options['depth'] = (int)$options['depth']; + + if(!isset($options['pid'])) + { + $options['pid'] = 0; + } + + $pid = (int)$options['pid']; + + if(!is_array($fselectcache)) + { + if(!is_array($forum_cache)) + { + $forum_cache = cache_forums(); + } + + foreach($forum_cache as $fid => $forum) + { + $fselectcache[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum; + } + } + + if($options['main_option'] && $is_first) + { + $select_add = ''; + if($selected == -1) + { + $select_add = " selected=\"selected\""; + } + + $selectoptions .= "\n"; + } + + if(isset($fselectcache[$pid])) + { + foreach($fselectcache[$pid] as $main) + { + foreach($main as $forum) + { + if($forum['fid'] != "0" && $forum['linkto'] == '') + { + $select_add = ''; + + if(!empty($selected) && ($forum['fid'] == $selected || (is_array($selected) && in_array($forum['fid'], $selected)))) + { + $select_add = " selected=\"selected\""; + } + + $sep = ''; + if(isset($options['depth'])) + { + $sep = str_repeat(" ", $options['depth']); + } + + $style = ""; + if($forum['active'] == 0) + { + $style = " style=\"font-style: italic;\""; + } + + $selectoptions .= "\n"; + + if($forum_cache[$forum['fid']]) + { + $options['depth'] += 5; + $options['pid'] = $forum['fid']; + $this->generate_forum_select($forum['fid'], $selected, $options, 0); + $options['depth'] -= 5; + } + } + } + } + } + + if($is_first == 1) + { + if(!isset($options['multiple'])) + { + $select = "read('usergroups'); + foreach($groups_cache as $group) + { + $selected_add = ""; + if(is_array($selected)) + { + if(in_array($group['gid'], $selected)) + { + $selected_add = " selected=\"selected\""; + } + } + + $select .= ""; + } + + $select .= ""; + + return $select; + } + + /** + * Generate a submit button. + * + * @param string The value for the submit button. + * @param array Array of options for the submit button (class, id, name, dsiabled, onclick) + * @return string The generated submit button. + */ + function generate_submit_button($value, $options=array()) + { + $input = "generate_radio_button($name, $yes_value, $lang->yes, $yes_options); + $no = $this->generate_radio_button($name, $no_value, $lang->no, $no_options); + return $yes." ".$no; + } + + /** + * Generate an on/off radio button choice. + * + * @param string The name of the on/off choice field. + * @param string The value that should be checked. + * @param boolean Using integers for the checkbox? + * @param array Array of options for the on checkbox (@see generate_radio_button) + * @param array Array of options for the off checkbox (@see generate_radio_button) + * @return string The generated on/off radio button. + */ + function generate_on_off_radio($name, $value=1, $int=true, $on_options=array(), $off_options = array()) + { + global $lang; + + // Checked status + if($value == "off" || (int) $value !== 1) + { + $off_checked = 1; + $on_checked = 0; + } + else + { + $on_checked = 1; + $off_checked = 0; + } + // Element value + if($int == true) + { + $on_value = 1; + $off_value = 0; + } + else + { + $on_value = "on"; + $off_value = "off"; + } + + // Set the options straight + if(!isset($on_options['class'])) + { + $on_options['class'] = ''; + } + + if(!isset($off_options['class'])) + { + $off_options['class'] = ''; + } + + $on_options['class'] = "radio_on ".$on_options['class']; + $on_options['checked'] = $on_checked; + $off_options['class'] = "radio_off ".$off_options['class']; + $off_options['checked'] = $off_checked; + + $on = $this->generate_radio_button($name, $on_value, $lang->on, $on_options); + $off = $this->generate_radio_button($name, $off_value, $lang->off, $off_options); + return $on." ".$off; + } + + function generate_date_select($name, $day="",$month="",$year="") + { + global $lang; + + $months = array( + 1 => $lang->january, + 2 => $lang->february, + 3 => $lang->march, + 4 => $lang->april, + 5 => $lang->may, + 6 => $lang->june, + 7 => $lang->july, + 8 => $lang->august, + 9 => $lang->september, + 10 => $lang->october, + 11 => $lang->november, + 12 => $lang->december, + ); + + // Construct option list for days + $days = array(); + for($i = 1; $i <= 31; ++$i) + { + $days[$i] = $i; + } + + if(!$day) + { + $day = date("j", TIME_NOW); + } + + if(!$month) + { + $month = date("n", TIME_NOW); + } + + if(!$year) + { + $year = date("Y", TIME_NOW); + } + + $built = $this->generate_select_box($name.'_day', $days, (int)$day, array('id' => $name.'_day'))."   "; + $built .= $this->generate_select_box($name.'_month', $months, (int)$month, array('id' => $name.'_month'))."   "; + $built .= $this->generate_text_box($name.'_year', (int)$year, array('id' => $name.'_year', 'style' => 'width: 100px;')); + return $built; + } + + /** + * Output a row of buttons in a wrapped container. + * + * @param array Array of the buttons (html) to output. + * @return string The submit wrapper (optional) + */ + function output_submit_wrapper($buttons) + { + global $plugins; + $buttons = $plugins->run_hooks("admin_form_output_submit_wrapper", $buttons); + $return = "
\n"; + foreach($buttons as $button) + { + $return .= $button." \n"; + } + $return .= "
\n"; + if($this->_return == false) + { + echo $return; + } + else + { + return $return; + } + } + + /** + * Finish up a form. + * + * @return string The ending form tag (optional) + */ + function end() + { + global $plugins; + $plugins->run_hooks("admin_form_end", $this); + if($this->_return == false) + { + echo ""; + } + else + { + return ""; + } + } +} + +/** + * Generate a form container. + */ +class DefaultFormContainer +{ + private $_container; + public $_title; + + /** + * Initialise the new form container. + * + * @param string The title of the forum container + * @param string An additional class to apply if we have one. + */ + function __construct($title='', $extra_class='') + { + $this->_container = new Table; + $this->extra_class = $extra_class; + $this->_title = $title; + } + + /** + * Output a header row of the form container. + * + * @param string The header row label. + * @param array Array of extra information for this header cell (class, style, colspan, width) + */ + function output_row_header($title, $extra=array()) + { + $this->_container->construct_header($title, $extra); + } + + /** + * Output a row of the form container. + * + * @param string The title of the row. + * @param string The description of the row/field. + * @param string The HTML content to show in the row. + * @param string The ID of the control this row should be a label for. + * @param array Array of options for the row cell. + * @param array Array of options for the row container. + */ + function output_row($title, $description="", $content="", $label_for="", $options=array(), $row_options=array()) + { + global $plugins; + $pluginargs = array( + 'title' => &$title, + 'description' => &$description, + 'content' => &$content, + 'label_for' => &$label_for, + 'options' => &$options, + 'row_options' => &$row_options, + 'this' => &$this + ); + + $plugins->run_hooks("admin_formcontainer_output_row", $pluginargs); + + $row = $for = ''; + if($label_for != '') + { + $for = " for=\"{$label_for}\""; + } + + if($title) + { + $row = "{$title}"; + } + + if(isset($options['id'])) + { + $options['id'] = " id=\"{$options['id']}\""; + } + else + { + $options['id'] = ''; + } + + if($description != '') + { + $row .= "\n
{$description}
\n"; + } + + $row .= "
{$content}
\n"; + + $this->_container->construct_cell($row, $options); + + if(!isset($options['skip_construct'])) + { + $this->_container->construct_row($row_options); + } + } + + /** + * Output a row cell for a table based form row. + * + * @param string The data to show in the cell. + * @param array Array of options for the cell (optional). + */ + function output_cell($data, $options=array()) + { + $this->_container->construct_cell($data, $options); + } + + /** + * Build a row for the table based form row. + * + * @param array Array of extra options for the cell (optional). + */ + function construct_row($extra=array()) + { + $this->_container->construct_row($extra); + } + + /** + * return the cells of a row for the table based form row. + * + * @param string The id of the row. + * @param boolean Whether or not to return or echo the resultant contents. + * @return string The output of the row cells (optional). + */ + function output_row_cells($row_id, $return=false) + { + if(!$return) + { + echo $this->_container->output_row_cells($row_id, $return); + } + else + { + return $this->_container->output_row_cells($row_id, $return); + } + } + + /** + * Count the number of rows in the form container. Useful for displaying a 'no rows' message. + * + * @return int The number of rows in the form container. + */ + function num_rows() + { + return $this->_container->num_rows(); + } + + /** + * Output the end of the form container row. + * + * @param boolean Whether or not to return or echo the resultant contents. + * @return string The output of the form container (optional). + */ + function end($return=false) + { + global $plugins; + + $hook = array( + 'return' => &$return, + 'this' => &$this + ); + + $plugins->run_hooks("admin_formcontainer_end", $hook); + if($return == true) + { + return $this->_container->output($this->_title, 1, "general form_container {$this->extra_class}", true); + } + else + { + echo $this->_container->output($this->_title, 1, "general form_container {$this->extra_class}", false); + } + } +} + diff --git a/Upload/admin/inc/class_page.php b/Upload/admin/inc/class_page.php new file mode 100644 index 0000000..1b19fe7 --- /dev/null +++ b/Upload/admin/inc/class_page.php @@ -0,0 +1,1166 @@ + tags. + */ + public $extra_header = ""; + + /** + * @var string Any additional messages to add after the flash messages are shown. + */ + public $extra_messages = array(); + + /** + * @var string Show a post verify error + */ + public $show_post_verify_error = ''; + + /** + * Output the page header. + * + * @param string The title of the page. + */ + function output_header($title="") + { + global $mybb, $admin_session, $lang, $plugins; + + $args = array( + 'this' => &$this, + 'title' => &$title, + ); + + $plugins->run_hooks("admin_page_output_header", $args); + + if(!$title) + { + $title = $lang->mybb_admin_panel; + } + + $rtl = ""; + if($lang->settings['rtl'] == 1) + { + $rtl = " dir=\"rtl\""; + } + + echo "\n"; + echo "\n"; + echo "\n"; + echo " ".$title."\n"; + echo " \n"; + echo " \n"; + echo " style."/main.css\" type=\"text/css\" />\n"; + echo " style."/modal.css\" type=\"text/css\" />\n"; + + // Load stylesheet for this module if it has one + if(file_exists(MYBB_ADMIN_DIR."styles/{$this->style}/{$this->active_module}.css")) + { + echo " style}/{$this->active_module}.css\" type=\"text/css\" />\n"; + } + + echo " \n"; + echo " \n"; + echo " \n"; + echo " \n"; + echo " \n"; + + echo " \n"; + echo " \n"; + echo " \n"; + echo " \n"; + + // Stop JS elements showing while page is loading (JS supported browsers only) + echo " \n"; + echo " \n"; + + echo " \n"; + echo $this->extra_header; + echo "\n"; + echo "\n"; + echo "
\n"; + echo "

{$lang->mybb_admin_cp}

\n"; + echo " \n"; + echo $this->_build_menu(); + echo "
\n"; + echo "
\n"; + echo $this->submenu; + echo $this->sidebar; + echo "
\n"; + echo "
\n"; + echo "
\n"; + echo $this->_generate_breadcrumb(); + echo "
\n"; + echo "
\n"; + if(isset($admin_session['data']['flash_message']) && $admin_session['data']['flash_message']) + { + $message = $admin_session['data']['flash_message']['message']; + $type = $admin_session['data']['flash_message']['type']; + echo "
\n"; + echo "{$message}\n"; + echo "
\n"; + update_admin_session('flash_message', ''); + } + + if(!empty($this->extra_messages) && is_array($this->extra_messages)) + { + foreach($this->extra_messages as $message) + { + switch($message['type']) + { + case 'success': + case 'error': + echo "
\n"; + echo "{$message['message']}\n"; + echo "
\n"; + break; + default: + $this->output_error($message['message']); + break; + } + } + } + + if($this->show_post_verify_error == true) + { + $this->output_error($lang->invalid_post_verify_key); + } + } + + /** + * Output the page footer. + */ + function output_footer($quit=true) + { + global $mybb, $maintimer, $db, $lang, $plugins; + + $args = array( + 'this' => &$this, + 'quit' => &$quit, + ); + + $plugins->run_hooks("admin_page_output_footer", $args); + + $memory_usage = get_friendly_size(get_memory_usage()); + + $totaltime = format_time_duration($maintimer->stop()); + $querycount = $db->query_count; + + if(my_strpos(getenv("REQUEST_URI"), "?")) + { + $debuglink = htmlspecialchars_uni(getenv("REQUEST_URI")) . "&debug=1#footer"; + } + else + { + $debuglink = htmlspecialchars_uni(getenv("REQUEST_URI")) . "?debug=1#footer"; + } + + echo "
\n"; + echo "
\n"; + echo "
"; + echo "
"; + echo "
\n"; + echo "

".$lang->sprintf($lang->generated_in, $totaltime, $debuglink, $querycount, $memory_usage)."

Powered By MyBB, © 2002-".COPY_YEAR." MyBB Group.

\n"; + if($mybb->debug_mode) + { + echo $db->explain; + } + echo "
\n"; + echo "\n"; + echo "\n"; + + if($quit != false) + { + exit; + } + } + + /** + * Add an item to the page breadcrumb trail. + * + * @param string The name of the item to add. + * @param string The URL to the item we're adding (if there is one) + */ + function add_breadcrumb_item($name, $url="") + { + $this->_breadcrumb_trail[] = array("name" => $name, "url" => $url); + } + + /** + * Generate a breadcrumb trail. + */ + function _generate_breadcrumb() + { + if(!is_array($this->_breadcrumb_trail)) + { + return false; + } + $trail = ""; + foreach($this->_breadcrumb_trail as $key => $crumb) + { + if(isset($this->_breadcrumb_trail[$key+1])) + { + $trail .= "".$crumb['name'].""; + if(isset($this->_breadcrumb_trail[$key+2])) + { + $trail .= " » "; + } + } + else + { + $trail .= "".$crumb['name'].""; + } + } + return $trail; + } + + /** + * Output a success message. + * + * @param string The message to output. + */ + function output_success($message) + { + echo "
{$message}
\n"; + } + + /** + * Output an alert/warning message. + * + * @param string The message to output. + * @param string The ID of the alert/warning (optional) + */ + function output_alert($message, $id="") + { + if($id) + { + $id = " id=\"{$id}\""; + } + echo "
{$message}
\n"; + } + + /** + * Output an inline message. + * + * @param string The message to output. + */ + function output_inline_message($message) + { + echo "
{$message}
\n"; + } + + /** + * Output a single error message. + * + * @param string The message to output. + */ + function output_error($error) + { + echo "
\n"; + echo "{$error}\n"; + echo "
\n"; + } + + /** + * Output one or more inline error messages. + * + * @param array Array of error messages to output. + */ + function output_inline_error($errors) + { + global $lang; + + if(!is_array($errors)) + { + $errors = array($errors); + } + echo "
\n"; + echo "

{$lang->encountered_errors}

\n"; + echo "
    \n"; + foreach($errors as $error) + { + echo "
  • {$error}
  • \n"; + } + echo "
\n"; + echo "
\n"; + } + + /** + * Generate the login page. + * + * @param string The any message to output on the page if there is one. + * @param string The class name of the message (defaults to success) + */ + function show_login($message="", $class="success") + { + global $plugins, $lang, $cp_style, $mybb; + + $args = array( + 'this' => &$this, + 'message' => &$message, + 'class' => &$class + ); + + $plugins->run_hooks('admin_page_show_login_start', $args); + + $copy_year = COPY_YEAR; + + $login_container_width = ""; + $login_label_width = ""; + + // If the language string for "Username" is too cramped then use this to define how much larger you want the gap to be (in px) + if(isset($lang->login_field_width)) + { + $login_label_width = " style=\"width: ".((int)$lang->login_field_width+100)."px;\""; + $login_container_width = " style=\"width: ".(410+((int)$lang->login_field_width))."px;\""; + } + + $login_page .= << + + +{$lang->mybb_admin_login} + + + + + + + + + +
+ +
+

{$lang->please_login}

+EOF; + if($message) + { + $login_page .= "

{$message}

"; + } + // Make query string nice and pretty so that user can go to his/her preferred destination + $query_string = ''; + if($_SERVER['QUERY_STRING']) + { + $query_string = '?'.preg_replace('#adminsid=(.{32})#i', '', $_SERVER['QUERY_STRING']); + $query_string = preg_replace('#my_post_key=(.{32})#i', '', $query_string); + $query_string = str_replace('action=logout', '', $query_string); + $query_string = preg_replace('#&+#', '&', $query_string); + $query_string = str_replace('?&', '?', $query_string); + $query_string = htmlspecialchars_uni($query_string); + } + switch($mybb->settings['username_method']) + { + case 0: + $lang_username = $lang->username; + break; + case 1: + $lang_username = $lang->username1; + break; + case 2: + $lang_username = $lang->username2; + break; + default: + $lang_username = $lang->username; + break; + } + + // Secret PIN + global $config; + if(isset($config['secret_pin']) && $config['secret_pin'] != '') + { + $secret_pin = "
+
"; + } + else + { + $secret_pin = ''; + } + + $login_lang_string = $lang->enter_username_and_password; + + switch($mybb->settings['username_method']) + { + case 0: // Username only + $login_lang_string = $lang->sprintf($login_lang_string, $lang->login_username); + break; + case 1: // Email only + $login_lang_string = $lang->sprintf($login_lang_string, $lang->login_email); + break; + case 2: // Username and email + default: + $login_lang_string = $lang->sprintf($login_lang_string, $lang->login_username_and_password); + break; + } + + $_SERVER['PHP_SELF'] = htmlspecialchars_uni($_SERVER['PHP_SELF']); + + $login_page .= <<{$login_lang_string}

+
+
+ +
+ +
+ +
+
+ {$secret_pin} +
+

+ + {$lang->lost_password} + + + + +

+
+
+
+ + +EOF; + + $args = array( + 'this' => &$this, + 'login_page' => &$login_page + ); + + $plugins->run_hooks('admin_page_show_login_end', $args); + + echo $login_page; + exit; + } + + /** + * Generate the lockout page + * + */ + function show_lockedout() + { + global $lang, $mybb, $cp_style; + + $copy_year = COPY_YEAR; + $allowed_attempts = (int)$mybb->settings['maxloginattempts']; + $lockedout_message = $lang->sprintf($lang->error_mybb_admin_lockedout_message, $allowed_attempts); + + print << + + +{$lang->mybb_admin_cp} - {$lang->error_mybb_admin_lockedout} + + + + + +
+ +
+

{$lang->error_mybb_admin_lockedout}

+
{$lockedout_message}
+
+
+ + +EOF; + exit; + } + + /** + * Generate the lockout unlock page + * + * @param string The any message to output on the page if there is one. + * @param string The class name of the message (defaults to success) + */ + function show_lockout_unlock($message="", $class="success") + { + global $lang, $mybb, $cp_style; + + $copy_year = COPY_YEAR; + switch($mybb->settings['username_method']) + { + case 0: + $lang_username = $lang->username; + break; + case 1: + $lang_username = $lang->username1; + break; + case 2: + $lang_username = $lang->username2; + break; + default: + $lang_username = $lang->username; + break; + } + + if($message) + { + $message = "

{$message}

"; + } + + print << + + +{$lang->mybb_admin_cp} - {$lang->lockout_unlock} + + + + + +
+ +
+

{$lang->lockout_unlock}

+ {$message} +

{$lang->enter_username_and_token}

+
+
+ +
+ +
+ +
+
+
+

+ + {$lang->lost_password} + + + + +

+
+
+
+ + +EOF; + exit; + } + + /** + * Add an item to the primary navigation menu. + * + * @param string The title of the menu item. + * @param string The ID of the menu item. This should correspond with the module the menu will run. + * @param string The link to follow when the menu item is clicked. + * @param int The display order of the menu item. Lower display order means closer to start of the menu. + * @param array Array of sub menu items if there are any. + */ + function add_menu_item($title, $id, $link, $order=10, $submenu=array()) + { + $this->_menu[$order][] = array( + "title" => $title, + "id" => $id, + "link" => $link, + "submenu" => $submenu + ); + } + + /** + * Build the actual navigation menu. + */ + function _build_menu() + { + if(!is_array($this->_menu)) + { + return false; + } + $build_menu = "
\n
    \n"; + ksort($this->_menu); + foreach($this->_menu as $items) + { + foreach($items as $menu_item) + { + $menu_item['link'] = htmlspecialchars_uni($menu_item['link']); + if($menu_item['id'] == $this->active_module) + { + $sub_menu = $menu_item['submenu']; + $sub_menu_title = $menu_item['title']; + $build_menu .= "
  • {$menu_item['title']}
  • \n"; + + } + else + { + $build_menu .= "
  • {$menu_item['title']}
  • \n"; + } + } + } + $build_menu .= "
\n
"; + + if($sub_menu) + { + $this->_build_submenu($sub_menu_title, $sub_menu); + } + return $build_menu; + } + + /** + * Build a navigation sub menu if we have one. + * + * @param string A title for the sub menu. + * @param array Array of items for the sub menu. + */ + function _build_submenu($title, $items) + { + if(is_array($items)) + { + $sidebar = new sideBarItem($title); + $sidebar->add_menu_items($items, $this->active_action); + $this->submenu .= $sidebar->get_markup(); + } + } + + /** + * Switch between two different alternating background colours. + */ + function get_alt_bg() + { + static $alt_bg; + if($alt_bg == "alt1") + { + $alt_bg = "alt2"; + return "alt1"; + } + else + { + $alt_bg = "alt1"; + return $alt_bg; + } + } + + /** + * Output a Javascript based tab control on to the page. + * + * @param array Array of tabs in name => title format. Name should correspond to the name of a DIV containing the tab content. + * @param boolean Whether or not to run the event onload or instantly + * @param string The ID to use for the tabs for if you run multiple instances of the tabbing control in one html page + */ + function output_tab_control($tabs=array(), $observe_onload=true, $id="tabs") + { + global $plugins; + $tabs = $plugins->run_hooks("admin_page_output_tab_control_start", $tabs); + echo "
    \n"; + $tab_count = count($tabs); + $done = 1; + foreach($tabs as $anchor => $title) + { + $class = ""; + if($tab_count == $done) + { + $class .= " last"; + } + if($done == 1) + { + $class .= " first"; + } + ++$done; + echo "
  • {$title}
  • \n"; + } + echo "
\n"; + $plugins->run_hooks("admin_page_output_tab_control_end", $tabs); + } + + /** + * Output a series of primary navigation tabs for swithcing between items within a particular module/action. + * + * @param array Nested array of tabs containing possible keys of align, link_target, link, title. + * @param string The name of the active tab. Corresponds with the key of each tab item. + */ + function output_nav_tabs($tabs=array(), $active='') + { + global $plugins; + $tabs = $plugins->run_hooks("admin_page_output_nav_tabs_start", $tabs); + echo "
"; + echo "\t
    \n"; + foreach($tabs as $id => $tab) + { + $class = ''; + if($id == $active) + { + $class = ' active'; + } + if(isset($tab['align']) == "right") + { + $class .= " right"; + } + $target = ''; + if(isset($tab['link_target'])) + { + $target = " target=\"{$tab['link_target']}\""; + } + if(!isset($tab['link'])) + { + $tab['link'] = ''; + } + echo "\t\t
  • {$tab['title']}
  • \n"; + $target = ''; + } + echo "\t
\n"; + if($tabs[$active]['description']) + { + echo "\t
{$tabs[$active]['description']}
\n"; + } + echo "
"; + $arguments = array('tabs' => $tabs, 'active' => $active); + $plugins->run_hooks("admin_page_output_nav_tabs_end", $arguments); + } + + /** + * Output a page asking if a user wishes to continue performing a specific action. + * + * @param string The URL to be forwarded to. + * @param string The confirmation message to output. + * @param string The title to use in the output header + */ + function output_confirm_action($url, $message="", $title="") + { + global $lang, $plugins; + + $args = array( + 'this' => &$this, + 'url' => &$url, + 'message' => &$message, + 'title' => &$title, + ); + + $plugins->run_hooks('admin_page_output_confirm_action', $args); + + if(!$message) + { + $message = $lang->confirm_action; + } + $this->output_header($title); + $form = new Form($url, 'post'); + + echo "
\n"; + echo "

{$message}

\n"; + echo "
\n"; + echo "

\n"; + echo $form->generate_submit_button($lang->yes, array('class' => 'button_yes')); + echo $form->generate_submit_button($lang->no, array("name" => "no", 'class' => 'button_no')); + echo "

\n"; + echo "
\n"; + + $form->end(); + $this->output_footer(); + } + + /** + * Build a clickable MyCode editor for the Admin CP. + * + * @param string The ID of the textarea to bind the editor to. + * @param string The language string for the editor. + * @return string The build MyCode editor Javascript. + */ + function build_codebuttons_editor($bind, $editor_language, $smilies) + { + global $lang, $mybb, $smiliecache, $cache; + + // Smilies + $emoticon = ""; + $emoticons_enabled = "false"; + if($smilies && $mybb->settings['smilieinserter'] != 0 && $mybb->settings['smilieinsertercols'] && $mybb->settings['smilieinsertertot']) + { + $emoticon = ",emoticon"; + $emoticons_enabled = "true"; + if(!$smiliecount) + { + $smilie_cache = $cache->read("smilies"); + $smiliecount = count($smilie_cache); + } + + if(!$smiliecache) + { + if(!is_array($smilie_cache)) + { + $smilie_cache = $cache->read("smilies"); + } + foreach($smilie_cache as $smilie) + { + if($smilie['showclickable'] != 0) + { + $smiliecache[$smilie['find']] = $smilie['image']; + } + } + } + + unset($smilie); + + if(is_array($smiliecache)) + { + reset($smiliecache); + + $dropdownsmilies = $moresmilies = $hiddensmilies = ""; + $i = 0; + + foreach($smiliecache as $find => $image) + { + $finds = explode("\n", $find); + $finds_count = count($finds); + + // Only show the first text to replace in the box + $find = htmlspecialchars_uni($finds[0]); + $image = htmlspecialchars_uni($image); + if(substr($image, 0, 4) != "http") + { + $image = $mybb->settings['bburl']."/".$image; + } + if($i < $mybb->settings['smilieinsertertot']) + { + $dropdownsmilies .= '"'.$find.'": "'.$image.'",'; + } + else + { + $moresmilies .= '"'.$find.'": "'.$image.'",'; + } + + for($j = 1; $j < $finds_count; ++$j) + { + $find = htmlspecialchars_uni($finds[$j]); + $hiddensmilies .= '"'.$find.'": "'.$image.'",'; + } + ++$i; + } + } + } + + $basic1 = $basic2 = $align = $font = $size = $color = $removeformat = $email = $link = $list = $code = $sourcemode = ""; + + if($mybb->settings['allowbasicmycode'] == 1) + { + $basic1 = "bold,italic,underline,strike|"; + $basic2 = "horizontalrule,"; + } + + if($mybb->settings['allowalignmycode'] == 1) + { + $align = "left,center,right,justify|"; + } + + if($mybb->settings['allowfontmycode'] == 1) + { + $font = "font,"; + } + + if($mybb->settings['allowsizemycode'] == 1) + { + $size = "size,"; + } + + if($mybb->settings['allowcolormycode'] == 1) + { + $color = "color,"; + } + + if($mybb->settings['allowfontmycode'] == 1 || $mybb->settings['allowsizemycode'] == 1 || $mybb->settings['allowcolormycode'] == 1) + { + $removeformat = "removeformat|"; + } + + if($mybb->settings['allowemailmycode'] == 1) + { + $email = "email,"; + } + + if($mybb->settings['allowlinkmycode'] == 1) + { + $link = "link,unlink"; + } + + if($mybb->settings['allowlistmycode'] == 1) + { + $list = "bulletlist,orderedlist|"; + } + + if($mybb->settings['allowcodemycode'] == 1) + { + $code = "code,php,"; + } + + if($mybb->user['sourceeditor'] == 1) + { + $sourcemode = "MyBBEditor.sourceMode(true);"; + } + + return << +var partialmode = {$mybb->settings['partialmode']}, +opt_editor = { + plugins: "bbcode", + style: "../jscripts/sceditor/textarea_styles/jquery.sceditor.mybb.css", + rtl: {$lang->settings['rtl']}, + locale: "mybblang", + enablePasteFiltering: true, + emoticonsEnabled: {$emoticons_enabled}, + emoticons: { + // Emoticons to be included in the dropdown + dropdown: { + {$dropdownsmilies} + }, + // Emoticons to be included in the more section + more: { + {$moresmilies} + }, + // Emoticons that are not shown in the dropdown but will still be converted. Can be used for things like aliases + hidden: { + {$hiddensmilies} + } + }, + emoticonsCompat: true, + toolbar: "{$basic1}{$align}{$font}{$size}{$color}{$removeformat}{$basic2}image,{$email}{$link}|video{$emoticon}|{$list}{$code}quote|maximize,source", +}; +{$editor_language} +$(function() { + $("#{$bind}").sceditor(opt_editor); + + MyBBEditor = $("#{$bind}").sceditor("instance"); + {$sourcemode} +}); + +EOF; + } +} + +/** + * A class for generating side bar blocks. + */ +class DefaultSidebarItem +{ + /** + * @var The title of the side bar block. + */ + private $_title; + + /** + * @var string The contents of the side bar block. + */ + private $_contents; + + /** + * Constructor. Set the title of the side bar block. + * + * @param string The title of the side bar block. + */ + function __construct($title="") + { + $this->_title = $title; + } + + /** + * Add menus item to the side bar block. + * + * @param array Array of menu items to add. Each menu item should be a nested array of id, link and title. + * @param string The ID of the active menu item if there is one. + */ + function add_menu_items($items, $active) + { + global $run_module; + + $this->_contents = "
    "; + foreach($items as $item) + { + if(!check_admin_permissions(array("module" => $run_module, "action" => $item['id']), false)) + { + continue; + } + + $class = ""; + if($item['id'] == $active) + { + $class = "active"; + } + $item['link'] = htmlspecialchars_uni($item['link']); + $this->_contents .= "
  • {$item['title']}
  • \n"; + } + $this->_contents .= "
"; + } + + /** + * Sets custom html to the contents variable + * + * @param string The custom html to set + */ + function set_contents($html) + { + $this->_contents = $html; + } + + /** + * Fetch the HTML markup for the side bar box. + */ + function get_markup() + { + $markup = "
\n"; + $markup .= "
{$this->_title}
\n"; + if($this->_contents) + { + $markup .= $this->_contents; + } + $markup .= "
\n"; + return $markup; + } +} + +/** + * Generate a Javascript based popup menu. + */ +class DefaultPopupMenu +{ + /** + * @var string The title of the popup menu to be shown on the button. + */ + private $_title; + + /** + * @var string The ID of this popup menu. Must be unique. + */ + private $_id; + + /** + * @var string Built HTML for the items in the popup menu. + */ + private $_items; + + /** + * Initialise a new popup menu. + * + * @var string The ID of the popup menu. + * @var string The title of the popup menu. + */ + function __construct($id, $title='') + { + $this->_id = $id; + $this->_title = $title; + } + + /** + * Add an item to the popup menu. + * + * @param string The title of this item. + * @param string The page this item should link to. + * @param string The onclick event handler if we have one. + */ + function add_item($text, $link, $onclick='') + { + if($onclick) + { + $onclick = " onclick=\"{$onclick}\""; + } + $this->_items .= "\n"; + } + + /** + * Fetch the contents of the popup menu. + * + * @return string The popup menu. + */ + function fetch() + { + $popup = "
_id}_popup\">\n{$this->_items}
\n"; + if($this->_title) + { + $popup .= "_id}\" class=\"popup_button\">{$this->_title}\n"; + } + $popup .= "\n"; + return $popup; + } + + /** + * Outputs a popup menu to the browser. + */ + function output() + { + echo $this->fetch(); + } +} diff --git a/Upload/admin/inc/class_table.php b/Upload/admin/inc/class_table.php new file mode 100644 index 0000000..894bf39 --- /dev/null +++ b/Upload/admin/inc/class_table.php @@ -0,0 +1,297 @@ +_cells[] = array("data" => $data, "extra" => $extra); + } + + /** + * Construct a row from the earlier defined constructed cells for the table. + * + * @param array Array of extra information about this row (class, id) + */ + function construct_row($extra = array()) + { + $i = 1; + $cells = ''; + + foreach(array('class', 'style', 'id', 'rowspan', 'width') as $field) + { + // Common-used fields + if(!isset($extra[$field])) + { + $extra[$field] = ''; + } + } + + // We construct individual cells here + foreach($this->_cells as $key => $cell) + { + $cells .= "\t\t\t_cells[$key+1])) + { + $cell['extra']['class'] .= " last"; + } + if($i == 2) + { + $cell['extra']['class'] .= " alt_col"; + $i = 0; + } + $i++; + if(isset($cell['extra']['class'])) + { + $cells .= " class=\"".trim($cell['extra']['class'])."\""; + } + if(isset($cell['extra']['style'])) + { + $cells .= " style=\"".$cell['extra']['style']."\""; + } + if(isset($cell['extra']['id'])) + { + $cells .= " id=\"".$cell['extra']['id']."\""; + } + if(isset($cell['extra']['colspan']) && $cell['extra']['colspan'] > 1) + { + $cells .= " colspan=\"".$cell['extra']['colspan']."\""; + } + if(isset($cell['extra']['rowspan']) && $cell['extra']['rowspan'] > 1) + { + $cells .= " rowspan=\"".$cell['extra']['rowspan']."\""; + } + if(isset($cell['extra']['width'])) + { + $cells .= " width=\"".$cell['extra']['width']."\""; + } + $cells .= ">"; + $cells .= $cell['data']; + $cells .= "\n"; + } + $data['cells'] = $cells; + $data['extra'] = $extra; + $this->_rows[] = $data; + + $this->_cells = array(); + } + + /** + * return the cells of a row for the table based row. + * + * @param string The id of the row you want to give it. + * @param boolean Whether or not to return or echo the resultant contents. + * @return string The output of the row cells (optional). + */ + function output_row_cells($row_id, $return=false) + { + $row = $this->_rows[$row_id]['cells']; + + if(!$return) + { + echo $row; + } + else + { + return $row; + } + } + + /** + * Count the number of rows in the table. Useful for displaying a 'no rows' message. + * + * @return int The number of rows in the table. + */ + function num_rows() + { + return count($this->_rows); + } + + /** + * Construct a header cell for this table. + * + * @param string The HTML content for this header cell. + * @param array Array of extra information for this header cell (class, style, colspan, width) + */ + function construct_header($data, $extra=array()) + { + $this->_headers[] = array("data" => $data, "extra" => $extra); + } + + /** + * Output this table to the browser. + * + * @param string The heading for this table. + * @param int The border width for this table. + * @param string The class for this table. + * @param boolean Whether or not to return or echo the resultant contents. + * @return string The output of the row cells (optional). + */ + function output($heading="", $border=1, $class="general", $return=false) + { + if($return == true) + { + return $this->construct_html($heading, $border, $class); + } + else + { + echo $this->construct_html($heading, $border, $class); + } + } + + /** + * Fetch the built HTML for this table. + * + * @param string The heading for this table. + * @param int The border width for this table. + * @param string The class for this table. + * @param string The id for this table. + * @return string The built HTML. + */ + function construct_html($heading="", $border=1, $class=null, $table_id="") + { + $table = ''; + if($border == 1) + { + $table .= "
\n"; + if($heading != "") + { + $table .= "
".$heading."
\n"; + } + } + $table .= "\n"; + if($this->_headers) + { + $table .= "\t\n"; + $table .= "\t\t\n"; + foreach($this->_headers as $key => $data) + { + $table .= "\t\t\t_headers[$key+1])) + { + $data['extra']['class'] .= " last"; + } + if(isset($data['extra']['class'])) + { + $table .= " class=\"".$data['extra']['class']."\""; + } + if(isset($data['extra']['style'])) + { + $table .= " style=\"".$data['extra']['style']."\""; + } + if(isset($data['extra']['width'])) + { + $table .= " width=\"".$data['extra']['width']."\""; + } + if(isset($data['extra']['colspan']) && $data['extra']['colspan'] > 1) + { + $table .= " colspan=\"".$data['extra']['colspan']."\""; + } + $table .= ">".$data['data']."\n"; + } + $table .= "\t\t\n"; + $table .= "\t\n"; + } + $table .= "\t\n"; + $i = 1; + foreach($this->_rows as $key => $table_row) + { + $table .= "\t\t_rows[$key+1])) + { + $table_row['extra']['class'] .= " last"; + } + if($i == 2 && !isset($table_row['extra']['no_alt_row'])) + { + $table_row['extra']['class'] .= " alt_row"; + $i = 0; + } + $i++; + if($table_row['extra']['class']) + { + $table .= " class=\"".trim($table_row['extra']['class'])."\""; + } + $table .= ">\n"; + $table .= $table_row['cells']; + $table .= "\t\t\n"; + } + $table .= "\t\n"; + $table .= "\n"; + // Clean up + $this->_cells = $this->_rows = $this->_headers = array(); + if($border == 1) + { + $table .= "
"; + } + return $table; + } +} diff --git a/Upload/admin/inc/functions.php b/Upload/admin/inc/functions.php new file mode 100644 index 0000000..3915868 --- /dev/null +++ b/Upload/admin/inc/functions.php @@ -0,0 +1,798 @@ + (int)$mybb->user['uid'], + "ipaddress" => $db->escape_binary(my_inet_pton(get_ip())), + "dateline" => TIME_NOW, + "module" => $db->escape_string($mybb->get_input('module')), + "action" => $db->escape_string($mybb->get_input('action')), + "data" => $db->escape_string(@serialize($data)) + ); + + $db->insert_query("adminlog", $log_entry); +} + +/** + * Redirects the current user to a specified URL. + * + * @param string The URL to redirect to + */ +function admin_redirect($url) +{ + if(!headers_sent()) + { + $url = str_replace("&", "&", $url); + header("Location: $url"); + } + else + { + echo ""; + } + exit; +} + +/** + * Updates an administration session data array. + * + * @param string The name of the item in the data session to update + * @param mixed The value + */ +function update_admin_session($name, $value) +{ + global $db, $admin_session; + + $admin_session['data'][$name] = $value; + $updated_session = array( + "data" => $db->escape_string(@serialize($admin_session['data'])) + ); + $db->update_query("adminsessions", $updated_session, "sid='{$admin_session['sid']}'"); +} + +/** + * Saves a "flash message" for the current user to be shown on their next page visit. + * + * @param string The message to show + * @param string The type of message to be shown (success|error) + */ +function flash_message($message, $type='') +{ + $flash = array('message' => $message, 'type' => $type); + update_admin_session('flash_message', $flash); +} + +/** + * Draw pagination for pages in the Admin CP. + * + * @param int The current page we're on + * @param int The number of items per page + * @param int The total number of items in this collection + * @param string The URL for pagination of this collection + * @return string The built pagination + */ +function draw_admin_pagination($page, $per_page, $total_items, $url) +{ + global $mybb, $lang; + + if($total_items <= $per_page) + { + return; + } + + $pages = ceil($total_items / $per_page); + + $pagination = "
{$lang->pages}: \n"; + + if($page > 1) + { + $prev = $page-1; + $prev_page = fetch_page_url($url, $prev); + $pagination .= "« {$lang->previous} \n"; + } + + // Maximum number of "page bits" to show + if(!$mybb->settings['maxmultipagelinks']) + { + $mybb->settings['maxmultipagelinks'] = 5; + } + + $max_links = $mybb->settings['maxmultipagelinks']; + + $from = $page-floor($mybb->settings['maxmultipagelinks']/2); + $to = $page+floor($mybb->settings['maxmultipagelinks']/2); + + if($from <= 0) + { + $from = 1; + $to = $from+$max_links-1; + } + + if($to > $pages) + { + $to = $pages; + $from = $pages-$max_links+1; + if($from <= 0) + { + $from = 1; + } + } + + if($to == 0) + { + $to = $pages; + } + + if($from > 2) + { + $first = fetch_page_url($url, 1); + $pagination .= "page} 1\" class=\"pagination_first\">1 ... "; + } + + for($i = $from; $i <= $to; ++$i) + { + $page_url = fetch_page_url($url, $i); + if($page == $i) + { + $pagination .= "{$i} \n"; + } + else + { + $pagination .= "page} {$i}\">{$i} \n"; + } + } + + if($to < $pages) + { + $last = fetch_page_url($url, $pages); + $pagination .= "... page} {$pages}\" class=\"pagination_last\">{$pages}"; + } + + if($page < $pages) + { + $next = $page+1; + $next_page = fetch_page_url($url, $next); + $pagination .= " {$lang->next} »\n"; + } + $pagination .= "
\n"; + return $pagination; +} + +/** + * Builds a CSV parent list for a particular forum. + * + * @param int The forum ID + * @param string Optional separator - defaults to comma for CSV list + * @return string The built parent list + */ +function make_parent_list($fid, $navsep=",") +{ + global $pforumcache, $db; + + if(!$pforumcache) + { + $query = $db->simple_select("forums", "name, fid, pid", "", array("order_by" => "disporder, pid")); + while($forum = $db->fetch_array($query)) + { + $pforumcache[$forum['fid']][$forum['pid']] = $forum; + } + } + + reset($pforumcache); + reset($pforumcache[$fid]); + + foreach($pforumcache[$fid] as $key => $forum) + { + if($fid == $forum['fid']) + { + if($pforumcache[$forum['pid']]) + { + $navigation = make_parent_list($forum['pid'], $navsep).$navigation; + } + + if($navigation) + { + $navigation .= $navsep; + } + $navigation .= $forum['fid']; + } + } + return $navigation; +} + +function save_quick_perms($fid) +{ + global $db, $inherit, $canview, $canpostthreads, $canpostreplies, $canpostpolls, $canpostattachments, $cache; + + $permission_fields = array(); + + $field_list = $db->show_fields_from("forumpermissions"); + foreach($field_list as $field) + { + if(strpos($field['Field'], 'can') !== false) + { + $permission_fields[$field['Field']] = 1; + } + } + + // "Can Only View Own Threads" and "Can Only Reply Own Threads" permissions are forum permission only options + $usergroup_permission_fields = $permission_fields; + unset($usergroup_permission_fields['canonlyviewownthreads']); + unset($usergroup_permission_fields['canonlyreplyownthreads']); + + $query = $db->simple_select("usergroups", "gid"); + while($usergroup = $db->fetch_array($query)) + { + $query2 = $db->simple_select("forumpermissions", $db->escape_string(implode(',', array_keys($permission_fields))), "fid='{$fid}' AND gid='{$usergroup['gid']}'", array('limit' => 1)); + $existing_permissions = $db->fetch_array($query2); + + if(!$existing_permissions) + { + $query2 = $db->simple_select("usergroups", $db->escape_string(implode(',', array_keys($usergroup_permission_fields))), "gid='{$usergroup['gid']}'", array('limit' => 1)); + $existing_permissions = $db->fetch_array($query2); + } + + // Delete existing permissions + $db->delete_query("forumpermissions", "fid='{$fid}' AND gid='{$usergroup['gid']}'"); + + // Only insert the new ones if we're using custom permissions + if($inherit[$usergroup['gid']] != 1) + { + if($canview[$usergroup['gid']] == 1) + { + $pview = 1; + } + else + { + $pview = 0; + } + + if($canpostthreads[$usergroup['gid']] == 1) + { + $pthreads = 1; + } + else + { + $pthreads = 0; + } + + if($canpostreplies[$usergroup['gid']] == 1) + { + $preplies = 1; + } + else + { + $preplies = 0; + } + + if($canpostpolls[$usergroup['gid']] == 1) + { + $ppolls = 1; + } + else + { + $ppolls = 0; + } + + if(!$preplies && !$pthreads) + { + $ppost = 0; + } + else + { + $ppost = 1; + } + + $insertquery = array( + "fid" => (int)$fid, + "gid" => (int)$usergroup['gid'], + "canview" => (int)$pview, + "canpostthreads" => (int)$pthreads, + "canpostreplys" => (int)$preplies, + "canpostpolls" => (int)$ppolls, + ); + + foreach($permission_fields as $field => $value) + { + if(array_key_exists($field, $insertquery)) + { + continue; + } + + $insertquery[$db->escape_string($field)] = (int)$existing_permissions[$field]; + } + + $db->insert_query("forumpermissions", $insertquery); + } + } + $cache->update_forumpermissions(); +} + +/** + * Checks if a particular user has the necessary permissions to access a particular page. + * + * @param array Array containing module and action to check for + */ +function check_admin_permissions($action, $error = true) +{ + global $mybb, $page, $lang, $modules_dir; + + if(is_super_admin($mybb->user['uid'])) + { + return true; + } + + require_once $modules_dir."/".$action['module']."/module_meta.php"; + if(function_exists($action['module']."_admin_permissions")) + { + $func = $action['module']."_admin_permissions"; + $permissions = $func(); + if($permissions['permissions'][$action['action']] && $mybb->admin['permissions'][$action['module']][$action['action']] != 1) + { + if($error) + { + $page->output_header($lang->access_denied); + $page->add_breadcrumb_item($lang->access_denied, "index.php?module=home-index"); + $page->output_error("{$lang->access_denied}
  • {$lang->access_denied_desc}
"); + $page->output_footer(); + exit; + } + else + { + return false; + } + } + } + + return true; +} + +/** + * Fetches the list of administrator permissions for a particular user or group + * + * @param int The user ID to fetch permissions for + * @param int The (optional) group ID to fetch permissions for + * @return array Array of permissions for specified user or group + */ +function get_admin_permissions($get_uid="", $get_gid="") +{ + global $db, $mybb; + + // Set UID and GID if none + $uid = $get_uid; + $gid = $get_gid; + + $gid_array = array(); + + if($uid === "") + { + $uid = $mybb->user['uid']; + } + + if(!$gid) + { + // Prepare user's groups since the group isn't specified + $gid_array[] = (-1) * (int)$mybb->user['usergroup']; + + if($mybb->user['additionalgroups']) + { + $additional_groups = explode(',', $mybb->user['additionalgroups']); + + if(!empty($additional_groups)) + { + // Make sure gids are negative + foreach($additional_groups as $g) + { + $gid_array[] = (-1) * abs($g); + } + } + } + } + else + { + // Group is specified + // Make sure gid is negative + $gid_array[] = (-1) * abs($gid); + } + + // What are we trying to find? + if($get_gid && !$get_uid) + { + // A group only + + $options = array( + "order_by" => "uid", + "order_dir" => "ASC", + "limit" => "1" + ); + $query = $db->simple_select("adminoptions", "permissions", "(uid='-{$get_gid}' OR uid='0') AND permissions != ''", $options); + return my_unserialize($db->fetch_field($query, "permissions")); + } + else + { + // A user and/or group + + $options = array( + "order_by" => "uid", + "order_dir" => "DESC" + ); + + // Prepare user's groups into SQL format + $group_sql = ''; + foreach($gid_array as $gid) + { + $group_sql .= " OR uid='{$gid}'"; + } + + $perms_group = array(); + $query = $db->simple_select("adminoptions", "permissions, uid", "(uid='{$uid}'{$group_sql}) AND permissions != ''", $options); + while($perm = $db->fetch_array($query)) + { + $perm['permissions'] = my_unserialize($perm['permissions']); + + // Sorting out which permission is which + if($perm['uid'] > 0) + { + $perms_user = $perm; + return $perms_user['permissions']; + } + elseif($perm['uid'] < 0) + { + $perms_group[] = $perm['permissions']; + } + else + { + $perms_def = $perm['permissions']; + } + } + + // Figure out group permissions...ugh. + foreach($perms_group as $gperms) + { + if(!isset($final_group_perms)) + { + // Use this group as the base for admin group permissions + $final_group_perms = $gperms; + continue; + } + + // Loop through each specific permission to find the highest permission + foreach($gperms as $perm_name => $perm_value) + { + if($final_group_perms[$perm_name] != '1' && $perm_value == '1') + { + $final_group_perms[$perm_name] = '1'; + } + } + } + + // Send specific user, or group permissions before default. + // If user's permission are explicitly set, they've already been returned above. + if(isset($final_group_perms)) + { + return $final_group_perms; + } + else + { + return $perms_def; + } + } +} + +/** + * Fetch the iconv/mb encoding for a particular MySQL encoding + * + * @param string The MySQL encoding + * @return string The iconv/mb encoding + */ +function fetch_iconv_encoding($mysql_encoding) +{ + $mysql_encoding = explode("_", $mysql_encoding); + switch($mysql_encoding[0]) + { + case "utf8": + return "utf-8"; + break; + case "latin1": + return "iso-8859-1"; + break; + default: + return $mysql_encoding[0]; + } +} + +/** + * Adds/Updates a Page/Tab to the permissions array in the adminoptions table + * + * @param string The name of the tab that is being affected + * @param string The name of the page being affected (optional - if not specified, will affect everything under the specified tab) + * @param integer Default permissions for the page (1 for allowed - 0 for disallowed - -1 to remove) + */ +function change_admin_permission($tab, $page="", $default=1) +{ + global $db; + + $query = $db->simple_select("adminoptions", "uid, permissions", "permissions != ''"); + while($adminoption = $db->fetch_array($query)) + { + $adminoption['permissions'] = my_unserialize($adminoption['permissions']); + + if($default == -1) + { + if(!empty($page)) + { + unset($adminoption['permissions'][$tab][$page]); + } + else + { + unset($adminoption['permissions'][$tab]); + } + } + else + { + if(!empty($page)) + { + if($adminoption['uid'] == 0) + { + $adminoption['permissions'][$tab][$page] = 0; + } + else + { + $adminoption['permissions'][$tab][$page] = $default; + } + } + else + { + if($adminoption['uid'] == 0) + { + $adminoption['permissions'][$tab]['tab'] = 0; + } + else + { + $adminoption['permissions'][$tab]['tab'] = $default; + } + } + } + + $db->update_query("adminoptions", array('permissions' => $db->escape_string(serialize($adminoption['permissions']))), "uid='{$adminoption['uid']}'"); + } +} + +/** + * Checks if we have had too many attempts at logging into the ACP + * + * @param integer The uid of the admin to check + * @param boolean Return an array of the number of attempts and expiry time? (default false) + * @return mixed Return an array if the second parameter is true, boolean otherwise. + */ +function login_attempt_check_acp($uid=0, $return_num=false) +{ + global $db, $mybb; + + $attempts['loginattempts'] = 0; + + if($uid > 0) + { + $query = $db->simple_select("adminoptions", "loginattempts, loginlockoutexpiry", "uid='".(int)$uid."'", 1); + $attempts = $db->fetch_array($query); + } + + if($attempts['loginattempts'] <= 0) + { + return false; + } + + if($mybb->settings['maxloginattempts'] > 0 && $attempts['loginattempts'] >= $mybb->settings['maxloginattempts']) + { + // Has the expiry dateline been set yet? + if($attempts['loginlockoutexpiry'] == 0 && $return_num == false) + { + $db->update_query("adminoptions", array("loginlockoutexpiry" => TIME_NOW+((int)$mybb->settings['loginattemptstimeout']*60)), "uid='".(int)$uid."'"); + } + + // Are we returning the # of login attempts? + if($return_num == true) + { + return $attempts; + } + // Otherwise are we still locked out? + else if($attempts['loginlockoutexpiry'] > TIME_NOW) + { + return true; + } + } + + return false; +} + +/** + * Checks whether the administrator is on a mobile device + * + * @param string The useragent to be checked + * @return boolean A true/false depending on if the administrator is on a mobile + */ +function is_mobile($useragent) +{ + return preg_match("/(android|avantgo|blackberry|bolt|boost|cricket|docomo|fone|hiptop|mini|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)/i", $useragent); +} + +/** + * Checks whether there are any 'security' issues in templates via complex syntax + * + * @param string The template to be scanned + * @return boolean A true/false depending on if an issue was detected + */ +function check_template($template) +{ + // Check to see if our database password is in the template + if(preg_match("#database'?\\s*\]\\s*\[\\s*'?password#", $template)) + { + return true; + } + + // System calls via backtick + if(preg_match('#\$\s*\{#', $template)) + { + return true; + } + + // Any other malicious acts? + // Courtesy of ZiNgA BuRgA + if(preg_match("~\\{\\$.+?\\}~s", preg_replace('~\\{\\$+[a-zA-Z_][a-zA-Z_0-9]*((?:-\\>|\\:\\:)\\$*[a-zA-Z_][a-zA-Z_0-9]*|\\[\s*\\$*([\'"]?)[a-zA-Z_ 0-9 ]+\\2\\]\s*)*\\}~', '', $template))) + { + return true; + } + + return false; +} + +/** + * Provides a function to entirely delete a user's posts, and find the threads attached to them + * + * @param integer The uid of the user + * @param int A UNIX timestamp to delete posts that are older + * @return array An array of threads to delete, threads/forums to recount + */ +function delete_user_posts($uid, $date) +{ + global $db; + $uid = (int)$uid; + + // Build an array of posts to delete + $postcache = array(); + $query = $db->simple_select("posts", "pid", "uid = '".$uid."' AND dateline < '".$date."'"); + while($post = $db->fetch_array($query)) + { + $postcache[] = $post['pid']; + } + + if(!$db->num_rows($query)) + { + return false; + } + elseif(!empty($postcache)) + { + // Let's start deleting posts + $user_posts = implode(",", $postcache); + $query = $db->query(" + SELECT p.pid, p.visible, f.usepostcounts, t.tid AS thread, t.firstpost, t.fid AS forum + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid) + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + WHERE p.pid IN ({$user_posts}) + "); + + $post_count = 0; // Collect the post number to deduct from the user's postcount + $thread_list = array(); + $forum_list = array(); + $delete_thread_list = array(); + if(!$db->num_rows($query)) + { + return false; + } + else + { + while($post = $db->fetch_array($query)) + { + if($post['usepostcounts'] != 0 && $post['visible'] != 0) + { + ++$post_count; + } + + if($post['pid'] == $post['firstpost']) + { + $delete_thread_list[] = $post['thread']; + } + + if(!in_array($post['thread'], $thread_list) && !in_array($post['thread'], $delete_thread_list)) + { + $thread_list[] = $post['thread']; // Threads that have been affected by this action, that aren't marked to be deleted + } + if(!in_array($post['forum'], $forum_list)) + { + $forum_list[] = $post['forum']; // Forums that have been affected, too + } + + // Remove the attachments to this post, then delete the post + remove_attachments($post['pid']); + $db->delete_query("posts", "pid = '".$post['pid']."'"); + $db->delete_query("pollvotes", "pid = '".$post['pid']."'"); // Delete pollvotes attached to this post + } + + $db->update_query("users", array("postnum" => "postnum-".$post_count.""), "uid='".$uid."'", 1, true); + + $to_return = array( + 'to_delete' => $delete_thread_list, + 'thread_update' => $thread_list, + 'forum_update' => $forum_list + ); + + return $to_return; + } + } +} + +/** + * Prints a selection JavaScript code for selectable groups/forums fields. + */ +function print_selection_javascript() +{ + static $already_printed = false; + + if($already_printed) + { + return; + } + + $already_printed = true; + + echo ""; +} diff --git a/Upload/admin/inc/functions_themes.php b/Upload/admin/inc/functions_themes.php new file mode 100644 index 0000000..677db4b --- /dev/null +++ b/Upload/admin/inc/functions_themes.php @@ -0,0 +1,1535 @@ +get_tree(); + + if(!is_array($tree) || !is_array($tree['theme'])) + { + return -1; + } + + $theme = $tree['theme']; + + // Do we have MyBB 1.2 template's we're importing? + $css_120 = ""; + + if(isset($theme['cssbits']) && is_array($theme['cssbits'])) + { + $cssbits = kill_tags($theme['cssbits']); + + foreach($cssbits as $name => $values) + { + $css_120 .= "{$name} {\n"; + foreach($values as $property => $value) + { + if(is_array($value)) + { + $property = str_replace('_', ':', $property); + + $css_120 .= "}\n{$name} {$property} {\n"; + foreach($value as $property2 => $value2) + { + $css_120 .= "\t{$property2}: {$value2}\n"; + } + } + else + { + $css_120 .= "\t{$property}: {$value}\n"; + } + } + $css_120 .= "}\n"; + } + } + + if(isset($theme['themebits']) && is_array($theme['themebits'])) + { + $themebits = kill_tags($theme['themebits']); + + $theme['properties']['tag'] = 'properties'; + + foreach($themebits as $name => $value) + { + if($name == "extracss") + { + $css_120 .= $value; + continue; + } + + $theme['properties'][$name] = $value; + } + } + + if($css_120) + { + $css_120 = upgrade_css_120_to_140($css_120); + $theme['stylesheets']['tag'] = 'stylesheets'; + $theme['stylesheets']['stylesheet'][0]['tag'] = 'stylesheet'; + $theme['stylesheets']['stylesheet'][0]['attributes'] = array('name' => 'global.css', 'version' => $mybb->version_code); + $theme['stylesheets']['stylesheet'][0]['value'] = $css_120; + + unset($theme['cssbits']); + unset($theme['themebits']); + } + + if(is_array($theme['properties'])) + { + foreach($theme['properties'] as $property => $value) + { + if($property == "tag" || $property == "value") + { + continue; + } + + if($property == 'colors' || $property == 'disporder') + { + $data = my_unserialize($value['value']); + + if(!is_array($data)) + { + // Bad data? + continue; + } + + $value['value'] = $data; + } + + $properties[$property] = $value['value']; + } + } + + if(empty($mybb->input['name'])) + { + $name = $theme['attributes']['name']; + } + else + { + $name = $mybb->input['name']; + } + $version = $theme['attributes']['version']; + + $query = $db->simple_select("themes", "tid", "name='".$db->escape_string($name)."'", array("limit" => 1)); + $existingtheme = $db->fetch_array($query); + if(!empty($options['force_name_check']) && $existingtheme['tid']) + { + return -3; + } + else if($existingtheme['tid']) + { + $options['tid'] = $existingtheme['tid']; + } + + if($mybb->version_code != $version && $options['version_compat'] != 1) + { + return -2; + } + + // Do we have any templates to insert? + if(!empty($theme['templates']['template']) && empty($options['no_templates'])) + { + if($options['templateset']) + { + $sid = $options['templateset']; + } + else + { + $sid = $db->insert_query("templatesets", array('title' => $db->escape_string($name)." Templates")); + } + + $templates = $theme['templates']['template']; + if(is_array($templates)) + { + // Theme only has one custom template + if(array_key_exists("attributes", $templates)) + { + $templates = array($templates); + } + } + + $security_check = false; + $templatecache = array(); + foreach($templates as $template) + { + if(check_template($template['value'])) + { + $security_check = true; + break; + } + + $templatecache[] = array( + "title" => $db->escape_string($template['attributes']['name']), + "template" => $db->escape_string($template['value']), + "sid" => $db->escape_string($sid), + "version" => $db->escape_string($template['attributes']['version']), + "dateline" => TIME_NOW + ); + } + + if($security_check == true) + { + return -4; + } + + foreach($templatecache as $template) + { + // PostgreSQL causes apache to stop sending content sometimes and + // causes the page to stop loading during many queries all at one time + if($db->engine == "pgsql") + { + echo " "; + flush(); + } + + $db->insert_query("templates", $template); + } + + $properties['templateset'] = $sid; + } + + // Not overriding an existing theme + if(empty($options['tid'])) + { + // Insert the theme + if(!isset($options['parent'])) + { + $options['parent'] = 0; + } + $theme_id = build_new_theme($name, $properties, $options['parent']); + } + // Overriding an existing - delete refs. + else + { + $db->delete_query("themestylesheets", "tid='{$options['tid']}'"); + $db->update_query("themes", array("properties" => $db->escape_string(serialize($properties))), "tid='{$options['tid']}'"); + $theme_id = $options['tid']; + } + + // If we have any stylesheets, process them + if(!empty($theme['stylesheets']['stylesheet']) && empty($options['no_stylesheets'])) + { + // Are we dealing with a single stylesheet? + if(isset($theme['stylesheets']['stylesheet']['tag'])) + { + // Trick the system into thinking we have a good array =P + $theme['stylesheets']['stylesheet'] = array($theme['stylesheets']['stylesheet']); + } + + // Retrieve a list of inherited stylesheets + $query = $db->simple_select("themes", "stylesheets", "tid = '{$theme_id}'"); + if($db->num_rows($query)) + { + $inherited_stylesheets = my_unserialize($db->fetch_field($query, "stylesheets")); + + if(is_array($inherited_stylesheets['inherited'])) + { + $loop = 1; + foreach($inherited_stylesheets['inherited'] as $action => $stylesheets) + { + foreach($stylesheets as $filename => $stylesheet) + { + if($properties['disporder'][basename($filename)]) + { + continue; + } + + $properties['disporder'][basename($filename)] = $loop; + ++$loop; + } + } + } + } + + $loop = 1; + foreach($theme['stylesheets']['stylesheet'] as $stylesheet) + { + if(substr($stylesheet['attributes']['name'], -4) != ".css") + { + continue; + } + + if(empty($stylesheet['attributes']['lastmodified'])) + { + $stylesheet['attributes']['lastmodified'] = TIME_NOW; + } + + if(empty($stylesheet['attributes']['disporder'])) + { + $stylesheet['attributes']['disporder'] = $loop; + } + + if(empty($stylesheet['attributes']['attachedto'])) + { + $stylesheet['attributes']['attachedto'] = ''; + } + + $properties['disporder'][$stylesheet['attributes']['name']] = $stylesheet['attributes']['disporder']; + + $new_stylesheet = array( + "name" => $db->escape_string($stylesheet['attributes']['name']), + "tid" => $theme_id, + "attachedto" => $db->escape_string($stylesheet['attributes']['attachedto']), + "stylesheet" => $db->escape_string($stylesheet['value']), + "lastmodified" => (int)$stylesheet['attributes']['lastmodified'], + "cachefile" => $db->escape_string($stylesheet['attributes']['name']) + ); + $sid = $db->insert_query("themestylesheets", $new_stylesheet); + $css_url = "css.php?stylesheet={$sid}"; + $cached = cache_stylesheet($theme_id, $stylesheet['attributes']['name'], $stylesheet['value']); + if($cached) + { + $css_url = $cached; + } + + $attachedto = $stylesheet['attributes']['attachedto']; + if(!$attachedto) + { + $attachedto = "global"; + } + + // private.php?compose,folders|usercp.php,global|global + $attachedto = explode("|", $attachedto); + foreach($attachedto as $attached_file) + { + $attached_actions = explode(",", $attached_file); + $attached_file = array_shift($attached_actions); + if(count($attached_actions) == 0) + { + $attached_actions = array("global"); + } + + foreach($attached_actions as $action) + { + $theme_stylesheets[$attached_file][$action][] = $css_url; + } + } + + ++$loop; + } + // Now we have our list of built stylesheets, save them + $updated_theme = array( + "stylesheets" => $db->escape_string(serialize($theme_stylesheets)) + ); + + if(is_array($properties['disporder'])) + { + asort($properties['disporder'], SORT_NUMERIC); + + // Because inherited stylesheets can mess this up + $loop = 1; + $orders = array(); + foreach($properties['disporder'] as $filename => $order) + { + $orders[$filename] = $loop; + ++$loop; + } + + $properties['disporder'] = $orders; + $updated_theme['properties'] = $db->escape_string(serialize($properties)); + } + + $db->update_query("themes", $updated_theme, "tid='{$theme_id}'"); + } + + update_theme_stylesheet_list($theme_id); + + // And done? + return $theme_id; +} + +/** + * Parse theme variables in a specific string. + * + * @param string $string The string to parse variables for + * @param array $variables Array of variables + * @return string Parsed string with variables replaced + */ +function parse_theme_variables($string, $variables=array()) +{ + $find = array(); + $replace = array(); + foreach(array_keys($variables) as $variable) + { + $find[] = "{{$variable}}"; + $replace[] = $variables[$variable]; + } + return str_replace($find, $replace, $string); +} + +/** + * Caches a stylesheet to the file system. + * + * @param string $tid The theme ID this stylesheet belongs to. + * @param string $filename The name of the stylesheet. + * @param string $stylesheet The contents of the stylesheet. + * + * @return string The cache file path. + */ +function cache_stylesheet($tid, $filename, $stylesheet) +{ + global $mybb; + + $filename = str_replace('/', '', $filename); + $tid = (int) $tid; + $theme_directory = "cache/themes/theme{$tid}"; + + // If we're in safe mode save to the main theme folder by default + if($mybb->safemode) + { + $theme_directory = "cache/themes"; + $filename = $tid."_".$filename; + } + // Does our theme directory exist? Try and create it. + elseif(!is_dir(MYBB_ROOT . $theme_directory)) + { + if(!@mkdir(MYBB_ROOT . $theme_directory)) + { + $theme_directory = "cache/themes"; + $filename = $tid."_".$filename; + } + else + { + // Add in empty index.html! + $fp = @fopen(MYBB_ROOT . $theme_directory."/index.html", "w"); + @fwrite($fp, ""); + @fclose($fp); + + } + } + + $theme_vars = array( + "theme" => $theme_directory + ); + $stylesheet = parse_theme_variables($stylesheet, $theme_vars); + $stylesheet = preg_replace_callback("#url\((\"|'|)(.*)\\1\)#", create_function('$matches', 'return fix_css_urls($matches[2]);'), $stylesheet); + + $fp = @fopen(MYBB_ROOT . "{$theme_directory}/{$filename}", "wb"); + if(!$fp) + { + return false; + } + + @fwrite($fp, $stylesheet); + @fclose($fp); + + $stylesheet_min = minify_stylesheet($stylesheet); + $filename_min = str_replace('.css', '.min.css', $filename); + $fp_min = @fopen(MYBB_ROOT . "{$theme_directory}/{$filename_min}", "wb"); + if(!$fp_min) + { + return false; + } + @fwrite($fp_min, $stylesheet_min); + @fclose($fp_min); + + if($mybb->settings['usecdn'] && !empty($mybb->settings['cdnpath'])) + { + $cdn_path = rtrim($mybb->settings['cdnpath'], '/\\'); + $cache_themes_dir = $cdn_path . '/' . $theme_directory; + + $copy_to_cdn = true; + + if(!is_dir($cache_themes_dir)) + { + if(!@mkdir($cache_themes_dir)) + { + $copy_to_cdn = false; + } + } + + if($copy_to_cdn) + { + @copy(MYBB_ROOT . "{$theme_directory}/{$filename}", "{$cache_themes_dir}/{$filename}"); + @copy(MYBB_ROOT . "{$theme_directory}/{$filename_min}", "{$cache_themes_dir}/{$filename_min}"); + } + } + + return "{$theme_directory}/{$filename}"; +} + +/** + * Minify a stylesheet to remove comments, linebreaks, whitespace, + * unnecessary semicolons, and prefers #rgb over #rrggbb. + * + * @param $stylesheet string The stylesheet in it's untouched form. + * @return string The minified stylesheet + */ +function minify_stylesheet($stylesheet) +{ + // Remove comments. + $stylesheet = preg_replace('@/\*.*?\*/@s', '', $stylesheet); + // Remove whitespace around symbols. + $stylesheet = preg_replace('@\s*([{}:;,])\s*@', '\1', $stylesheet); + // Remove unnecessary semicolons. + $stylesheet = preg_replace('@;}@', '}', $stylesheet); + // Replace #rrggbb with #rgb when possible. + $stylesheet = preg_replace('@#([a-f0-9])\1([a-f0-9])\2([a-f0-9])\3@i','#\1\2\3',$stylesheet); + $stylesheet = trim($stylesheet); + return $stylesheet; +} + +function resync_stylesheet($stylesheet) +{ + global $db; + + // Try and fix any missing cache file names + if(!$stylesheet['cachefile'] && $stylesheet['name']) + { + $stylesheet['cachefile'] = $stylesheet['name']; + $db->update_query("themestylesheets", array('cachefile' => $db->escape_string($stylesheet['name'])), "sid='{$stylesheet['sid']}'"); + } + + // Still don't have the cache file name or is it not a flat file? Return false + if(!$stylesheet['cachefile'] || strpos($stylesheet['cachefile'], 'css.php') !== false) + { + return false; + } + + if(!file_exists(MYBB_ROOT."cache/themes/theme{$stylesheet['tid']}/{$stylesheet['name']}") && !file_exists(MYBB_ROOT."cache/themes/{$stylesheet['tid']}_{$stylesheet['name']}")) + { + if(cache_stylesheet($stylesheet['tid'], $stylesheet['cachefile'], $stylesheet['stylesheet']) !== false) + { + $db->update_query("themestylesheets", array('cachefile' => $db->escape_string($stylesheet['name'])), "sid='{$stylesheet['sid']}'"); + + update_theme_stylesheet_list($stylesheet['tid']); + + if($stylesheet['sid'] != 1) + { + $db->update_query("themestylesheets", array('lastmodified' => TIME_NOW), "sid='{$stylesheet['sid']}'"); + } + } + + return true; + } + + return false; +} + +function fix_css_urls($url) +{ + if(!preg_match("#^([a-z0-9]+\:|/)#i", $url) && strpos($url, "../../../") === false) + { + return "url(../../../{$url})"; + } + else + { + return "url({$url})"; + } +} + +function unfix_css_urls($url) +{ + return str_replace("../../../", "", $url); +} + +/** + * Build a theme based on the specified parameters. + * + * @param string $name The name of the theme + * @param array $properties Array of theme properties (if blank, inherits from parent) + * @param int $parent The parent ID for this theme (defaults to Master) + * @return int The new theme ID + */ +function build_new_theme($name, $properties=null, $parent=1) +{ + global $db; + + $new_theme = array( + "name" => $db->escape_string($name), + "pid" => (int)$parent, + "def" => 0, + "allowedgroups" => "all", + "properties" => "", + "stylesheets" => "" + ); + $tid = $db->insert_query("themes", $new_theme); + + $inherited_properties = false; + $stylesheets = array(); + if($parent > 0) + { + $query = $db->simple_select("themes", "*", "tid='".(int)$parent."'"); + $parent_theme = $db->fetch_array($query); + if(count($properties) == 0 || !is_array($properties)) + { + $parent_properties = my_unserialize($parent_theme['properties']); + if(!empty($parent_properties)) + { + foreach($parent_properties as $property => $value) + { + if($property == "inherited") + { + continue; + } + + $properties[$property] = $value; + if(!empty($parent_properties['inherited'][$property])) + { + $properties['inherited'][$property] = $parent_properties['inherited'][$property]; + } + else + { + $properties['inherited'][$property] = $parent; + } + } + $inherited_properties = true; + } + } + + $parent_stylesheets = my_unserialize($parent_theme['stylesheets']); + if(!empty($parent_stylesheets)) + { + foreach($parent_stylesheets as $location => $value) + { + if($location == "inherited") + { + continue; + } + + foreach($value as $action => $sheets) + { + foreach($sheets as $stylesheet) + { + $stylesheets[$location][$action][] = $stylesheet; + $inherited_check = "{$location}_{$action}"; + if(!empty($parent_stylesheets['inherited'][$inherited_check][$stylesheet])) + { + $stylesheets['inherited'][$inherited_check][$stylesheet] = $parent_stylesheets['inherited'][$inherited_check][$stylesheet]; + } + else + { + $stylesheets['inherited'][$inherited_check][$stylesheet] = $parent; + } + } + } + } + } + } + + if(!$inherited_properties) + { + $theme_vars = array( + "theme" => "cache/themes/theme{$tid}" + ); + $properties['logo'] = parse_theme_variables($properties['logo'], $theme_vars); + } + if(!empty($stylesheets)) + { + $updated_theme['stylesheets'] = $db->escape_string(serialize($stylesheets)); + } + $updated_theme['properties'] = $db->escape_string(serialize($properties)); + + if(count($updated_theme) > 0) + { + $db->update_query("themes", $updated_theme, "tid='{$tid}'"); + } + + return $tid; +} + +/** + * Generates an array from an incoming CSS file. + * + * @param string $css The incoming CSS + * @return array Parsed CSS file as array, false on failure + */ +function css_to_array($css) +{ + // Normalise line breaks + $css = str_replace(array("\r\n", "\n", "\r"), "\n", $css); + + /** + * Play with the css a little - just to ensure we can parse it + * + * This essentially adds line breaks before and after each } not inside a string + * so it's parsed correctly below + */ + $stripped_css = preg_replace('#(?\*\.\#\,\s\(\)\|~|@\^]+)(\s*)\{(.*?)\}\n#msi', $stripped_css, $matches, PREG_PATTERN_ORDER); + $total = count($matches[1]); + + $parsed_css = array(); + + for($i=0; $i < $total; $i++) + { + $name = $description = ''; + $class_name = $matches[3][$i]; + $class_name = trim($class_name); + $comments = $matches[1][$i]; + preg_match_all("#Name:(.*)#i", $comments, $name_match); + if(isset($name_match[count($name_match)-1][0])) + { + $name = trim($name_match[count($name_match)-1][0]); + } + preg_match_all("#Description:(.*)#i", $comments, $description_match); + if(isset($description_match[count($description_match)-1][0])) + { + $description = trim($description_match[count($description_match)-1][0]); + } + $class_id = md5($class_name); + if(isset($already_parsed[$class_id])) + { + $already_parsed[$class_id]++; + $class_id .= "_".$already_parsed[$class_id]; + } + else + { + $already_parsed[$class_id] = 1; + } + $values = trim($matches[5][$i]); + $values = preg_replace("#/\*(.*?)\*/#s", "", $values); + $parsed_css[$class_id] = array("class_name" => $class_name, "name" => $name, "description" => $description, "values" => $values); + } + + return $parsed_css; +} + +function get_selectors_as_options($css, $selected_item="") +{ + $select = ""; + + if(!is_array($css)) + { + $css = css_to_array($css); + } + + $selected = false; + + if(is_array($css)) + { + uasort($css, "css_selectors_sort_cmp"); + + foreach($css as $id => $css_array) + { + if(!$css_array['name']) + { + $css_array['name'] = $css_array['class_name']; + } + + if($selected_item == $id || (!$selected_item && !$selected)) + { + $select .= "\n"; + $selected = true; + } + else + { + $select .= "\n"; + } + } + } + return $select; +} + +function css_selectors_sort_cmp($a, $b) +{ + if(!$a['name']) + { + $a['name'] = $a['class_name']; + } + + if(!$b['name']) + { + $b['name'] = $b['class_name']; + } + return strcmp($a['name'], $b['name']); +} + +function get_css_properties($css, $id) +{ + if(!is_array($css)) + { + $css = css_to_array($css); + } + + if(!isset($css[$id])) + { + return false; + } + return parse_css_properties($css[$id]['values']); +} + +/** + * Parses CSS supported properties and returns them as an array. + * + * @param string $values Value of CSS properties from within class or selector + * @return array Array of CSS properties + */ +function parse_css_properties($values) +{ + $css_bits = array(); + + if(!$values) + { + return null; + } + + $values = explode(";", $values); + foreach($values as $value) + { + $value = trim($value); + if(!$value) continue; + list($property, $css_value) = explode(":", $value, 2); + $property = trim($property); + switch(strtolower($property)) + { + case "background": + case "color": + case "width": + case "font-family": + case "font-size": + case "font-weight": + case "font-style": + case "text-decoration": + $css_bits[$property] = trim($css_value); + break; + default: + $css_bits['extra'] .= "{$property}: ".trim($css_value).";\n"; + + } + } + return $css_bits; +} + +/** + * Inserts an incoming string of CSS in to an already defined document. If the class ID is not found, the CSS is appended to the file. + * + * @param string $new_css CSS we wish to insert at this location. + * @param string $selector The selector for this piece of CSS. + * @param string $css The existing CSS if we have any. + * @param string $class_id (Optional) The optional friendly class id value just incase the CSS is not found in the file. + * + * @return string The altered CSS. + */ +function insert_into_css($new_css, $selector="", $css="", $class_id="") +{ + $new_css = str_replace(array("\r\n", "\n", "\r"), "\n", $new_css); + + $generated_css = ''; + + // Build the new CSS properties list + $new_css = explode("\n", $new_css); + foreach($new_css as $css_line) + { + $generated_css .= "\t".trim($css_line)."\n"; + } + + $parsed_css = array(); + + // Parse out the CSS + if($css) + { + $parsed_css = css_to_array($css); + } + + if(!$class_id) + { + $class_id = $parsed_css[$selector]['class_name']; + } + + // The specified class ID cannot be found, add CSS to end of file + if(!$css || !$parsed_css[$selector]) + { + return $css."{$class_id}\n{\n{$generated_css}\n}\n\n"; + } + // Valid CSS, swap out old, swap in new + else + { + $css = str_replace(array("\r\n", "\n", "\r"), "\n", $css); + $css = preg_replace('#(?\*\.\#\,\s\(\)\|~\^]+)(\s*)\{(\n*)#isu", "\n$1 {\n", $css); + $css = preg_replace("#\s{1,}\{#", " {", $css); + $existing_block = $parsed_css[$selector]; + + $break = strrpos($selector, "_"); + $actual_occurance = 0; + if($break !== false) + { + $actual_occurance = (int)substr($selector, ($break+1)); + } + + if(!$actual_occurance) + { + $actual_occurance = 1; + } + + $occurance = 1; + $pos = 0; + do + { + $pos = strpos($css, "\n".$existing_block['class_name']." {", $pos); + if($pos === false) + { + break; + } + if($occurance == $actual_occurance) + { + // This is the part we want to replace, now we need to fetch the opening & closing braces + $opening = strpos($css, "{", $pos); + $closing = strpos($css, "}", $pos); + $css = substr_replace($css, "\n".$generated_css."\n", $opening+1, $closing-$opening-1); + break; + } + ++$occurance; + ++$pos; + } while($occurance <= $actual_occurance); + } + $css = preg_replace("#{\n*#s", "{\n", $css); + $css = preg_replace("#\s*\}\s*#", "\n}\n\n", $css); + return $css; +} + +function copy_stylesheet_to_theme($stylesheet, $tid) +{ + global $db; + + $stylesheet['tid'] = $tid; + unset($stylesheet['sid']); + + $new_stylesheet = array(); + foreach($stylesheet as $key => $value) + { + if(!is_numeric($key)) + { + $new_stylesheet[$db->escape_string($key)] = $db->escape_string($value); + } + } + + $sid = $db->insert_query("themestylesheets", $new_stylesheet); + + return $sid; +} + +function update_theme_stylesheet_list($tid, $theme = false, $update_disporders = true) +{ + global $db, $cache; + + $stylesheets = array(); + + $child_list = make_child_theme_list($tid); + $parent_list = make_parent_theme_list($tid); + + if(!is_array($parent_list)) + { + return false; + } + + $tid_list = implode(',', $parent_list); + + // Get our list of stylesheets + $query = $db->simple_select("themestylesheets", "*", "tid IN ({$tid_list})", array('order_by' => 'tid', 'order_dir' => 'desc')); + while($stylesheet = $db->fetch_array($query)) + { + if(empty($stylesheets[$stylesheet['name']])) + { + if($stylesheet['tid'] != $tid) + { + $stylesheet['inherited'] = $stylesheet['tid']; + } + + $stylesheets[$stylesheet['name']] = $stylesheet; + } + } + + $theme_stylesheets = array(); + + foreach($stylesheets as $name => $stylesheet) + { + $sid = $stylesheet['sid']; + $css_url = "css.php?stylesheet={$sid}"; + + foreach($parent_list as $theme_id) + { + if($mybb->settings['usecdn'] && !empty($mybb->settings['cdnpath'])) + { + $cdnpath = rtrim($mybb->settings['cdnpath'], '/\\').'/'; + if(file_exists($cdnpath."cache/themes/theme{$theme_id}/{$stylesheet['name']}") && filemtime( + $cdnpath."cache/themes/theme{$theme_id}/{$stylesheet['name']}" + ) >= $stylesheet['lastmodified'] + ) + { + $css_url = "cache/themes/theme{$theme_id}/{$stylesheet['name']}"; + break; + } + } + else + { + if(file_exists(MYBB_ROOT."cache/themes/theme{$theme_id}/{$stylesheet['name']}") && filemtime( + MYBB_ROOT."cache/themes/theme{$theme_id}/{$stylesheet['name']}" + ) >= $stylesheet['lastmodified'] + ) + { + $css_url = "cache/themes/theme{$theme_id}/{$stylesheet['name']}"; + break; + } + } + } + + $attachedto = $stylesheet['attachedto']; + if(!$attachedto) + { + $attachedto = "global"; + } + // private.php?compose,folders|usercp.php,global|global + $attachedto = explode("|", $attachedto); + foreach($attachedto as $attached_file) + { + $attached_actions = array(); + if(strpos($attached_file, '?') !== false) + { + $attached_file = explode('?', $attached_file); + $attached_actions = explode(",", $attached_file[1]); + $attached_file = $attached_file[0]; + } + + if(count($attached_actions) == 0) + { + $attached_actions = array("global"); + } + + foreach($attached_actions as $action) + { + $theme_stylesheets[$attached_file][$action][] = $css_url; + + if(!empty($stylesheet['inherited'])) + { + $theme_stylesheets['inherited']["{$attached_file}_{$action}"][$css_url] = $stylesheet['inherited']; + } + } + } + } + + // Now we have our list of built stylesheets, save them + $updated_theme = array( + "stylesheets" => $db->escape_string(serialize($theme_stylesheets)) + ); + + // Do we have a theme present? If so, update the stylesheet display orders + if($update_disporders) + { + if(!is_array($theme) || !$theme) + { + $theme_cache = cache_themes(); + $theme = $theme_cache[$tid]; + } + + $orders = $orphaned_stylesheets = array(); + $properties = $theme['properties']; + + if(!is_array($properties)) + { + $properties = my_unserialize($theme['properties']); + } + + $max_disporder = 0; + + foreach($stylesheets as $stylesheet) + { + if(!isset($properties['disporder'][$stylesheet['name']])) + { + $orphaned_stylesheets[] = $stylesheet['name']; + continue; + } + + if($properties['disporder'][$stylesheet['name']] > $max_disporder) + { + $max_disporder = $properties['disporder'][$stylesheet['name']]; + } + + $orders[$stylesheet['name']] = $properties['disporder'][$stylesheet['name']]; + } + + if(!empty($orphaned_stylesheets)) + { + $loop = $max_disporder + 1; + $max_disporder = $loop; + foreach($orphaned_stylesheets as $stylesheet) + { + $orders[$stylesheet] = $loop; + ++$loop; + } + } + + asort($orders); + $properties['disporder'] = $orders; + $updated_theme['properties'] = $db->escape_string(serialize($properties)); + } + + $db->update_query("themes", $updated_theme, "tid = '{$tid}'"); + + // Do we have any children themes that need updating too? + if(count($child_list) > 0) + { + foreach($child_list as $id) + { + update_theme_stylesheet_list($id, false, $update_disporders); + } + } + + $cache->update_default_theme(); + + return true; +} + +function make_parent_theme_list($tid) +{ + static $themes_by_parent; + + $themes = array(); + if(!is_array($themes_by_parent)) + { + $theme_cache = cache_themes(); + foreach($theme_cache as $key => $theme) + { + if($key == "default") + { + continue; + } + + $themes_by_parent[$theme['tid']][$theme['pid']] = $theme; + } + } + + if(!isset($themes_by_parent[$tid]) || !is_array($themes_by_parent[$tid])) + { + return false; + } + + reset($themes_by_parent); + reset($themes_by_parent[$tid]); + + $themes = array(); + + foreach($themes_by_parent[$tid] as $key => $theme) + { + $themes[] = $theme['tid']; + $parents = make_parent_theme_list($theme['pid']); + + if(is_array($parents)) + { + $themes = array_merge($themes, $parents); + } + } + + return $themes; +} + +function make_child_theme_list($tid) +{ + static $themes_by_child; + + $themes = array(); + if(!is_array($themes_by_child)) + { + $theme_cache = cache_themes(); + foreach($theme_cache as $key => $theme) + { + if($key == "default") + { + continue; + } + + $themes_by_child[$theme['pid']][$theme['tid']] = $theme; + } + } + + if(!isset($themes_by_child[$tid]) || !is_array($themes_by_child[$tid])) + { + return null; + } + + $themes = array(); + + foreach($themes_by_child[$tid] as $theme) + { + $themes[] = $theme['tid']; + $children = make_child_theme_list($theme['tid']); + + if(is_array($children)) + { + $themes = array_merge($themes, $children); + } + } + + return $themes; +} + +function cache_themes() +{ + global $db, $theme_cache; + + if(empty($theme_cache) || !is_array($theme_cache)) + { + $query = $db->simple_select("themes", "*", "", array('order_by' => "pid, name")); + while($theme = $db->fetch_array($query)) + { + $theme['properties'] = my_unserialize($theme['properties']); + $theme['stylesheets'] = my_unserialize($theme['stylesheets']); + $theme_cache[$theme['tid']] = $theme; + + if($theme['def'] == 1) + { + $theme_cache['default'] = $theme['tid']; + } + } + } + + // Do we have no themes assigned as default? + if(empty($theme_cache['default'])) + { + $theme_cache['default'] = 1; + } + + return $theme_cache; +} + +function build_theme_list($parent=0, $depth=0) +{ + global $mybb, $db, $table, $lang, $page; // Global $table is bad, but it will have to do for now + static $theme_cache; + + $padding = $depth*20; // Padding + + if(!is_array($theme_cache)) + { + $themes = cache_themes(); + $query = $db->simple_select("users", "style, COUNT(uid) AS users", "", array('group_by' => 'style')); + while($user_themes = $db->fetch_array($query)) + { + if($user_themes['style'] == 0) + { + $user_themes['style'] = $themes['default']; + } + + if($themes[$user_themes['style']]['users'] > 0) + { + $themes[$user_themes['style']]['users'] += (int)$user_themes['users']; + } + else + { + $themes[$user_themes['style']]['users'] = (int)$user_themes['users']; + } + } + + // Restrucure the theme array to something we can "loop-de-loop" with + foreach($themes as $key => $theme) + { + if($key == "default") + { + continue; + } + + $theme_cache[$theme['pid']][$theme['tid']] = $theme; + } + $theme_cache['num_themes'] = count($themes); + unset($themes); + } + + if(!is_array($theme_cache[$parent])) + { + return; + } + + foreach($theme_cache[$parent] as $theme) + { + $popup = new PopupMenu("theme_{$theme['tid']}", $lang->options); + if($theme['tid'] > 1) + { + $popup->add_item($lang->edit_theme, "index.php?module=style-themes&action=edit&tid={$theme['tid']}"); + $theme['name'] = "".htmlspecialchars_uni($theme['name']).""; + + // We must have at least the master and 1 other active theme + if($theme_cache['num_themes'] > 2) + { + $popup->add_item($lang->delete_theme, "index.php?module=style-themes&action=delete&tid={$theme['tid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_theme_deletion}')"); + } + + if($theme['def'] != 1) + { + $popup->add_item($lang->set_as_default, "index.php?module=style-themes&action=set_default&tid={$theme['tid']}&my_post_key={$mybb->post_code}"); + $set_default = "post_code}\">style}/images/icons/make_default.png\" alt=\"{$lang->set_as_default}\" style=\"vertical-align: middle;\" title=\"{$lang->set_as_default}\" />"; + } + else + { + $set_default = "style}/images/icons/default.png\" alt=\"{$lang->default_theme}\" style=\"vertical-align: middle;\" title=\"{$lang->default_theme}\" />"; + } + $popup->add_item($lang->force_on_users, "index.php?module=style-themes&action=force&tid={$theme['tid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_theme_forced}')"); + } + $popup->add_item($lang->export_theme, "index.php?module=style-themes&action=export&tid={$theme['tid']}"); + $popup->add_item($lang->duplicate_theme, "index.php?module=style-themes&action=duplicate&tid={$theme['tid']}"); + $table->construct_cell("
{$set_default}
{$theme['name']}
"); + $table->construct_cell(my_number_format($theme['users']), array("class" => "align_center")); + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + $table->construct_row(); + + // Fetch & build any child themes + build_theme_list($theme['tid'], ++$depth); + } +} + +// returns an array which can be sent to generate_select_box() +function build_theme_array($ignoretid = null, $parent=0, $depth=0) +{ + global $list; + static $theme_cache; + + if(!is_array($theme_cache)) + { + $themes = cache_themes(); + // Restrucure the theme array to something we can "loop-de-loop" with + foreach($themes as $key => $theme) + { + if($key == "default") + { + continue; + } + + $theme_cache[$theme['pid']][$theme['tid']] = $theme; + } + unset($theme); + } + + if(!is_array($theme_cache[$parent]) || $ignoretid === $parent) + { + return null; + } + + foreach($theme_cache[$parent] as $theme) + { + if($ignoretid === $theme['tid']) + { + continue; + } + + $list[$theme['tid']] = str_repeat("--", $depth).$theme['name']; + // Fetch & build any child themes + build_theme_array($ignoretid, $theme['tid'], $depth+1); + } + + if(!$parent) + { + return $list; + } +} + +function fetch_theme_stylesheets($theme) +{ + // Fetch list of all of the stylesheets for this theme + $file_stylesheets = my_unserialize($theme['stylesheets']); + + if(!is_array($file_stylesheets)) + { + return false; + } + + $stylesheets = array(); + $inherited_load = array(); + + // Now we loop through the list of stylesheets for each file + foreach($file_stylesheets as $file => $action_stylesheet) + { + if($file == 'inherited') + { + continue; + } + + foreach($action_stylesheet as $action => $style) + { + foreach($style as $stylesheet2) + { + $stylesheets[$stylesheet2]['applied_to'][$file][] = $action; + if(is_array($file_stylesheets['inherited'][$file."_".$action]) && in_array($stylesheet2, array_keys($file_stylesheets['inherited'][$file."_".$action]))) + { + $stylesheets[$stylesheet2]['inherited'] = $file_stylesheets['inherited'][$file."_".$action]; + foreach($file_stylesheets['inherited'][$file."_".$action] as $value) + { + $inherited_load[] = $value; + } + } + } + } + } + + foreach($stylesheets as $file => $stylesheet2) + { + if(is_array($stylesheet2['inherited'])) + { + foreach($stylesheet2['inherited'] as $inherited_file => $tid) + { + $stylesheet2['inherited'][basename($inherited_file)] = $tid; + unset($stylesheet2['inherited'][$inherited_file]); + } + } + + $stylesheets[basename($file)] = $stylesheet2; + unset($stylesheets[$file]); + } + + return $stylesheets; +} + +function upgrade_css_120_to_140($css) +{ + // Update our CSS to the new stuff in 1.4 + $parsed_css = css_to_array($css); + + if(!is_array($parsed_css)) + { + return ""; + } + + foreach($parsed_css as $class_id => $array) + { + $parsed_css[$class_id]['values'] = str_replace('#eea8a1', '#ffdde0', $array['values']); + $parsed_css[$class_id]['values'] = str_replace('font-family: Verdana;', 'font-family: Verdana, Arial, Sans-Serif;', $array['values']); + + switch($array['class_name']) + { + case '.bottommenu': + $parsed_css[$class_id]['values'] = str_replace('padding: 6px;', 'padding: 10px;', $array['values']); + break; + case '.expcolimage': + $parsed_css[$class_id]['values'] .= "\n\tmargin-top: 2px;"; + break; + case '.toolbar_normal': + case '.toolbar_hover': + case '.toolbar_clicked': + case '.pagenav': + case '.pagenavbit': + case '.pagenavbit a': + case '.pagenavcurrent': + case '.quote_header': + case '.quote_body': + case '.code_header': + case '.code_body': + case '.usercpnav': + case '.usercpnav li': + case '.usercpnav .pmfolders': + unset($parsed_css[$class_id]); + break; + default: + } + } + + $to_add = array( + md5('.trow_selected td') => array("class_name" => '.trow_selected td', "values" => 'background: #FFFBD9;'), + md5('blockquote') => array("class_name" => 'blockquote', "values" => "border: 1px solid #ccc;\n\tmargin: 0;\n\tbackground: #fff;\n\tpadding: 4px;"), + md5('blockquote cite') => array("class_name" => 'blockquote cite', "values" => "font-weight: bold;\n\tborder-bottom: 1px solid #ccc;\n\tfont-style: normal;\n\tdisplay: block;\n\tmargin: 4px 0;"), + md5('blockquote cite span') => array("class_name" => 'blockquote cite span', "values" => "float: right;\n\tfont-weight: normal;"), + md5('.codeblock') => array("class_name" => '.codeblock', "values" => "background: #fff;\n\tborder: 1px solid #ccc;\n\tpadding: 4px;"), + md5('.codeblock .title') => array("class_name" => '.codeblock .title', "values" => "border-bottom: 1px solid #ccc;\n\tfont-weight: bold;\n\tmargin: 4px 0;"), + md5('.codeblock code') => array("class_name" => '.codeblock code', "values" => "overflow: auto;\n\theight: auto;\n\tmax-height: 200px;\n\tdisplay: block;\n\tfont-family: Monaco, Consolas, Courier, monospace;\n\tfont-size: 13px;"), + md5('.subject_new') => array("class_name" => '.subject_new', "values" => "font-weight: bold;"), + md5('.highlight') => array("class_name" => '.highlight', "values" => "background: #FFFFCC;\n\tpadding: 3px;"), + md5('.pm_alert') => array("class_name" => '.pm_alert', "values" => "background: #FFF6BF;\n\tborder: 1px solid #FFD324;\n\ttext-align: center;\n\tpadding: 5px 20px;\n\tfont-size: 11px;"), + md5('.red_alert') => array("class_name" => '.red_alert', "values" => "background: #FBE3E4;\n\tborder: 1px solid #A5161A;\n\tcolor: #A5161A;\n\ttext-align: center;\n\tpadding: 5px 20px;\n\tfont-size: 11px;"), + md5('.high_warning') => array("class_name" => '.high_warning', "values" => "color: #CC0000;"), + md5('.moderate_warning') => array("class_name" => '.moderate_warning', "values" => "color: #F3611B;"), + md5('.low_warning') => array("class_name" => '.low_warning', "values" => "color: #AE5700;"), + md5('div.error') => array("class_name" => 'div.error', "values" => "padding: 5px 10px;\n\tborder-top: 2px solid #FFD324;\n\tborder-bottom: 2px solid #FFD324;\n\tbackground: #FFF6BF\n\tfont-size: 12px;"), + md5('.high_warning') => array("class_name" => '.high_warning', "values" => "color: #CC0000;"), + md5('.moderate_warning') => array("class_name" => '.moderate_warning', "values" => "color: #F3611B;"), + md5('.low_warning') => array("class_name" => '.low_warning', "values" => "color: #AE5700;"), + md5('div.error') => array("class_name" => 'div.error', "values" => "padding: 5px 10px;\n\tborder-top: 2px solid #FFD324;\n\tborder-bottom: 2px solid #FFD324;\n\tbackground: #FFF6BF;\n\tfont-size: 12px;"), + md5('div.error p') => array("class_name" => 'div.error p', "values" => "margin: 0;\n\tcolor: #000;\n\tfont-weight: normal;"), + md5('div.error p em') => array("class_name" => 'div.error p em', "values" => "font-style: normal;\n\tfont-weight: bold;\n\tpadding-left: 24px;\n\tdisplay: block;\n\tcolor: #C00;\n\tbackground: url({$mybb->settings['bburl']}/images/error.png) no-repeat 0;"), + md5('div.error.ul') => array("class_name" => 'div.error.ul', "values" => "margin-left: 24px;"), + md5('.online') => array("class_name" => '.online', "values" => "color: #15A018;"), + md5('.offline') => array("class_name" => '.offline', "values" => "color: #C7C7C7;"), + md5('.pagination') => array("class_name" => '.pagination', "values" => "font-size: 11px;\n\tpadding-top: 10px;\n\tmargin-bottom: 5px;"), + md5('.tfoot .pagination, .tcat .pagination') => array("class_name" => '.tfoot .pagination, .tcat .pagination', "values" => "padding-top: 0;"), + md5('.pagination .pages') => array("class_name" => '.pagination .pages', "values" => "font-weight: bold;"), + md5('.pagination .pagination_current, .pagination a') => array("class_name" => '.pagination .pagination_current, .pagination a', "values" => "padding: 2px 6px;\n\tmargin-bottom: 3px;"), + md5('.pagination a') => array("class_name" => '.pagination a', "values" => "border: 1px solid #81A2C4;"), + md5('.pagination .pagination_current') => array("class_name" => '.pagination .pagination_current', "values" => "background: #F5F5F5;\n\tborder: 1px solid #81A2C4;\n\tfont-weight: bold;"), + md5('.pagination a:hover') => array("class_name" => '.pagination a:hover', "values" => "background: #F5F5F5;\n\ttext-decoration: none;"), + md5('.thread_legend, .thread_legend dd') => array("class_name" => '.thread_legend, .thread_legend dd', "values" => "margin: 0;\n\tpadding: 0;"), + md5('.thread_legend dd') => array("class_name" => '.thread_legend dd', "values" => "padding-bottom: 4px;\n\tmargin-right: 15px;"), + md5('.thread_legend img') => array("class_name" => '.thread_legend img', "values" => "margin-right: 4px;\n\tvertical-align: bottom;"), + md5('.forum_legend, .forum_legend dt, .forum_legend dd') => array("class_name" => '.forum_legend, .forum_legend dt, .forum_legend dd', "values" => "margin: 0;\n\tpadding: 0;"), + md5('.forum_legend dd') => array("class_name" => '.forum_legend dd', "values" => "float: left;\n\tmargin-right: 10px;"), + md5('.forum_legend dt') => array("class_name" => '.forum_legend dt', "values" => "margin-right: 10px;\n\tfloat: left;"), + md5('.success_message') => array("class_name" => '.success_message', "values" => "color: #00b200;\n\tfont-weight: bold;\n\tfont-size: 10px;\n\tmargin-bottom: 10px;"), + md5('.error_message') => array("class_name" => '.error_message', "values" => "color: #C00;\n\tfont-weight: bold;\n\tfont-size: 10px;\n\tmargin-bottom: 10px;"), + md5('.post_body') => array("class_name" => '.post_body', "values" => "padding: 5px;"), + md5('.post_content') => array("class_name" => '.post_content', "values" => "padding: 5px 10px;"), + md5('.invalid_field') => array("class_name" => '.invalid_field', "values" => "border: 1px solid #f30;\n\tcolor: #f30;"), + md5('.valid_field') => array("class_name" => '.valid_field', "values" => "border: 1px solid #0c0;"), + md5('.validation_error') => array("class_name" => '.validation_error', "values" => "background: url(images/invalid.png) no-repeat center left;\n\tcolor: #f30;\n\tmargin: 5px 0;\n\tpadding: 5px;\n\tfont-weight: bold;\n\tfont-size: 11px;\n\tpadding-left: 22px;"), + md5('.validation_success') => array("class_name" => '.validation_success', "values" => "background: url(images/valid.png) no-repeat center left;\n\tcolor: #00b200;\n\tmargin: 5px 0;\n\tpadding: 5px;\n\tfont-weight: bold;\n\tfont-size: 11px;\n\tpadding-left: 22px;"), + md5('.validation_loading') => array("class_name" => '.validation_loading', "values" => "background: url(images/spinner.gif) no-repeat center left;\n\tcolor: #555;\n\tmargin: 5px 0;\n\tpadding: 5px;\n\tfont-weight: bold;\n\tfont-size: 11px;\n\tpadding-left: 22px;"), + ); + + $already_parsed = array(); + + foreach($to_add as $class_id => $array) + { + if($already_parsed[$class_id]) + { + $already_parsed[$class_id]++; + $class_id .= "_".$already_parsed[$class_id]; + } + else + { + $already_parsed[$class_id] = 1; + } + + $array['name'] = ""; + $array['description'] = ""; + + $parsed_css[$class_id] = $array; + } + + $theme = array( + 'css' => '', + ); + + $css = ""; + foreach($parsed_css as $class_id => $array) + { + if($array['name'] || $array['description']) + { + $theme['css'] .= "/* "; + if($array['name']) + { + $array['css'] .= "Name: {$array['name']}"; + + if($array['description']) + { + $array['css'] .= "\n"; + } + } + + if($array['description']) + { + $array['css'] .= "Description: {$array['description']}"; + } + + $array['css'] .= " */\n"; + } + + $css .= "{$array['class_name']} {\n\t{$array['values']}\n}\n"; + } + + return $css; +} diff --git a/Upload/admin/inc/functions_view_manager.php b/Upload/admin/inc/functions_view_manager.php new file mode 100644 index 0000000..9e1b1de --- /dev/null +++ b/Upload/admin/inc/functions_view_manager.php @@ -0,0 +1,668 @@ + $lang->views, + 'link' => "{$base_url}&action=views", + 'description' => $lang->views_desc + ); + + $sub_tabs['create_view'] = array( + 'title' => $lang->create_new_view, + 'link' => "{$base_url}&action=views&do=add", + 'description' => $lang->create_new_view_desc + ); + + $page->add_breadcrumb_item($lang->view_manager, 'index.php?module=user-users&action=views'); + + // Lang strings should be in global lang file + + if($mybb->input['do'] == "set_default") + { + $query = $db->simple_select("adminviews", "vid, uid, visibility", "vid='".$mybb->get_input('vid', 1)."'"); + $admin_view = $db->fetch_array($query); + + if(!$admin_view['vid'] || $admin_view['visibility'] == 1 && $mybb->user['uid'] != $admin_view['uid']) + { + flash_message($lang->error_invalid_admin_view, 'error'); + admin_redirect($base_url."&action=views"); + } + set_default_view($type, $admin_view['vid']); + flash_message($lang->succuss_view_set_as_default, 'success'); + admin_redirect($base_url."&action=views"); + } + + if($mybb->input['do'] == "add") + { + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_view_title; + } + if($mybb->input['fields_js']) + { + $mybb->input['fields'] = explode(",", $mybb->input['fields_js']); + } + if(count($mybb->input['fields']) <= 0) + { + $errors[] = $lang->error_no_view_fields; + } + + if($mybb->get_input('perpage', 1) <= 0) + { + $errors[] = $lang->error_invalid_view_perpage; + } + + if(!in_array($mybb->input['sortby'], array_keys($sort_options))) + { + $errors[] = $lang->error_invalid_view_sortby; + } + + if($mybb->input['sortorder'] != "asc" && $mybb->input['sortorder'] != "desc") + { + $errors[] = $lang->error_invalid_view_sortorder; + } + + if($mybb->input['visibility'] == 0) + { + $mybb->input['visibility'] = 2; + } + + if(!$errors) + { + $new_view = array( + "uid" => $mybb->user['uid'], + "title" => $db->escape_string($mybb->input['title']), + "type" => $type, + "visibility" => $mybb->get_input('visibility', 1), + "fields" => $db->escape_string(serialize($mybb->input['fields'])), + "conditions" => $db->escape_string(serialize($mybb->input['conditions'])), + "custom_profile_fields" => $db->escape_string(serialize($mybb->input['profile_fields'])), + "sortby" => $db->escape_string($mybb->input['sortby']), + "sortorder" => $db->escape_string($mybb->input['sortorder']), + "perpage" => $mybb->get_input('perpage', 1), + "view_type" => $db->escape_string($mybb->input['view_type']) + ); + + $vid = $db->insert_query("adminviews", $new_view); + + if($mybb->input['isdefault']) + { + set_default_view($type, $vid); + } + flash_message($lang->success_view_created, "success"); + admin_redirect($base_url."&vid={$vid}"); + } + } + else + { + $mybb->input = array_merge($mybb->input, array('perpage' => 20)); + } + + // Write in our JS based field selector + $page->extra_header .= "\n"; + + $page->add_breadcrumb_item($lang->create_new_view); + $page->output_header($lang->create_new_view); + + $form = new Form($base_url."&action=views&do=add", "post"); + + $page->output_nav_tabs($sub_tabs, 'create_view'); + + // If we have any error messages, show them + if($errors) + { + $page->output_inline_error($errors); + } + + $form_container = new FormContainer($lang->create_new_view); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + + if($mybb->input['visibility'] == 2) + { + $visibility_public_checked = true; + } + else + { + $visibility_private_checked = true; + } + + $visibility_options = array( + $form->generate_radio_button("visibility", "1", "{$lang->private} - {$lang->private_desc}", array("checked" => $visibility_private_checked)), + $form->generate_radio_button("visibility", "2", "{$lang->public} - {$lang->public_desc}", array("checked" => $visibility_public_checked)) + ); + $form_container->output_row($lang->visibility, "", implode("
", $visibility_options)); + + $form_container->output_row($lang->set_as_default_view, "", $form->generate_yes_no_radio("isdefault", $mybb->input['isdefault'], array('yes' => 1, 'no' => 0))); + + if(count($sort_options) > 0) + { + $sort_directions = array( + "asc" => $lang->ascending, + "desc" => $lang->descending + ); + $form_container->output_row($lang->sort_results_by, "", $form->generate_select_box('sortby', $sort_options, $mybb->input['sortby'], array('id' => 'sortby'))." {$lang->in} ".$form->generate_select_box('sortorder', $sort_directions, $mybb->input['sortorder'], array('id' => 'sortorder')), 'sortby'); + } + + $form_container->output_row($lang->results_per_page, "", $form->generate_text_box('perpage', $mybb->input['perpage'], array('id' => 'perpage')), 'perpage'); + + if($type == "user") + { + $form_container->output_row($lang->display_results_as, "", $form->generate_radio_button('view_type', 'table', $lang->table, array('checked' => ($mybb->input['view_type'] != "card" ? true : false)))."
".$form->generate_radio_button('view_type', 'card', $lang->business_card, array('checked' => ($mybb->input['view_type'] == "card" ? true : false)))); + } + + $form_container->end(); + + $field_select .= "
\n"; + $field_select .= "
{$lang->enabled}
    \n"; + if(is_array($mybb->input['fields'])) + { + foreach($mybb->input['fields'] as $field) + { + if($fields[$field]) + { + $field_select .= "
  • • {$fields[$field]['title']}
  • "; + $active[$field] = 1; + } + } + } + $field_select .= "
\n"; + $field_select .= "
{$lang->disabled}
    \n"; + foreach($fields as $key => $field) + { + if($active[$key]) + { + continue; + } + $field_select .= "
  • • {$field['title']}
  • "; + } + $field_select .= "
\n"; + $field_select .= $form->generate_hidden_field("fields_js", @implode(",", @array_keys($active)), array('id' => 'fields_js')); + $field_select = str_replace("'", "\\'", $field_select); + $field_select = str_replace("\n", "", $field_select); + + $field_select = "\n"; + + foreach($fields as $key => $field) + { + $field_options[$key] = $field['title']; + } + + $field_select .= "\n"; + + $form_container = new FormContainer($lang->fields_to_show); + $form_container->output_row($lang->fields_to_show_desc, $description, $field_select); + $form_container->end(); + + // Build the search conditions + if(function_exists($conditions_callback)) + { + $conditions_callback($mybb->input, $form); + } + + $buttons[] = $form->generate_submit_button($lang->save_view); + $form->output_submit_wrapper($buttons); + + $form->end(); + $page->output_footer(); + } + else if($mybb->input['do'] == "edit") + { + $query = $db->simple_select("adminviews", "*", "vid='".$mybb->get_input('vid', 1)."'"); + $admin_view = $db->fetch_array($query); + + // Does the view not exist? + if(!$admin_view['vid'] || $admin_view['visibility'] == 1 && $mybb->user['uid'] != $admin_view['uid']) + { + flash_message($lang->error_invalid_admin_view, 'error'); + admin_redirect($base_url."&action=views"); + } + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_view_title; + } + if($mybb->input['fields_js']) + { + $mybb->input['fields'] = explode(",", $mybb->input['fields_js']); + } + + if(count($mybb->input['fields']) <= 0) + { + $errors[] = $lang->error_no_view_fields; + } + + if($mybb->get_input('perpage', 1) <= 0) + { + $errors[] = $lang->error_invalid_view_perpage; + } + + if(!in_array($mybb->input['sortby'], array_keys($sort_options))) + { + $errors[] = $lang->error_invalid_view_sortby; + } + + if($mybb->input['sortorder'] != "asc" && $mybb->input['sortorder'] != "desc") + { + $errors[] = $lang->error_invalid_view_sortorder; + } + + if($mybb->input['visibility'] == 0) + { + $mybb->input['visibility'] = 2; + } + + if(!$errors) + { + $updated_view = array( + "title" => $db->escape_string($mybb->input['title']), + "type" => $type, + "visibility" => $mybb->get_input('visibility', 1), + "fields" => $db->escape_string(serialize($mybb->input['fields'])), + "conditions" => $db->escape_string(serialize($mybb->input['conditions'])), + "custom_profile_fields" => $db->escape_string(serialize($mybb->input['profile_fields'])), + "sortby" => $db->escape_string($mybb->input['sortby']), + "sortorder" => $db->escape_string($mybb->input['sortorder']), + "perpage" => $mybb->get_input('perpage', 1), + "view_type" => $db->escape_string($mybb->input['view_type']) + ); + $db->update_query("adminviews", $updated_view, "vid='{$admin_view['vid']}'"); + + if($mybb->input['isdefault']) + { + set_default_view($type, $admin_view['vid']); + } + + flash_message($lang->success_view_updated, "success"); + admin_redirect($base_url."&vid={$admin_view['vid']}"); + } + } + + // Write in our JS based field selector + $page->extra_header .= "\n"; + + $page->add_breadcrumb_item($lang->edit_view); + $page->output_header($lang->edit_view); + + $form = new Form($base_url."&action=views&do=edit&vid={$admin_view['vid']}", "post"); + + $sub_tabs = array(); + $sub_tabs['edit_view'] = array( + 'title' => $lang->edit_view, + 'link' => $base_url."&action=views&do=edit&vid={$admin_view['vid']}", + 'description' => $lang->edit_view_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_view'); + + // If we have any error messages, show them + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $admin_view['conditions'] = my_unserialize($admin_view['conditions']); + $admin_view['fields'] = my_unserialize($admin_view['fields']); + $admin_view['profile_fields'] = my_unserialize($admin_view['custom_profile_fields']); + $mybb->input = array_merge($mybb->input, $admin_view); + + $mybb->input['isdefault'] = 0; + $default_view = fetch_default_view($type); + + if($default_view == $admin_view['vid']) + { + $mybb->input['isdefault'] = 1; + } + } + + $form_container = new FormContainer($lang->edit_view); + $form_container->output_row($lang->view." *", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + + if($mybb->input['visibility'] == 2) + { + $visibility_public_checked = true; + } + else + { + $visibility_private_checked = true; + } + + $visibility_options = array( + $form->generate_radio_button("visibility", "1", "{$lang->private} - {$lang->private_desc}", array("checked" => $visibility_private_checked)), + $form->generate_radio_button("visibility", "2", "{$lang->public} - {$lang->public_desc}", array("checked" => $visibility_public_checked)) + ); + $form_container->output_row($lang->visibility, "", implode("
", $visibility_options)); + + $form_container->output_row($lang->set_as_default_view, "", $form->generate_yes_no_radio("isdefault", $mybb->input['isdefault'], array('yes' => 1, 'no' => 0))); + + if(count($sort_options) > 0) + { + $sort_directions = array( + "asc" => $lang->ascending, + "desc" => $lang->descending + ); + $form_container->output_row($lang->sort_results_by, "", $form->generate_select_box('sortby', $sort_options, $mybb->input['sortby'], array('id' => 'sortby'))." {$lang->in} ".$form->generate_select_box('sortorder', $sort_directions, $mybb->input['sortorder'], array('id' => 'sortorder')), 'sortby'); + } + + $form_container->output_row($lang->results_per_page, "", $form->generate_text_box('perpage', $mybb->input['perpage'], array('id' => 'perpage')), 'perpage'); + + if($type == "user") + { + $form_container->output_row($lang->display_results_as, "", $form->generate_radio_button('view_type', 'table', $lang->table, array('checked' => ($mybb->input['view_type'] != "card" ? true : false)))."
".$form->generate_radio_button('view_type', 'card', $lang->business_card, array('checked' => ($mybb->input['view_type'] == "card" ? true : false)))); + } + + $form_container->end(); + + $field_select .= "
\n"; + $field_select .= "
{$lang->enabled}
    \n"; + if(is_array($mybb->input['fields'])) + { + foreach($mybb->input['fields'] as $field) + { + if($fields[$field]) + { + $field_select .= "
  • • {$fields[$field]['title']}
  • "; + $active[$field] = 1; + } + } + } + $field_select .= "
\n"; + $field_select .= "
{$lang->disabled}
    \n"; + if(is_array($fields)) + { + foreach($fields as $key => $field) + { + if($active[$key]) + { + continue; + } + $field_select .= "
  • • {$field['title']}
  • "; + } + } + $field_select .= "
\n"; + $field_select .= $form->generate_hidden_field("fields_js", @implode(",", @array_keys($active)), array('id' => 'fields_js')); + $field_select = str_replace("'", "\\'", $field_select); + $field_select = str_replace("\n", "", $field_select); + + $field_select = "\n"; + + foreach($fields as $key => $field) + { + $field_options[$key] = $field['title']; + } + + $field_select .= "\n"; + + $form_container = new FormContainer($lang->fields_to_show); + $form_container->output_row($lang->fields_to_show_desc, $description, $field_select); + $form_container->end(); + + // Build the search conditions + if(function_exists($conditions_callback)) + { + $conditions_callback($mybb->input, $form); + } + + $buttons[] = $form->generate_submit_button($lang->save_view); + $form->output_submit_wrapper($buttons); + + $form->end(); + $page->output_footer(); + } + + else if($mybb->input['do'] == "delete") + { + if($mybb->input['no']) + { + admin_redirect($base_url."&action=views"); + } + + $query = $db->simple_select("adminviews", "COUNT(vid) as views"); + $views = $db->fetch_field($query, "views"); + + if($views == 0) + { + flash_message($lang->error_cannot_delete_view, 'error'); + admin_redirect($base_url."&action=views"); + } + + $vid = $mybb->get_input('vid', 1); + $query = $db->simple_select("adminviews", "vid, uid, visibility", "vid = '{$vid}'"); + $admin_view = $db->fetch_array($query); + + if($vid == 1 || !$admin_view['vid'] || $admin_view['visibility'] == 1 && $mybb->user['uid'] != $admin_view['uid']) + { + flash_message($lang->error_invalid_view_delete, 'error'); + admin_redirect($base_url."&action=views"); + } + + if($mybb->request_method == "post") + { + $db->delete_query("adminviews", "vid='{$admin_view['vid']}'"); + flash_message($lang->success_view_deleted, 'success'); + admin_redirect($base_url."&action=views"); + } + else + { + $page->output_confirm_action($base_url."&action=views&do=delete&vid={$admin_view['vid']}", $lang->confirm_view_deletion); + } + } + + // Export views + else if($mybb->input['do'] == "export") + { + $xml = "\n"; + $xml = "version_code."\" exported=\"".TIME_NOW."\">\n"; + + if($mybb->input['type']) + { + $type_where = "type='".$db->escape_string($mybb->input['type'])."'"; + } + + $query = $db->simple_select("adminviews", "*", $type_where); + while($admin_view = $db->fetch_array($query)) + { + $fields = my_unserialize($admin_view['fields']); + $conditions = my_unserialize($admin_view['conditions']); + + $admin_view['title'] = str_replace(']]>', ']]]]>', $admin_view['title']); + $admin_view['sortby'] = str_replace(']]>', ']]]]>', $admin_view['sortby']); + $admin_view['sortorder'] = str_replace(']]>', ']]]]>', $admin_view['sortorder']); + $admin_view['view_type'] = str_replace(']]>', ']]]]>', $admin_view['view_type']); + + $xml .= "\t\n"; + $xml .= "\t\t<![CDATA[{$admin_view['title']}]]>\n"; + $xml .= "\t\t\n"; + foreach($fields as $field) + { + $xml .= "\t\t\t\n"; + } + $xml .= "\t\t\n"; + $xml .= "\t\t\n"; + foreach($conditions as $name => $condition) + { + if(!$conditions) continue; + if(is_array($condition)) + { + $condition = serialize($condition); + $is_serialized = " is_serialized=\"1\""; + } + $condition = str_replace(']]>', ']]]]>', $condition); + $xml .= "\t\t\t\n"; + } + $xml .= "\t\t\n"; + $xml .= "\t\t\n"; + $xml .= "\t\t\n"; + $xml .= "\t\t\n"; + $xml .= "\t\t\n"; + $xml .= "\t\n"; + } + $xml .= "\n"; + $mybb->settings['bbname'] = urlencode($mybb->settings['bbname']); + header("Content-disposition: filename=".$mybb->settings['bbname']."-views.xml"); + header("Content-Length: ".my_strlen($xml)); + header("Content-type: unknown/unknown"); + header("Pragma: no-cache"); + header("Expires: 0"); + echo $xml; + exit; + } + + // Generate a listing of all current views + else + { + $page->output_header($lang->view_manager); + + $page->output_nav_tabs($sub_tabs, 'views'); + + $table = new Table; + $table->construct_header($lang->view); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 150)); + + $default_view = fetch_default_view($type); + + $query = $db->simple_select("adminviews", "COUNT(vid) as views"); + $views = $db->fetch_field($query, "views"); + + $query = $db->query(" + SELECT v.*, u.username + FROM ".TABLE_PREFIX."adminviews v + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=v.uid) + WHERE v.visibility='2' OR (v.visibility='1' AND v.uid='{$mybb->user['uid']}') + ORDER BY title + "); + while($view = $db->fetch_array($query)) + { + $created = ""; + if($view['uid'] == 0) + { + $view_type = "default"; + $default_class = "grey"; + } + else if($view['visibility'] == 2) + { + $view_type = "group"; + if($view['username']) + { + $created = "
{$lang->created_by} {$view['username']}"; + } + } + else + { + $view_type = "user"; + } + + $default_add = ''; + if($default_view == $view['vid']) + { + $default_add = " ({$lang->default})"; + } + + $title_string = "view_title_{$view['vid']}"; + + if($lang->$title_string) + { + $view['title'] = $lang->$title_string; + } + + $table->construct_cell("
style}/images/icons/{$view_type}.png\" title=\"".$lang->sprintf($lang->this_is_a_view, $view_type)."\" alt=\"{$view_type}\" />
{$view['title']}{$default_add}{$created}
"); + + $popup = new PopupMenu("view_{$view['vid']}", $lang->options); + $popup->add_item($lang->edit_view, "{$base_url}&action=views&do=edit&vid={$view['vid']}"); + if($view['vid'] != $default_view) + { + $popup->add_item($lang->set_as_default, "{$base_url}&action=views&do=set_default&vid={$view['vid']}"); + } + + if($views > 1 && $view['vid'] != 1) + { + $popup->add_item($lang->delete_view, "{$base_url}&action=views&do=delete&vid={$view['vid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_view_deletion}')"); + } + $controls = $popup->fetch(); + $table->construct_cell($controls, array("class" => "align_center")); + $table->construct_row(); + } + + $table->output($lang->view); + + echo << +
+{$lang->legend} +{$lang->default} {$lang->default_view_desc}
+{$lang->public} {$lang->public_view_desc}
+{$lang->private} {$lang->private_view_desc}
+LEGEND; + $page->output_footer(); + } +} + +function set_default_view($type, $vid) +{ + global $mybb, $db; + + $query = $db->simple_select("adminoptions", "defaultviews", "uid='{$mybb->user['uid']}'"); + $default_views = my_unserialize($db->fetch_field($query, "defaultviews")); + if(!$db->num_rows($query)) + { + $create = true; + } + $default_views[$type] = $vid; + $default_views = serialize($default_views); + $updated_admin = array("defaultviews" => $db->escape_string($default_views)); + + if($create == true) + { + $updated_admin['uid'] = $mybb->user['uid']; + $updated_admin['notes'] = ''; + $updated_admin['permissions'] = ''; + $db->insert_query("adminoptions", $updated_admin); + } + else + { + $db->update_query("adminoptions", $updated_admin, "uid='{$mybb->user['uid']}'"); + } +} + +function fetch_default_view($type) +{ + global $mybb, $db; + $query = $db->simple_select("adminoptions", "defaultviews", "uid='{$mybb->user['uid']}'"); + $default_views = my_unserialize($db->fetch_field($query, "defaultviews")); + if(!is_array($default_views)) + { + return false; + } + return $default_views[$type]; +} diff --git a/Upload/admin/inc/index.html b/Upload/admin/inc/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/inc/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/index.php b/Upload/admin/index.php new file mode 100644 index 0000000..215a0fb --- /dev/null +++ b/Upload/admin/index.php @@ -0,0 +1,598 @@ +settings['cplanguage']."/admin/home_dashboard.lang.php")) + { + $mybb->settings['cplanguage'] = "english"; + } + $lang->set_language($mybb->settings['cplanguage'], "admin"); +} + +// Load global language phrases +$lang->load("global"); + +if(function_exists('mb_internal_encoding') && !empty($lang->settings['charset'])) +{ + @mb_internal_encoding($lang->settings['charset']); +} + +header("Content-type: text/html; charset={$lang->settings['charset']}"); + +$time = TIME_NOW; +$errors = null; + +if(is_dir(MYBB_ROOT."install") && !file_exists(MYBB_ROOT."install/lock")) +{ + $mybb->trigger_generic_error("install_directory"); +} + +$ip_address = get_ip(); +unset($user); + +// Load Admin CP style +if(!isset($cp_style)) +{ + if(!empty($mybb->settings['cpstyle']) && file_exists(MYBB_ADMIN_DIR."/styles/".$mybb->settings['cpstyle']."/main.css")) + { + $cp_style = $mybb->settings['cpstyle']; + } + else + { + $cp_style = "default"; + } +} + +$default_page = new DefaultPage; + +$logged_out = false; +$fail_check = 0; +$post_verify = true; + +foreach(array('action', 'do', 'module') as $input) +{ + if(!isset($mybb->input[$input])) + { + $mybb->input[$input] = ''; + } +} + +if($mybb->input['action'] == "unlock") +{ + $user = array(); + $error = ''; + if($mybb->input['username']) + { + $user = get_user_by_username($mybb->input['username'], array('fields' => '*')); + + if(!$user['uid']) + { + $error = $lang->error_invalid_username; + } + } + else if($mybb->input['uid']) + { + $user = get_user($mybb->input['uid']); + if(!$user['uid']) + { + $error = $lang->error_invalid_uid; + } + } + + // Do we have the token? If so let's process it + if($mybb->input['token'] && $user['uid']) + { + $query = $db->simple_select("awaitingactivation", "COUNT(aid) AS num", "uid='".(int)$user['uid']."' AND code='".$db->escape_string($mybb->input['token'])."' AND type='l'"); + + // If we're good to go + if($db->fetch_field($query, "num") > 0) + { + $db->delete_query("awaitingactivation", "uid='".(int)$user['uid']."' AND code='".$db->escape_string($mybb->input['token'])."' AND type='l'"); + $db->update_query("adminoptions", array('loginlockoutexpiry' => 0, 'loginattempts' => 0), "uid='".(int)$user['uid']."'"); + + admin_redirect("index.php"); + } + else + { + $error = $lang->error_invalid_token; + } + } + + $default_page->show_lockout_unlock($error, 'error'); +} +elseif($mybb->input['do'] == "login") +{ + require_once MYBB_ROOT."inc/datahandlers/login.php"; + $loginhandler = new LoginDataHandler("get"); + + // Validate PIN first + if(!empty($config['secret_pin']) && (empty($mybb->input['pin']) || $mybb->input['pin'] != $config['secret_pin'])) + { + $default_page->show_login($lang->error_invalid_secret_pin, "error"); + } + + $loginhandler->set_data(array( + 'username' => $mybb->input['username'], + 'password' => $mybb->input['password'] + )); + + if($loginhandler->verify_username() !== false && $loginhandler->verify_password() !== false) + { + $mybb->user = get_user($loginhandler->login_data['uid']); + } + + if($mybb->user['uid']) + { + if(login_attempt_check_acp($mybb->user['uid']) == true) + { + log_admin_action(array( + 'type' => 'admin_locked_out', + 'uid' => (int)$mybb->user['uid'], + 'username' => $mybb->user['username'], + ) + ); + + $default_page->show_lockedout(); + } + + $db->delete_query("adminsessions", "uid='{$mybb->user['uid']}'"); + + $sid = md5(uniqid(microtime(true), true)); + + $useragent = $_SERVER['HTTP_USER_AGENT']; + if(my_strlen($useragent) > 100) + { + $useragent = my_substr($useragent, 0, 100); + } + + // Create a new admin session for this user + $admin_session = array( + "sid" => $sid, + "uid" => $mybb->user['uid'], + "loginkey" => $mybb->user['loginkey'], + "ip" => $db->escape_binary(my_inet_pton(get_ip())), + "dateline" => TIME_NOW, + "lastactive" => TIME_NOW, + "data" => serialize(array()), + "useragent" => $db->escape_string($useragent), + ); + $db->insert_query("adminsessions", $admin_session); + $admin_session['data'] = array(); + $db->update_query("adminoptions", array("loginattempts" => 0, "loginlockoutexpiry" => 0), "uid='".(int)$mybb->user['uid']."'"); + my_setcookie("adminsid", $sid, '', true); + my_setcookie('acploginattempts', 0); + $post_verify = false; + + $mybb->request_method = "get"; + + if(!empty($mybb->input['module'])) + { + // $query_string should contain the module + $query_string = '?module='.htmlspecialchars_uni($mybb->input['module']); + + // Now we look for any paramters passed in $_SERVER['QUERY_STRING'] + if($_SERVER['QUERY_STRING']) + { + $qstring = '?'.preg_replace('#adminsid=(.{32})#i', '', $_SERVER['QUERY_STRING']); + $qstring = str_replace('action=logout', '', $qstring); + $qstring = preg_replace('#&+#', '&', $qstring); + $qstring = str_replace('?&', '?', $qstring); + + // So what do we do? We know that parameters are devided by ampersands + // That means we must get to work! + $parameters = explode('&', $qstring); + + // Remove our first member if it's for the module + if(substr($parameters[0], 0, 8) == '?module=') + { + unset($parameters[0]); + } + + foreach($parameters as $key => $param) + { + $params = explode("=", $param); + + $query_string .= '&'.htmlspecialchars_uni($params[0])."=".htmlspecialchars_uni($params[1]); + } + } + + admin_redirect("index.php".$query_string); + } + } + else + { + $login_user = get_user_by_username($mybb->input['username'], array('fields' => array('email', 'username'))); + + if($login_user['uid'] > 0) + { + $db->update_query("adminoptions", array("loginattempts" => "loginattempts+1"), "uid='".(int)$login_user['uid']."'", '', true); + } + + $loginattempts = login_attempt_check_acp($login_user['uid'], true); + + // Have we attempted too many times? + if($loginattempts['loginattempts'] > 0) + { + // Have we set an expiry yet? + if($loginattempts['loginlockoutexpiry'] == 0) + { + $db->update_query("adminoptions", array("loginlockoutexpiry" => TIME_NOW+((int)$mybb->settings['loginattemptstimeout']*60)), "uid='".(int)$login_user['uid']."'"); + } + + // Did we hit lockout for the first time? Send the unlock email to the administrator + if($loginattempts['loginattempts'] == $mybb->settings['maxloginattempts']) + { + $db->delete_query("awaitingactivation", "uid='".(int)$login_user['uid']."' AND type='l'"); + $lockout_array = array( + "uid" => $login_user['uid'], + "dateline" => TIME_NOW, + "code" => random_str(), + "type" => "l" + ); + $db->insert_query("awaitingactivation", $lockout_array); + + $subject = $lang->sprintf($lang->locked_out_subject, $mybb->settings['bbname']); + $message = $lang->sprintf($lang->locked_out_message, htmlspecialchars_uni($mybb->input['username']), $mybb->settings['bbname'], $mybb->settings['maxloginattempts'], $mybb->settings['bburl'], $mybb->config['admin_dir'], $lockout_array['code'], $lockout_array['uid']); + my_mail($login_user['email'], $subject, $message); + } + + log_admin_action(array( + 'type' => 'admin_locked_out', + 'uid' => (int)$login_user['uid'], + 'username' => $login_user['username'], + ) + ); + + $default_page->show_lockedout(); + } + + $fail_check = 1; + } +} +else +{ + // No admin session - show message on the login screen + if(!isset($mybb->cookies['adminsid'])) + { + $login_message = ""; + } + // Otherwise, check admin session + else + { + $query = $db->simple_select("adminsessions", "*", "sid='".$db->escape_string($mybb->cookies['adminsid'])."'"); + $admin_session = $db->fetch_array($query); + + // No matching admin session found - show message on login screen + if(!$admin_session['sid']) + { + $login_message = $lang->error_invalid_admin_session; + } + else + { + $admin_session['data'] = my_unserialize($admin_session['data']); + + // Fetch the user from the admin session + $mybb->user = get_user($admin_session['uid']); + + // Login key has changed - force logout + if(!$mybb->user['uid'] || $mybb->user['loginkey'] != $admin_session['loginkey']) + { + unset($mybb->user); + } + else + { + // Admin CP sessions 2 hours old are expired + if($admin_session['lastactive'] < TIME_NOW-7200) + { + $login_message = $lang->error_admin_session_expired; + $db->delete_query("adminsessions", "sid='".$db->escape_string($mybb->cookies['adminsid'])."'"); + unset($mybb->user); + } + // If IP matching is set - check IP address against the session IP + else if(ADMIN_IP_SEGMENTS > 0) + { + $exploded_ip = explode(".", $ip_address); + $exploded_admin_ip = explode(".", $admin_session['ip']); + $matches = 0; + $valid_ip = false; + for($i = 0; $i < ADMIN_IP_SEGMENTS; ++$i) + { + if($exploded_ip[$i] == $exploded_admin_ip[$i]) + { + ++$matches; + } + if($matches == ADMIN_IP_SEGMENTS) + { + $valid_ip = true; + break; + } + } + + // IP doesn't match properly - show message on logon screen + if(!$valid_ip) + { + $login_message = $lang->error_invalid_ip; + unset($mybb->user); + } + } + } + } + } +} + +if($mybb->input['action'] == "logout" && $mybb->user) +{ + if(verify_post_check($mybb->input['my_post_key'])) + { + $db->delete_query("adminsessions", "sid='".$db->escape_string($mybb->cookies['adminsid'])."'"); + my_unsetcookie('adminsid'); + $logged_out = true; + } +} + +if(!isset($mybb->user['usergroup'])) +{ + $mybbgroups = 1; +} +else +{ + $mybbgroups = $mybb->user['usergroup'].",".$mybb->user['additionalgroups']; +} +$mybb->usergroup = usergroup_permissions($mybbgroups); + +$is_super_admin = is_super_admin($mybb->user['uid']); + +if($mybb->usergroup['cancp'] != 1 && !$is_super_admin || !$mybb->user['uid']) +{ + $uid = 0; + if(isset($mybb->user['uid'])) + { + $uid = (int)$mybb->user['uid']; + } + $db->delete_query("adminsessions", "uid = '{$uid}'"); + unset($mybb->user); + my_unsetcookie('adminsid'); +} + +if(!empty($mybb->user['uid'])) +{ + $query = $db->simple_select("adminoptions", "*", "uid='".$mybb->user['uid']."'"); + $admin_options = $db->fetch_array($query); + + if(!empty($admin_options['cplanguage']) && file_exists(MYBB_ROOT."inc/languages/".$admin_options['cplanguage']."/admin/home_dashboard.lang.php")) + { + $cp_language = $admin_options['cplanguage']; + $lang->set_language($cp_language, "admin"); + $lang->load("global"); // Reload global language vars + } + + if(!empty($admin_options['cpstyle']) && file_exists(MYBB_ADMIN_DIR."/styles/{$admin_options['cpstyle']}/main.css")) + { + $cp_style = $admin_options['cpstyle']; + } + + // Update the session information in the DB + if($admin_session['sid']) + { + $db->update_query("adminsessions", array('lastactive' => TIME_NOW, 'ip' => $db->escape_binary(my_inet_pton(get_ip()))), "sid='".$db->escape_string($admin_session['sid'])."'"); + } + + // Fetch administrator permissions + $mybb->admin['permissions'] = get_admin_permissions($mybb->user['uid']); +} + +// Include the layout generation class overrides for this style +if(file_exists(MYBB_ADMIN_DIR."/styles/{$cp_style}/style.php")) +{ + require_once MYBB_ADMIN_DIR."/styles/{$cp_style}/style.php"; +} + +// Check if any of the layout generation classes we can override exist in the style file +$classes = array( + "Page" => "DefaultPage", + "SidebarItem" => "DefaultSidebarItem", + "PopupMenu" => "DefaultPopupMenu", + "Table" => "DefaultTable", + "Form" => "DefaultForm", + "FormContainer" => "DefaultFormContainer" +); +foreach($classes as $style_name => $default_name) +{ + // Style does not have this layout generation class, create it + if(!class_exists($style_name)) + { + eval("class {$style_name} extends {$default_name} { }"); + } +} + +$page = new Page; +$page->style = $cp_style; + +// Do not have a valid Admin user, throw back to login page. +if(!isset($mybb->user['uid']) || $logged_out == true) +{ + if($logged_out == true) + { + $page->show_login($lang->success_logged_out); + } + elseif($fail_check == 1) + { + $login_lang_string = $lang->error_invalid_username_password; + + switch($mybb->settings['username_method']) + { + case 0: // Username only + $login_lang_string = $lang->sprintf($login_lang_string, $lang->login_username); + break; + case 1: // Email only + $login_lang_string = $lang->sprintf($login_lang_string, $lang->login_email); + break; + case 2: // Username and email + default: + $login_lang_string = $lang->sprintf($login_lang_string, $lang->login_username_and_password); + break; + } + + $page->show_login($login_lang_string, "error"); + } + else + { + // If we have this error while retreiving it from an AJAX request, then send back a nice error + if(isset($mybb->input['ajax']) && $mybb->input['ajax'] == 1) + { + echo json_encode(array("errors" => array("login"))); + exit; + } + $page->show_login($login_message, "error"); + } +} + +$page->add_breadcrumb_item($lang->home, "index.php"); + +// Begin dealing with the modules +$modules_dir = MYBB_ADMIN_DIR."modules"; +$dir = opendir($modules_dir); +while(($module = readdir($dir)) !== false) +{ + if(is_dir($modules_dir."/".$module) && !in_array($module, array(".", "..")) && file_exists($modules_dir."/".$module."/module_meta.php")) + { + require_once $modules_dir."/".$module."/module_meta.php"; + + // Need to always load it for admin permissions / quick access + $lang->load($module."_module_meta", false, true); + + $has_permission = false; + if(function_exists($module."_admin_permissions")) + { + if(isset($mybb->admin['permissions'][$module]) || $is_super_admin == true) + { + $has_permission = true; + } + } + // This module doesn't support permissions + else + { + $has_permission = true; + } + + // Do we have permissions to run this module (Note: home is accessible by all) + if($module == "home" || $has_permission == true) + { + $meta_function = $module."_meta"; + $initialized = $meta_function(); + if($initialized == true) + { + $modules[$module] = 1; + } + } + else + { + $modules[$module] = 0; + } + } +} + +$modules = $plugins->run_hooks("admin_tabs", $modules); + +closedir($dir); + +if(strpos($mybb->input['module'], "/") !== false) +{ + $current_module = explode("/", $mybb->input['module'], 2); +} +else +{ + $current_module = explode("-", $mybb->input['module'], 2); +} + +if(!isset($current_module[1])) +{ + $current_module[1] = 'home'; +} + +if($mybb->input['module'] && isset($modules[$current_module[0]])) +{ + $run_module = $current_module[0]; +} +else +{ + $run_module = "home"; +} + +$action_handler = $run_module."_action_handler"; +$action_file = $action_handler($current_module[1]); + +// Set our POST validation code here +$mybb->post_code = generate_post_check(); + +if($run_module != "home") +{ + check_admin_permissions(array('module' => $page->active_module, 'action' => $page->active_action)); +} + +// Only POST actions with a valid post code can modify information. Here we check if the incoming request is a POST and if that key is valid. +$post_check_ignores = array( + "example/page" => array("action") +); // An array of modules/actions to ignore POST checks for. + +if($mybb->request_method == "post") +{ + if(in_array($mybb->input['module'], $post_check_ignores)) + { + $k = array_search($mybb->input['module'], $post_check_ignores); + if(in_array($mybb->input['action'], $post_check_ignores[$k])) + { + $post_verify = false; + } + } + + if($post_verify == true) + { + // If the post key does not match we switch the action to GET and set a message to show the user + if(!isset($mybb->input['my_post_key']) || $mybb->post_code != $mybb->input['my_post_key']) + { + $mybb->request_method = "get"; + $page->show_post_verify_error = true; + } + } +} + +$lang->load("{$run_module}_{$page->active_action}", false, true); + +$plugins->run_hooks("admin_load"); + +require $modules_dir."/".$run_module."/".$action_file; + diff --git a/Upload/admin/jscripts/admincp.js b/Upload/admin/jscripts/admincp.js new file mode 100644 index 0000000..7d4d810 --- /dev/null +++ b/Upload/admin/jscripts/admincp.js @@ -0,0 +1,23 @@ +var AdminCP = { + init: function() + { + }, + + deleteConfirmation: function(element, message) + { + if(!element) return false; + confirmReturn = confirm(message); + if(confirmReturn == true) + { + form = $("
", { method: "post", action: element.href, style: "display: none;" }); + $("body").append(form); + form.submit(); + } + return false; + } +}; + +$(function() +{ + AdminCP.init(); +}); \ No newline at end of file diff --git a/Upload/admin/jscripts/codemirror/LICENSE b/Upload/admin/jscripts/codemirror/LICENSE new file mode 100644 index 0000000..d21bbea --- /dev/null +++ b/Upload/admin/jscripts/codemirror/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2014 by Marijn Haverbeke and others + +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. diff --git a/Upload/admin/jscripts/codemirror/addon/comment/comment.js b/Upload/admin/jscripts/codemirror/addon/comment/comment.js new file mode 100644 index 0000000..3ac4764 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/comment/comment.js @@ -0,0 +1,172 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var noOptions = {}; + var nonWS = /[^\s\u00a0]/; + var Pos = CodeMirror.Pos; + + function firstNonWS(str) { + var found = str.search(nonWS); + return found == -1 ? 0 : found; + } + + CodeMirror.commands.toggleComment = function(cm) { + var minLine = Infinity, ranges = cm.listSelections(), mode = null; + for (var i = ranges.length - 1; i >= 0; i--) { + var from = ranges[i].from(), to = ranges[i].to(); + if (from.line >= minLine) continue; + if (to.line >= minLine) to = Pos(minLine, 0); + minLine = from.line; + if (mode == null) { + if (cm.uncomment(from, to)) mode = "un"; + else { cm.lineComment(from, to); mode = "line"; } + } else if (mode == "un") { + cm.uncomment(from, to); + } else { + cm.lineComment(from, to); + } + } + }; + + CodeMirror.defineExtension("lineComment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = self.getModeAt(from); + var commentString = options.lineComment || mode.lineComment; + if (!commentString) { + if (options.blockCommentStart || mode.blockCommentStart) { + options.fullLines = true; + self.blockComment(from, to, options); + } + return; + } + var firstLine = self.getLine(from.line); + if (firstLine == null) return; + var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1); + var pad = options.padding == null ? " " : options.padding; + var blankLines = options.commentBlankLines || from.line == to.line; + + self.operation(function() { + if (options.indent) { + var baseString = firstLine.slice(0, firstNonWS(firstLine)); + for (var i = from.line; i < end; ++i) { + var line = self.getLine(i), cut = baseString.length; + if (!blankLines && !nonWS.test(line)) continue; + if (line.slice(0, cut) != baseString) cut = firstNonWS(line); + self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut)); + } + } else { + for (var i = from.line; i < end; ++i) { + if (blankLines || nonWS.test(self.getLine(i))) + self.replaceRange(commentString + pad, Pos(i, 0)); + } + } + }); + }); + + CodeMirror.defineExtension("blockComment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = self.getModeAt(from); + var startString = options.blockCommentStart || mode.blockCommentStart; + var endString = options.blockCommentEnd || mode.blockCommentEnd; + if (!startString || !endString) { + if ((options.lineComment || mode.lineComment) && options.fullLines != false) + self.lineComment(from, to, options); + return; + } + + var end = Math.min(to.line, self.lastLine()); + if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end; + + var pad = options.padding == null ? " " : options.padding; + if (from.line > end) return; + + self.operation(function() { + if (options.fullLines != false) { + var lastLineHasText = nonWS.test(self.getLine(end)); + self.replaceRange(pad + endString, Pos(end)); + self.replaceRange(startString + pad, Pos(from.line, 0)); + var lead = options.blockCommentLead || mode.blockCommentLead; + if (lead != null) for (var i = from.line + 1; i <= end; ++i) + if (i != end || lastLineHasText) + self.replaceRange(lead + pad, Pos(i, 0)); + } else { + self.replaceRange(endString, to); + self.replaceRange(startString, from); + } + }); + }); + + CodeMirror.defineExtension("uncomment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = self.getModeAt(from); + var end = Math.min(to.line, self.lastLine()), start = Math.min(from.line, end); + + // Try finding line comments + var lineString = options.lineComment || mode.lineComment, lines = []; + var pad = options.padding == null ? " " : options.padding, didSomething; + lineComment: { + if (!lineString) break lineComment; + for (var i = start; i <= end; ++i) { + var line = self.getLine(i); + var found = line.indexOf(lineString); + if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1; + if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment; + if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment; + lines.push(line); + } + self.operation(function() { + for (var i = start; i <= end; ++i) { + var line = lines[i - start]; + var pos = line.indexOf(lineString), endPos = pos + lineString.length; + if (pos < 0) continue; + if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length; + didSomething = true; + self.replaceRange("", Pos(i, pos), Pos(i, endPos)); + } + }); + if (didSomething) return true; + } + + // Try block comments + var startString = options.blockCommentStart || mode.blockCommentStart; + var endString = options.blockCommentEnd || mode.blockCommentEnd; + if (!startString || !endString) return false; + var lead = options.blockCommentLead || mode.blockCommentLead; + var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end); + var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString); + if (close == -1 && start != end) { + endLine = self.getLine(--end); + close = endLine.lastIndexOf(endString); + } + if (open == -1 || close == -1 || + !/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) || + !/comment/.test(self.getTokenTypeAt(Pos(end, close + 1)))) + return false; + + self.operation(function() { + self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)), + Pos(end, close + endString.length)); + var openEnd = open + startString.length; + if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length; + self.replaceRange("", Pos(start, open), Pos(start, openEnd)); + if (lead) for (var i = start + 1; i <= end; ++i) { + var line = self.getLine(i), found = line.indexOf(lead); + if (found == -1 || nonWS.test(line.slice(0, found))) continue; + var foundEnd = found + lead.length; + if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length; + self.replaceRange("", Pos(i, found), Pos(i, foundEnd)); + } + }); + return true; + }); +}); diff --git a/Upload/admin/jscripts/codemirror/addon/comment/continuecomment.js b/Upload/admin/jscripts/codemirror/addon/comment/continuecomment.js new file mode 100644 index 0000000..b11d51e --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/comment/continuecomment.js @@ -0,0 +1,85 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var modes = ["clike", "css", "javascript"]; + + for (var i = 0; i < modes.length; ++i) + CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "}); + + function continueComment(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), mode, inserts = []; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].head, token = cm.getTokenAt(pos); + if (token.type != "comment") return CodeMirror.Pass; + var modeHere = CodeMirror.innerMode(cm.getMode(), token.state).mode; + if (!mode) mode = modeHere; + else if (mode != modeHere) return CodeMirror.Pass; + + var insert = null; + if (mode.blockCommentStart && mode.blockCommentContinue) { + var end = token.string.indexOf(mode.blockCommentEnd); + var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found; + if (end != -1 && end == token.string.length - mode.blockCommentEnd.length && pos.ch >= end) { + // Comment ended, don't continue it + } else if (token.string.indexOf(mode.blockCommentStart) == 0) { + insert = full.slice(0, token.start); + if (!/^\s*$/.test(insert)) { + insert = ""; + for (var j = 0; j < token.start; ++j) insert += " "; + } + } else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 && + found + mode.blockCommentContinue.length > token.start && + /^\s*$/.test(full.slice(0, found))) { + insert = full.slice(0, found); + } + if (insert != null) insert += mode.blockCommentContinue; + } + if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) { + var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment); + if (found > -1) { + insert = line.slice(0, found); + if (/\S/.test(insert)) insert = null; + else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0]; + } + } + if (insert == null) return CodeMirror.Pass; + inserts[i] = "\n" + insert; + } + + cm.operation(function() { + for (var i = ranges.length - 1; i >= 0; i--) + cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert"); + }); + } + + function continueLineCommentEnabled(cm) { + var opt = cm.getOption("continueComments"); + if (opt && typeof opt == "object") + return opt.continueLineComment !== false; + return true; + } + + CodeMirror.defineOption("continueComments", null, function(cm, val, prev) { + if (prev && prev != CodeMirror.Init) + cm.removeKeyMap("continueComment"); + if (val) { + var key = "Enter"; + if (typeof val == "string") + key = val; + else if (typeof val == "object" && val.key) + key = val.key; + var map = {name: "continueComment"}; + map[key] = continueComment; + cm.addKeyMap(map); + } + }); +}); diff --git a/Upload/admin/jscripts/codemirror/addon/dialog/dialog-mybb.css b/Upload/admin/jscripts/codemirror/addon/dialog/dialog-mybb.css new file mode 100644 index 0000000..3fc83f2 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/dialog/dialog-mybb.css @@ -0,0 +1,32 @@ +.CodeMirror-dialog { + position: absolute; + left: 0; right: 0; + background: #1F4661; + z-index: 15; + padding: .1em .8em; + overflow: hidden; + color: #fff; +} + +.CodeMirror-dialog-top { + border-bottom: 1px solid #3E7087; + top: 0; +} + +.CodeMirror-dialog-bottom { + border-top: 1px solid #3E7087; + bottom: 0; +} + +.CodeMirror-dialog input { + border: none; + outline: none; + background: transparent; + width: 20em; + color: inherit; + font-family: monospace; +} + +.CodeMirror-dialog button { + font-size: 70%; +} diff --git a/Upload/admin/jscripts/codemirror/addon/dialog/dialog.css b/Upload/admin/jscripts/codemirror/addon/dialog/dialog.css new file mode 100644 index 0000000..2e7c0fc --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/dialog/dialog.css @@ -0,0 +1,32 @@ +.CodeMirror-dialog { + position: absolute; + left: 0; right: 0; + background: white; + z-index: 15; + padding: .1em .8em; + overflow: hidden; + color: #333; +} + +.CodeMirror-dialog-top { + border-bottom: 1px solid #eee; + top: 0; +} + +.CodeMirror-dialog-bottom { + border-top: 1px solid #eee; + bottom: 0; +} + +.CodeMirror-dialog input { + border: none; + outline: none; + background: transparent; + width: 20em; + color: inherit; + font-family: monospace; +} + +.CodeMirror-dialog button { + font-size: 70%; +} diff --git a/Upload/admin/jscripts/codemirror/addon/dialog/dialog.js b/Upload/admin/jscripts/codemirror/addon/dialog/dialog.js new file mode 100644 index 0000000..622d689 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/dialog/dialog.js @@ -0,0 +1,137 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Open simple dialogs on top of an editor. Relies on dialog.css. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + function dialogDiv(cm, template, bottom) { + var wrap = cm.getWrapperElement(); + var dialog; + dialog = wrap.appendChild(document.createElement("div")); + if (bottom) { + dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom"; + } else { + dialog.className = "CodeMirror-dialog CodeMirror-dialog-top"; + } + if (typeof template == "string") { + dialog.innerHTML = template; + } else { // Assuming it's a detached DOM element. + dialog.appendChild(template); + } + return dialog; + } + + function closeNotification(cm, newVal) { + if (cm.state.currentNotificationClose) + cm.state.currentNotificationClose(); + cm.state.currentNotificationClose = newVal; + } + + CodeMirror.defineExtension("openDialog", function(template, callback, options) { + closeNotification(this, null); + var dialog = dialogDiv(this, template, options && options.bottom); + var closed = false, me = this; + function close(newVal) { + if (typeof newVal == 'string') { + inp.value = newVal; + } else { + if (closed) return; + closed = true; + dialog.parentNode.removeChild(dialog); + } + } + var inp = dialog.getElementsByTagName("input")[0], button; + if (inp) { + if (options && options.value) inp.value = options.value; + CodeMirror.on(inp, "keydown", function(e) { + if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; } + if (e.keyCode == 13 || e.keyCode == 27) { + inp.blur(); + CodeMirror.e_stop(e); + close(); + me.focus(); + if (e.keyCode == 13) callback(inp.value); + } + }); + if (options && options.onKeyUp) { + CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);}); + } + if (options && options.value) inp.value = options.value; + inp.focus(); + CodeMirror.on(inp, "blur", close); + } else if (button = dialog.getElementsByTagName("button")[0]) { + CodeMirror.on(button, "click", function() { + close(); + me.focus(); + }); + button.focus(); + CodeMirror.on(button, "blur", close); + } + return close; + }); + + CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) { + closeNotification(this, null); + var dialog = dialogDiv(this, template, options && options.bottom); + var buttons = dialog.getElementsByTagName("button"); + var closed = false, me = this, blurring = 1; + function close() { + if (closed) return; + closed = true; + dialog.parentNode.removeChild(dialog); + me.focus(); + } + buttons[0].focus(); + for (var i = 0; i < buttons.length; ++i) { + var b = buttons[i]; + (function(callback) { + CodeMirror.on(b, "click", function(e) { + CodeMirror.e_preventDefault(e); + close(); + if (callback) callback(me); + }); + })(callbacks[i]); + CodeMirror.on(b, "blur", function() { + --blurring; + setTimeout(function() { if (blurring <= 0) close(); }, 200); + }); + CodeMirror.on(b, "focus", function() { ++blurring; }); + } + }); + + /* + * openNotification + * Opens a notification, that can be closed with an optional timer + * (default 5000ms timer) and always closes on click. + * + * If a notification is opened while another is opened, it will close the + * currently opened one and open the new one immediately. + */ + CodeMirror.defineExtension("openNotification", function(template, options) { + closeNotification(this, close); + var dialog = dialogDiv(this, template, options && options.bottom); + var duration = options && (options.duration === undefined ? 5000 : options.duration); + var closed = false, doneTimer; + + function close() { + if (closed) return; + closed = true; + clearTimeout(doneTimer); + dialog.parentNode.removeChild(dialog); + } + + CodeMirror.on(dialog, 'click', function(e) { + CodeMirror.e_preventDefault(e); + close(); + }); + if (duration) + doneTimer = setTimeout(close, options.duration); + }); +}); diff --git a/Upload/admin/jscripts/codemirror/addon/dialog/index.html b/Upload/admin/jscripts/codemirror/addon/dialog/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/dialog/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/jscripts/codemirror/addon/display/fullscreen.css b/Upload/admin/jscripts/codemirror/addon/display/fullscreen.css new file mode 100644 index 0000000..437acd8 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/display/fullscreen.css @@ -0,0 +1,6 @@ +.CodeMirror-fullscreen { + position: fixed; + top: 0; left: 0; right: 0; bottom: 0; + height: auto; + z-index: 9; +} diff --git a/Upload/admin/jscripts/codemirror/addon/display/fullscreen.js b/Upload/admin/jscripts/codemirror/addon/display/fullscreen.js new file mode 100644 index 0000000..cd3673b --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/display/fullscreen.js @@ -0,0 +1,41 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("fullScreen", false, function(cm, val, old) { + if (old == CodeMirror.Init) old = false; + if (!old == !val) return; + if (val) setFullscreen(cm); + else setNormal(cm); + }); + + function setFullscreen(cm) { + var wrap = cm.getWrapperElement(); + cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset, + width: wrap.style.width, height: wrap.style.height}; + wrap.style.width = ""; + wrap.style.height = "auto"; + wrap.className += " CodeMirror-fullscreen"; + document.documentElement.style.overflow = "hidden"; + cm.refresh(); + } + + function setNormal(cm) { + var wrap = cm.getWrapperElement(); + wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, ""); + document.documentElement.style.overflow = ""; + var info = cm.state.fullScreenRestore; + wrap.style.width = info.width; wrap.style.height = info.height; + window.scrollTo(info.scrollLeft, info.scrollTop); + cm.refresh(); + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/display/placeholder.js b/Upload/admin/jscripts/codemirror/addon/display/placeholder.js new file mode 100644 index 0000000..bb0c393 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/display/placeholder.js @@ -0,0 +1,58 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("placeholder", "", function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm.on("blur", onBlur); + cm.on("change", onChange); + onChange(cm); + } else if (!val && prev) { + cm.off("blur", onBlur); + cm.off("change", onChange); + clearPlaceholder(cm); + var wrapper = cm.getWrapperElement(); + wrapper.className = wrapper.className.replace(" CodeMirror-empty", ""); + } + + if (val && !cm.hasFocus()) onBlur(cm); + }); + + function clearPlaceholder(cm) { + if (cm.state.placeholder) { + cm.state.placeholder.parentNode.removeChild(cm.state.placeholder); + cm.state.placeholder = null; + } + } + function setPlaceholder(cm) { + clearPlaceholder(cm); + var elt = cm.state.placeholder = document.createElement("pre"); + elt.style.cssText = "height: 0; overflow: visible"; + elt.className = "CodeMirror-placeholder"; + elt.appendChild(document.createTextNode(cm.getOption("placeholder"))); + cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild); + } + + function onBlur(cm) { + if (isEmpty(cm)) setPlaceholder(cm); + } + function onChange(cm) { + var wrapper = cm.getWrapperElement(), empty = isEmpty(cm); + wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : ""); + + if (empty) setPlaceholder(cm); + else clearPlaceholder(cm); + } + + function isEmpty(cm) { + return (cm.lineCount() === 1) && (cm.getLine(0) === ""); + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/display/rulers.js b/Upload/admin/jscripts/codemirror/addon/display/rulers.js new file mode 100644 index 0000000..13185d3 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/display/rulers.js @@ -0,0 +1,64 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("rulers", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + clearRulers(cm); + cm.off("refresh", refreshRulers); + } + if (val && val.length) { + setRulers(cm); + cm.on("refresh", refreshRulers); + } + }); + + function clearRulers(cm) { + for (var i = cm.display.lineSpace.childNodes.length - 1; i >= 0; i--) { + var node = cm.display.lineSpace.childNodes[i]; + if (/(^|\s)CodeMirror-ruler($|\s)/.test(node.className)) + node.parentNode.removeChild(node); + } + } + + function setRulers(cm) { + var val = cm.getOption("rulers"); + var cw = cm.defaultCharWidth(); + var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left; + var minH = cm.display.scroller.offsetHeight + 30; + for (var i = 0; i < val.length; i++) { + var elt = document.createElement("div"); + elt.className = "CodeMirror-ruler"; + var col, cls = null, conf = val[i]; + if (typeof conf == "number") { + col = conf; + } else { + col = conf.column; + if (conf.className) elt.className += " " + conf.className; + if (conf.color) elt.style.borderColor = conf.color; + if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle; + if (conf.width) elt.style.borderLeftWidth = conf.width; + cls = val[i].className; + } + elt.style.left = (left + col * cw) + "px"; + elt.style.top = "-50px"; + elt.style.bottom = "-20px"; + elt.style.minHeight = minH + "px"; + cm.display.lineSpace.insertBefore(elt, cm.display.cursorDiv); + } + } + + function refreshRulers(cm) { + clearRulers(cm); + setRulers(cm); + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/edit/closebrackets.js b/Upload/admin/jscripts/codemirror/addon/edit/closebrackets.js new file mode 100644 index 0000000..83d4229 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/edit/closebrackets.js @@ -0,0 +1,143 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var DEFAULT_BRACKETS = "()[]{}''\"\""; + var DEFAULT_EXPLODE_ON_ENTER = "[]{}"; + var SPACE_CHAR_REGEX = /\s/; + + var Pos = CodeMirror.Pos; + + CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { + if (old != CodeMirror.Init && old) + cm.removeKeyMap("autoCloseBrackets"); + if (!val) return; + var pairs = DEFAULT_BRACKETS, explode = DEFAULT_EXPLODE_ON_ENTER; + if (typeof val == "string") pairs = val; + else if (typeof val == "object") { + if (val.pairs != null) pairs = val.pairs; + if (val.explode != null) explode = val.explode; + } + var map = buildKeymap(pairs); + if (explode) map.Enter = buildExplodeHandler(explode); + cm.addKeyMap(map); + }); + + function charsAround(cm, pos) { + var str = cm.getRange(Pos(pos.line, pos.ch - 1), + Pos(pos.line, pos.ch + 1)); + return str.length == 2 ? str : null; + } + + function buildKeymap(pairs) { + var map = { + name : "autoCloseBrackets", + Backspace: function(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + for (var i = ranges.length - 1; i >= 0; i--) { + var cur = ranges[i].head; + cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1)); + } + } + }; + var closingBrackets = ""; + for (var i = 0; i < pairs.length; i += 2) (function(left, right) { + if (left != right) closingBrackets += right; + map["'" + left + "'"] = function(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), type, next; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i], cur = range.head, curType; + if (left == "'" && cm.getTokenTypeAt(cur) == "comment") + return CodeMirror.Pass; + var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); + if (!range.empty()) + curType = "surround"; + else if (left == right && next == right) { + if (cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == left + left + left) + curType = "skipThree"; + else + curType = "skip"; + } else if (left == right && cur.ch > 1 && + cm.getRange(Pos(cur.line, cur.ch - 2), cur) == left + left && + (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != left)) + curType = "addFour"; + else if (left == right && CodeMirror.isWordChar(next)) + return CodeMirror.Pass; + else if (cm.getLine(cur.line).length == cur.ch || closingBrackets.indexOf(next) >= 0 || SPACE_CHAR_REGEX.test(next)) + curType = "both"; + else + return CodeMirror.Pass; + if (!type) type = curType; + else if (type != curType) return CodeMirror.Pass; + } + + cm.operation(function() { + if (type == "skip") { + cm.execCommand("goCharRight"); + } else if (type == "skipThree") { + for (var i = 0; i < 3; i++) + cm.execCommand("goCharRight"); + } else if (type == "surround") { + var sels = cm.getSelections(); + for (var i = 0; i < sels.length; i++) + sels[i] = left + sels[i] + right; + cm.replaceSelections(sels, "around"); + } else if (type == "both") { + cm.replaceSelection(left + right, null); + cm.execCommand("goCharLeft"); + } else if (type == "addFour") { + cm.replaceSelection(left + left + left + left, "before"); + cm.execCommand("goCharRight"); + } + }); + }; + if (left != right) map["'" + right + "'"] = function(cm) { + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (!range.empty() || + cm.getRange(range.head, Pos(range.head.line, range.head.ch + 1)) != right) + return CodeMirror.Pass; + } + cm.execCommand("goCharRight"); + }; + })(pairs.charAt(i), pairs.charAt(i + 1)); + return map; + } + + function buildExplodeHandler(pairs) { + return function(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + cm.operation(function() { + cm.replaceSelection("\n\n", null); + cm.execCommand("goCharLeft"); + ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var line = ranges[i].head.line; + cm.indentLine(line, null, true); + cm.indentLine(line + 1, null, true); + } + }); + }; + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/edit/closetag.js b/Upload/admin/jscripts/codemirror/addon/edit/closetag.js new file mode 100644 index 0000000..414498b --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/edit/closetag.js @@ -0,0 +1,141 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/** + * Tag-closer extension for CodeMirror. + * + * This extension adds an "autoCloseTags" option that can be set to + * either true to get the default behavior, or an object to further + * configure its behavior. + * + * These are supported options: + * + * `whenClosing` (default true) + * Whether to autoclose when the '/' of a closing tag is typed. + * `whenOpening` (default true) + * Whether to autoclose the tag when the final '>' of an opening + * tag is typed. + * `dontCloseTags` (default is empty tags for HTML, none for XML) + * An array of tag names that should not be autoclosed. + * `indentTags` (default is block tags for HTML, none for XML) + * An array of tag names that should, when opened, cause a + * blank line to be added inside the tag, and the blank line and + * closing line to be indented. + * + * See demos/closetag.html for a usage example. + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../fold/xml-fold")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../fold/xml-fold"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) { + if (old != CodeMirror.Init && old) + cm.removeKeyMap("autoCloseTags"); + if (!val) return; + var map = {name: "autoCloseTags"}; + if (typeof val != "object" || val.whenClosing) + map["'/'"] = function(cm) { return autoCloseSlash(cm); }; + if (typeof val != "object" || val.whenOpening) + map["'>'"] = function(cm) { return autoCloseGT(cm); }; + cm.addKeyMap(map); + }); + + var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", + "source", "track", "wbr"]; + var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4", + "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"]; + + function autoCloseGT(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), replacements = []; + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var pos = ranges[i].head, tok = cm.getTokenAt(pos); + var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; + if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass; + + var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html"; + var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); + var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); + + var tagName = state.tagName; + if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); + var lowerTagName = tagName.toLowerCase(); + // Don't process the '>' at the end of an end-tag or self-closing tag + if (!tagName || + tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) || + tok.type == "tag" && state.type == "closeTag" || + tok.string.indexOf("/") == (tok.string.length - 1) || // match something like + dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 || + closingTagExists(cm, tagName, pos, state, true)) + return CodeMirror.Pass; + + var indent = indentTags && indexOf(indentTags, lowerTagName) > -1; + replacements[i] = {indent: indent, + text: ">" + (indent ? "\n\n" : "") + "", + newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)}; + } + + for (var i = ranges.length - 1; i >= 0; i--) { + var info = replacements[i]; + cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert"); + var sel = cm.listSelections().slice(0); + sel[i] = {head: info.newPos, anchor: info.newPos}; + cm.setSelections(sel); + if (info.indent) { + cm.indentLine(info.newPos.line, null, true); + cm.indentLine(info.newPos.line + 1, null, true); + } + } + } + + function autoCloseSlash(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), replacements = []; + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var pos = ranges[i].head, tok = cm.getTokenAt(pos); + var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; + if (tok.type == "string" || tok.string.charAt(0) != "<" || + tok.start != pos.ch - 1 || inner.mode.name != "xml" || + !state.context || !state.context.tagName || + closingTagExists(cm, state.context.tagName, pos, state)) + return CodeMirror.Pass; + replacements[i] = "/" + state.context.tagName + ">"; + } + cm.replaceSelections(replacements); + } + + function indexOf(collection, elt) { + if (collection.indexOf) return collection.indexOf(elt); + for (var i = 0, e = collection.length; i < e; ++i) + if (collection[i] == elt) return i; + return -1; + } + + // If xml-fold is loaded, we use its functionality to try and verify + // whether a given tag is actually unclosed. + function closingTagExists(cm, tagName, pos, state, newTag) { + if (!CodeMirror.scanForClosingTag) return false; + var end = Math.min(cm.lastLine() + 1, pos.line + 500); + var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end); + if (!nextClose || nextClose.tag != tagName) return false; + var cx = state.context; + // If the immediate wrapping context contains onCx instances of + // the same tag, a closing tag only exists if there are at least + // that many closing tags of that type following. + for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx; + pos = nextClose.to; + for (var i = 1; i < onCx; i++) { + var next = CodeMirror.scanForClosingTag(cm, pos, null, end); + if (!next || next.tag != tagName) return false; + pos = next.to; + } + return true; + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/edit/continuelist.js b/Upload/admin/jscripts/codemirror/addon/edit/continuelist.js new file mode 100644 index 0000000..8cee761 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/edit/continuelist.js @@ -0,0 +1,38 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var listRE = /^(\s*)([*+-]|(\d+)\.)(\s+)/, + unorderedBullets = "*+-"; + + CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), replacements = []; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].head, match; + var inList = cm.getStateAfter(pos.line).list !== false; + + if (!ranges[i].empty() || !inList || !(match = cm.getLine(pos.line).match(listRE))) { + cm.execCommand("newlineAndIndent"); + return; + } + var indent = match[1], after = match[4]; + var bullet = unorderedBullets.indexOf(match[2]) >= 0 + ? match[2] + : (parseInt(match[3], 10) + 1) + "."; + + replacements[i] = "\n" + indent + bullet + after; + } + + cm.replaceSelections(replacements); + }; +}); diff --git a/Upload/admin/jscripts/codemirror/addon/edit/matchbrackets.js b/Upload/admin/jscripts/codemirror/addon/edit/matchbrackets.js new file mode 100644 index 0000000..fa1ae03 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/edit/matchbrackets.js @@ -0,0 +1,120 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var ie_lt8 = /MSIE \d/.test(navigator.userAgent) && + (document.documentMode == null || document.documentMode < 8); + + var Pos = CodeMirror.Pos; + + var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"}; + + function findMatchingBracket(cm, where, strict, config) { + var line = cm.getLineHandle(where.line), pos = where.ch - 1; + var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)]; + if (!match) return null; + var dir = match.charAt(1) == ">" ? 1 : -1; + if (strict && (dir > 0) != (pos == where.ch)) return null; + var style = cm.getTokenTypeAt(Pos(where.line, pos + 1)); + + var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config); + if (found == null) return null; + return {from: Pos(where.line, pos), to: found && found.pos, + match: found && found.ch == match.charAt(0), forward: dir > 0}; + } + + // bracketRegex is used to specify which type of bracket to scan + // should be a regexp, e.g. /[[\]]/ + // + // Note: If "where" is on an open bracket, then this bracket is ignored. + // + // Returns false when no bracket was found, null when it reached + // maxScanLines and gave up + function scanForBracket(cm, where, dir, style, config) { + var maxScanLen = (config && config.maxScanLineLength) || 10000; + var maxScanLines = (config && config.maxScanLines) || 1000; + + var stack = []; + var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/; + var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1) + : Math.max(cm.firstLine() - 1, where.line - maxScanLines); + for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) { + var line = cm.getLine(lineNo); + if (!line) continue; + var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1; + if (line.length > maxScanLen) continue; + if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0); + for (; pos != end; pos += dir) { + var ch = line.charAt(pos); + if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) { + var match = matching[ch]; + if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch); + else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch}; + else stack.pop(); + } + } + } + return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null; + } + + function matchBrackets(cm, autoclear, config) { + // Disable brace matching in long lines, since it'll cause hugely slow updates + var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000; + var marks = [], ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config); + if (match && cm.getLine(match.from.line).length <= maxHighlightLen) { + var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; + marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style})); + if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen) + marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style})); + } + } + + if (marks.length) { + // Kludge to work around the IE bug from issue #1193, where text + // input stops going to the textare whever this fires. + if (ie_lt8 && cm.state.focused) cm.display.input.focus(); + + var clear = function() { + cm.operation(function() { + for (var i = 0; i < marks.length; i++) marks[i].clear(); + }); + }; + if (autoclear) setTimeout(clear, 800); + else return clear; + } + } + + var currentlyHighlighted = null; + function doMatchBrackets(cm) { + cm.operation(function() { + if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;} + currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets); + }); + } + + CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) + cm.off("cursorActivity", doMatchBrackets); + if (val) { + cm.state.matchBrackets = typeof val == "object" ? val : {}; + cm.on("cursorActivity", doMatchBrackets); + } + }); + + CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);}); + CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){ + return findMatchingBracket(this, pos, strict, config); + }); + CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){ + return scanForBracket(this, pos, dir, style, config); + }); +}); diff --git a/Upload/admin/jscripts/codemirror/addon/edit/matchtags.js b/Upload/admin/jscripts/codemirror/addon/edit/matchtags.js new file mode 100644 index 0000000..fb1911a --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/edit/matchtags.js @@ -0,0 +1,66 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../fold/xml-fold")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../fold/xml-fold"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("matchTags", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.off("cursorActivity", doMatchTags); + cm.off("viewportChange", maybeUpdateMatch); + clear(cm); + } + if (val) { + cm.state.matchBothTags = typeof val == "object" && val.bothTags; + cm.on("cursorActivity", doMatchTags); + cm.on("viewportChange", maybeUpdateMatch); + doMatchTags(cm); + } + }); + + function clear(cm) { + if (cm.state.tagHit) cm.state.tagHit.clear(); + if (cm.state.tagOther) cm.state.tagOther.clear(); + cm.state.tagHit = cm.state.tagOther = null; + } + + function doMatchTags(cm) { + cm.state.failedTagMatch = false; + cm.operation(function() { + clear(cm); + if (cm.somethingSelected()) return; + var cur = cm.getCursor(), range = cm.getViewport(); + range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to); + var match = CodeMirror.findMatchingTag(cm, cur, range); + if (!match) return; + if (cm.state.matchBothTags) { + var hit = match.at == "open" ? match.open : match.close; + if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"}); + } + var other = match.at == "close" ? match.open : match.close; + if (other) + cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"}); + else + cm.state.failedTagMatch = true; + }); + } + + function maybeUpdateMatch(cm) { + if (cm.state.failedTagMatch) doMatchTags(cm); + } + + CodeMirror.commands.toMatchingTag = function(cm) { + var found = CodeMirror.findMatchingTag(cm, cm.getCursor()); + if (found) { + var other = found.at == "close" ? found.open : found.close; + if (other) cm.extendSelection(other.to, other.from); + } + }; +}); diff --git a/Upload/admin/jscripts/codemirror/addon/edit/trailingspace.js b/Upload/admin/jscripts/codemirror/addon/edit/trailingspace.js new file mode 100644 index 0000000..fa7b56b --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/edit/trailingspace.js @@ -0,0 +1,27 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) { + if (prev == CodeMirror.Init) prev = false; + if (prev && !val) + cm.removeOverlay("trailingspace"); + else if (!prev && val) + cm.addOverlay({ + token: function(stream) { + for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {} + if (i > stream.pos) { stream.pos = i; return null; } + stream.pos = l; + return "trailingspace"; + }, + name: "trailingspace" + }); + }); +}); diff --git a/Upload/admin/jscripts/codemirror/addon/fold/brace-fold.js b/Upload/admin/jscripts/codemirror/addon/fold/brace-fold.js new file mode 100644 index 0000000..1605f6c --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/fold/brace-fold.js @@ -0,0 +1,105 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("fold", "brace", function(cm, start) { + var line = start.line, lineText = cm.getLine(line); + var startCh, tokenType; + + function findOpening(openCh) { + for (var at = start.ch, pass = 0;;) { + var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1); + if (found == -1) { + if (pass == 1) break; + pass = 1; + at = lineText.length; + continue; + } + if (pass == 1 && found < start.ch) break; + tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)); + if (!/^(comment|string)/.test(tokenType)) return found + 1; + at = found - 1; + } + } + + var startToken = "{", endToken = "}", startCh = findOpening("{"); + if (startCh == null) { + startToken = "[", endToken = "]"; + startCh = findOpening("["); + } + + if (startCh == null) return; + var count = 1, lastLine = cm.lastLine(), end, endCh; + outer: for (var i = line; i <= lastLine; ++i) { + var text = cm.getLine(i), pos = i == line ? startCh : 0; + for (;;) { + var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); + if (nextOpen < 0) nextOpen = text.length; + if (nextClose < 0) nextClose = text.length; + pos = Math.min(nextOpen, nextClose); + if (pos == text.length) break; + if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) { + if (pos == nextOpen) ++count; + else if (!--count) { end = i; endCh = pos; break outer; } + } + ++pos; + } + } + if (end == null || line == end && endCh == startCh) return; + return {from: CodeMirror.Pos(line, startCh), + to: CodeMirror.Pos(end, endCh)}; +}); + +CodeMirror.registerHelper("fold", "import", function(cm, start) { + function hasImport(line) { + if (line < cm.firstLine() || line > cm.lastLine()) return null; + var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); + if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); + if (start.type != "keyword" || start.string != "import") return null; + // Now find closing semicolon, return its position + for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) { + var text = cm.getLine(i), semi = text.indexOf(";"); + if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)}; + } + } + + var start = start.line, has = hasImport(start), prev; + if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1)) + return null; + for (var end = has.end;;) { + var next = hasImport(end.line + 1); + if (next == null) break; + end = next.end; + } + return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end}; +}); + +CodeMirror.registerHelper("fold", "include", function(cm, start) { + function hasInclude(line) { + if (line < cm.firstLine() || line > cm.lastLine()) return null; + var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); + if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); + if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8; + } + + var start = start.line, has = hasInclude(start); + if (has == null || hasInclude(start - 1) != null) return null; + for (var end = start;;) { + var next = hasInclude(end + 1); + if (next == null) break; + ++end; + } + return {from: CodeMirror.Pos(start, has + 1), + to: cm.clipPos(CodeMirror.Pos(end))}; +}); + +}); diff --git a/Upload/admin/jscripts/codemirror/addon/fold/comment-fold.js b/Upload/admin/jscripts/codemirror/addon/fold/comment-fold.js new file mode 100644 index 0000000..b75db7e --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/fold/comment-fold.js @@ -0,0 +1,57 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerGlobalHelper("fold", "comment", function(mode) { + return mode.blockCommentStart && mode.blockCommentEnd; +}, function(cm, start) { + var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd; + if (!startToken || !endToken) return; + var line = start.line, lineText = cm.getLine(line); + + var startCh; + for (var at = start.ch, pass = 0;;) { + var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1); + if (found == -1) { + if (pass == 1) return; + pass = 1; + at = lineText.length; + continue; + } + if (pass == 1 && found < start.ch) return; + if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)))) { + startCh = found + startToken.length; + break; + } + at = found - 1; + } + + var depth = 1, lastLine = cm.lastLine(), end, endCh; + outer: for (var i = line; i <= lastLine; ++i) { + var text = cm.getLine(i), pos = i == line ? startCh : 0; + for (;;) { + var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); + if (nextOpen < 0) nextOpen = text.length; + if (nextClose < 0) nextClose = text.length; + pos = Math.min(nextOpen, nextClose); + if (pos == text.length) break; + if (pos == nextOpen) ++depth; + else if (!--depth) { end = i; endCh = pos; break outer; } + ++pos; + } + } + if (end == null || line == end && endCh == startCh) return; + return {from: CodeMirror.Pos(line, startCh), + to: CodeMirror.Pos(end, endCh)}; +}); + +}); diff --git a/Upload/admin/jscripts/codemirror/addon/fold/foldcode.js b/Upload/admin/jscripts/codemirror/addon/fold/foldcode.js new file mode 100644 index 0000000..3abeb83 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/fold/foldcode.js @@ -0,0 +1,145 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function doFold(cm, pos, options, force) { + if (options && options.call) { + var finder = options; + options = null; + } else { + var finder = getOption(cm, options, "rangeFinder"); + } + if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0); + var minSize = getOption(cm, options, "minFoldSize"); + + function getRange(allowFolded) { + var range = finder(cm, pos); + if (!range || range.to.line - range.from.line < minSize) return null; + var marks = cm.findMarksAt(range.from); + for (var i = 0; i < marks.length; ++i) { + if (marks[i].__isFold && force !== "fold") { + if (!allowFolded) return null; + range.cleared = true; + marks[i].clear(); + } + } + return range; + } + + var range = getRange(true); + if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) { + pos = CodeMirror.Pos(pos.line - 1, 0); + range = getRange(false); + } + if (!range || range.cleared || force === "unfold") return; + + var myWidget = makeWidget(cm, options); + CodeMirror.on(myWidget, "mousedown", function(e) { + myRange.clear(); + CodeMirror.e_preventDefault(e); + }); + var myRange = cm.markText(range.from, range.to, { + replacedWith: myWidget, + clearOnEnter: true, + __isFold: true + }); + myRange.on("clear", function(from, to) { + CodeMirror.signal(cm, "unfold", cm, from, to); + }); + CodeMirror.signal(cm, "fold", cm, range.from, range.to); + } + + function makeWidget(cm, options) { + var widget = getOption(cm, options, "widget"); + if (typeof widget == "string") { + var text = document.createTextNode(widget); + widget = document.createElement("span"); + widget.appendChild(text); + widget.className = "CodeMirror-foldmarker"; + } + return widget; + } + + // Clumsy backwards-compatible interface + CodeMirror.newFoldFunction = function(rangeFinder, widget) { + return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); }; + }; + + // New-style interface + CodeMirror.defineExtension("foldCode", function(pos, options, force) { + doFold(this, pos, options, force); + }); + + CodeMirror.defineExtension("isFolded", function(pos) { + var marks = this.findMarksAt(pos); + for (var i = 0; i < marks.length; ++i) + if (marks[i].__isFold) return true; + }); + + CodeMirror.commands.toggleFold = function(cm) { + cm.foldCode(cm.getCursor()); + }; + CodeMirror.commands.fold = function(cm) { + cm.foldCode(cm.getCursor(), null, "fold"); + }; + CodeMirror.commands.unfold = function(cm) { + cm.foldCode(cm.getCursor(), null, "unfold"); + }; + CodeMirror.commands.foldAll = function(cm) { + cm.operation(function() { + for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) + cm.foldCode(CodeMirror.Pos(i, 0), null, "fold"); + }); + }; + CodeMirror.commands.unfoldAll = function(cm) { + cm.operation(function() { + for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) + cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold"); + }); + }; + + CodeMirror.registerHelper("fold", "combine", function() { + var funcs = Array.prototype.slice.call(arguments, 0); + return function(cm, start) { + for (var i = 0; i < funcs.length; ++i) { + var found = funcs[i](cm, start); + if (found) return found; + } + }; + }); + + CodeMirror.registerHelper("fold", "auto", function(cm, start) { + var helpers = cm.getHelpers(start, "fold"); + for (var i = 0; i < helpers.length; i++) { + var cur = helpers[i](cm, start); + if (cur) return cur; + } + }); + + var defaultOptions = { + rangeFinder: CodeMirror.fold.auto, + widget: "\u2194", + minFoldSize: 0, + scanUp: false + }; + + CodeMirror.defineOption("foldOptions", null); + + function getOption(cm, options, name) { + if (options && options[name] !== undefined) + return options[name]; + var editorOptions = cm.options.foldOptions; + if (editorOptions && editorOptions[name] !== undefined) + return editorOptions[name]; + return defaultOptions[name]; + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/fold/foldgutter.css b/Upload/admin/jscripts/codemirror/addon/fold/foldgutter.css new file mode 100644 index 0000000..ad19ae2 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/fold/foldgutter.css @@ -0,0 +1,20 @@ +.CodeMirror-foldmarker { + color: blue; + text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px; + font-family: arial; + line-height: .3; + cursor: pointer; +} +.CodeMirror-foldgutter { + width: .7em; +} +.CodeMirror-foldgutter-open, +.CodeMirror-foldgutter-folded { + cursor: pointer; +} +.CodeMirror-foldgutter-open:after { + content: "\25BE"; +} +.CodeMirror-foldgutter-folded:after { + content: "\25B8"; +} diff --git a/Upload/admin/jscripts/codemirror/addon/fold/foldgutter.js b/Upload/admin/jscripts/codemirror/addon/fold/foldgutter.js new file mode 100644 index 0000000..bd31ec4 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/fold/foldgutter.js @@ -0,0 +1,134 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./foldcode")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./foldcode"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("foldGutter", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.clearGutter(cm.state.foldGutter.options.gutter); + cm.state.foldGutter = null; + cm.off("gutterClick", onGutterClick); + cm.off("change", onChange); + cm.off("viewportChange", onViewportChange); + cm.off("fold", onFold); + cm.off("unfold", onFold); + cm.off("swapDoc", updateInViewport); + } + if (val) { + cm.state.foldGutter = new State(parseOptions(val)); + updateInViewport(cm); + cm.on("gutterClick", onGutterClick); + cm.on("change", onChange); + cm.on("viewportChange", onViewportChange); + cm.on("fold", onFold); + cm.on("unfold", onFold); + cm.on("swapDoc", updateInViewport); + } + }); + + var Pos = CodeMirror.Pos; + + function State(options) { + this.options = options; + this.from = this.to = 0; + } + + function parseOptions(opts) { + if (opts === true) opts = {}; + if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter"; + if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open"; + if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded"; + return opts; + } + + function isFolded(cm, line) { + var marks = cm.findMarksAt(Pos(line)); + for (var i = 0; i < marks.length; ++i) + if (marks[i].__isFold && marks[i].find().from.line == line) return true; + } + + function marker(spec) { + if (typeof spec == "string") { + var elt = document.createElement("div"); + elt.className = spec + " CodeMirror-guttermarker-subtle"; + return elt; + } else { + return spec.cloneNode(true); + } + } + + function updateFoldInfo(cm, from, to) { + var opts = cm.state.foldGutter.options, cur = from; + cm.eachLine(from, to, function(line) { + var mark = null; + if (isFolded(cm, cur)) { + mark = marker(opts.indicatorFolded); + } else { + var pos = Pos(cur, 0), func = opts.rangeFinder || CodeMirror.fold.auto; + var range = func && func(cm, pos); + if (range && range.from.line + 1 < range.to.line) + mark = marker(opts.indicatorOpen); + } + cm.setGutterMarker(line, opts.gutter, mark); + ++cur; + }); + } + + function updateInViewport(cm) { + var vp = cm.getViewport(), state = cm.state.foldGutter; + if (!state) return; + cm.operation(function() { + updateFoldInfo(cm, vp.from, vp.to); + }); + state.from = vp.from; state.to = vp.to; + } + + function onGutterClick(cm, line, gutter) { + var opts = cm.state.foldGutter.options; + if (gutter != opts.gutter) return; + cm.foldCode(Pos(line, 0), opts.rangeFinder); + } + + function onChange(cm) { + var state = cm.state.foldGutter, opts = cm.state.foldGutter.options; + state.from = state.to = 0; + clearTimeout(state.changeUpdate); + state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600); + } + + function onViewportChange(cm) { + var state = cm.state.foldGutter, opts = cm.state.foldGutter.options; + clearTimeout(state.changeUpdate); + state.changeUpdate = setTimeout(function() { + var vp = cm.getViewport(); + if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { + updateInViewport(cm); + } else { + cm.operation(function() { + if (vp.from < state.from) { + updateFoldInfo(cm, vp.from, state.from); + state.from = vp.from; + } + if (vp.to > state.to) { + updateFoldInfo(cm, state.to, vp.to); + state.to = vp.to; + } + }); + } + }, opts.updateViewportTimeSpan || 400); + } + + function onFold(cm, from) { + var state = cm.state.foldGutter, line = from.line; + if (line >= state.from && line < state.to) + updateFoldInfo(cm, line, line + 1); + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/fold/indent-fold.js b/Upload/admin/jscripts/codemirror/addon/fold/indent-fold.js new file mode 100644 index 0000000..e29f15e --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/fold/indent-fold.js @@ -0,0 +1,44 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("fold", "indent", function(cm, start) { + var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line); + if (!/\S/.test(firstLine)) return; + var getIndent = function(line) { + return CodeMirror.countColumn(line, null, tabSize); + }; + var myIndent = getIndent(firstLine); + var lastLineInFold = null; + // Go through lines until we find a line that definitely doesn't belong in + // the block we're folding, or to the end. + for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) { + var curLine = cm.getLine(i); + var curIndent = getIndent(curLine); + if (curIndent > myIndent) { + // Lines with a greater indent are considered part of the block. + lastLineInFold = i; + } else if (!/\S/.test(curLine)) { + // Empty lines might be breaks within the block we're trying to fold. + } else { + // A non-empty line at an indent equal to or less than ours marks the + // start of another block. + break; + } + } + if (lastLineInFold) return { + from: CodeMirror.Pos(start.line, firstLine.length), + to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length) + }; +}); + +}); diff --git a/Upload/admin/jscripts/codemirror/addon/fold/markdown-fold.js b/Upload/admin/jscripts/codemirror/addon/fold/markdown-fold.js new file mode 100644 index 0000000..ce84c94 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/fold/markdown-fold.js @@ -0,0 +1,49 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("fold", "markdown", function(cm, start) { + var maxDepth = 100; + + function isHeader(lineNo) { + var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0)); + return tokentype && /\bheader\b/.test(tokentype); + } + + function headerLevel(lineNo, line, nextLine) { + var match = line && line.match(/^#+/); + if (match && isHeader(lineNo)) return match[0].length; + match = nextLine && nextLine.match(/^[=\-]+\s*$/); + if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2; + return maxDepth; + } + + var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1); + var level = headerLevel(start.line, firstLine, nextLine); + if (level === maxDepth) return undefined; + + var lastLineNo = cm.lastLine(); + var end = start.line, nextNextLine = cm.getLine(end + 2); + while (end < lastLineNo) { + if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break; + ++end; + nextLine = nextNextLine; + nextNextLine = cm.getLine(end + 2); + } + + return { + from: CodeMirror.Pos(start.line, firstLine.length), + to: CodeMirror.Pos(end, cm.getLine(end).length) + }; +}); + +}); diff --git a/Upload/admin/jscripts/codemirror/addon/fold/xml-fold.js b/Upload/admin/jscripts/codemirror/addon/fold/xml-fold.js new file mode 100644 index 0000000..a45da58 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/fold/xml-fold.js @@ -0,0 +1,181 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var Pos = CodeMirror.Pos; + function cmp(a, b) { return a.line - b.line || a.ch - b.ch; } + + var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; + var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; + var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); + + function Iter(cm, line, ch, range) { + this.line = line; this.ch = ch; + this.cm = cm; this.text = cm.getLine(line); + this.min = range ? range.from : cm.firstLine(); + this.max = range ? range.to - 1 : cm.lastLine(); + } + + function tagAt(iter, ch) { + var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch)); + return type && /\btag\b/.test(type); + } + + function nextLine(iter) { + if (iter.line >= iter.max) return; + iter.ch = 0; + iter.text = iter.cm.getLine(++iter.line); + return true; + } + function prevLine(iter) { + if (iter.line <= iter.min) return; + iter.text = iter.cm.getLine(--iter.line); + iter.ch = iter.text.length; + return true; + } + + function toTagEnd(iter) { + for (;;) { + var gt = iter.text.indexOf(">", iter.ch); + if (gt == -1) { if (nextLine(iter)) continue; else return; } + if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; } + var lastSlash = iter.text.lastIndexOf("/", gt); + var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); + iter.ch = gt + 1; + return selfClose ? "selfClose" : "regular"; + } + } + function toTagStart(iter) { + for (;;) { + var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1; + if (lt == -1) { if (prevLine(iter)) continue; else return; } + if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; } + xmlTagStart.lastIndex = lt; + iter.ch = lt; + var match = xmlTagStart.exec(iter.text); + if (match && match.index == lt) return match; + } + } + + function toNextTag(iter) { + for (;;) { + xmlTagStart.lastIndex = iter.ch; + var found = xmlTagStart.exec(iter.text); + if (!found) { if (nextLine(iter)) continue; else return; } + if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; } + iter.ch = found.index + found[0].length; + return found; + } + } + function toPrevTag(iter) { + for (;;) { + var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1; + if (gt == -1) { if (prevLine(iter)) continue; else return; } + if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; } + var lastSlash = iter.text.lastIndexOf("/", gt); + var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); + iter.ch = gt + 1; + return selfClose ? "selfClose" : "regular"; + } + } + + function findMatchingClose(iter, tag) { + var stack = []; + for (;;) { + var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0); + if (!next || !(end = toTagEnd(iter))) return; + if (end == "selfClose") continue; + if (next[1]) { // closing tag + for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) { + stack.length = i; + break; + } + if (i < 0 && (!tag || tag == next[2])) return { + tag: next[2], + from: Pos(startLine, startCh), + to: Pos(iter.line, iter.ch) + }; + } else { // opening tag + stack.push(next[2]); + } + } + } + function findMatchingOpen(iter, tag) { + var stack = []; + for (;;) { + var prev = toPrevTag(iter); + if (!prev) return; + if (prev == "selfClose") { toTagStart(iter); continue; } + var endLine = iter.line, endCh = iter.ch; + var start = toTagStart(iter); + if (!start) return; + if (start[1]) { // closing tag + stack.push(start[2]); + } else { // opening tag + for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) { + stack.length = i; + break; + } + if (i < 0 && (!tag || tag == start[2])) return { + tag: start[2], + from: Pos(iter.line, iter.ch), + to: Pos(endLine, endCh) + }; + } + } + } + + CodeMirror.registerHelper("fold", "xml", function(cm, start) { + var iter = new Iter(cm, start.line, 0); + for (;;) { + var openTag = toNextTag(iter), end; + if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return; + if (!openTag[1] && end != "selfClose") { + var start = Pos(iter.line, iter.ch); + var close = findMatchingClose(iter, openTag[2]); + return close && {from: start, to: close.from}; + } + } + }); + CodeMirror.findMatchingTag = function(cm, pos, range) { + var iter = new Iter(cm, pos.line, pos.ch, range); + if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return; + var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch); + var start = end && toTagStart(iter); + if (!end || end == "selfClose" || !start || cmp(iter, pos) > 0) return; + var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]}; + + if (start[1]) { // closing tag + return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"}; + } else { // opening tag + iter = new Iter(cm, to.line, to.ch, range); + return {open: here, close: findMatchingClose(iter, start[2]), at: "open"}; + } + }; + + CodeMirror.findEnclosingTag = function(cm, pos, range) { + var iter = new Iter(cm, pos.line, pos.ch, range); + for (;;) { + var open = findMatchingOpen(iter); + if (!open) break; + var forward = new Iter(cm, pos.line, pos.ch, range); + var close = findMatchingClose(forward, open.tag); + if (close) return {open: open, close: close}; + } + }; + + // Used by addon/edit/closetag.js + CodeMirror.scanForClosingTag = function(cm, pos, name, end) { + var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null); + return findMatchingClose(iter, name); + }; +}); diff --git a/Upload/admin/jscripts/codemirror/addon/hint/anyword-hint.js b/Upload/admin/jscripts/codemirror/addon/hint/anyword-hint.js new file mode 100644 index 0000000..be72e2b --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/hint/anyword-hint.js @@ -0,0 +1,42 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var WORD = /[\w$]+/, RANGE = 500; + + CodeMirror.registerHelper("hint", "anyword", function(editor, options) { + var word = options && options.word || WORD; + var range = options && options.range || RANGE; + var cur = editor.getCursor(), curLine = editor.getLine(cur.line); + var start = cur.ch, end = start; + while (end < curLine.length && word.test(curLine.charAt(end))) ++end; + while (start && word.test(curLine.charAt(start - 1))) --start; + var curWord = start != end && curLine.slice(start, end); + + var list = [], seen = {}; + var re = new RegExp(word.source, "g"); + for (var dir = -1; dir <= 1; dir += 2) { + var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir; + for (; line != endLine; line += dir) { + var text = editor.getLine(line), m; + while (m = re.exec(text)) { + if (line == cur.line && m[0] === curWord) continue; + if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) { + seen[m[0]] = true; + list.push(m[0]); + } + } + } + } + return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; + }); +}); diff --git a/Upload/admin/jscripts/codemirror/addon/hint/css-hint.js b/Upload/admin/jscripts/codemirror/addon/hint/css-hint.js new file mode 100644 index 0000000..3300f4b --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/hint/css-hint.js @@ -0,0 +1,56 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../../mode/css/css")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../../mode/css/css"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var pseudoClasses = {link: 1, visited: 1, active: 1, hover: 1, focus: 1, + "first-letter": 1, "first-line": 1, "first-child": 1, + before: 1, after: 1, lang: 1}; + + CodeMirror.registerHelper("hint", "css", function(cm) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var inner = CodeMirror.innerMode(cm.getMode(), token.state); + if (inner.mode.name != "css") return; + + var word = token.string, start = token.start, end = token.end; + if (/[^\w$_-]/.test(word)) { + word = ""; start = end = cur.ch; + } + + var spec = CodeMirror.resolveMode("text/css"); + + var result = []; + function add(keywords) { + for (var name in keywords) + if (!word || name.lastIndexOf(word, 0) == 0) + result.push(name); + } + + var st = inner.state.state; + if (st == "pseudo" || token.type == "variable-3") { + add(pseudoClasses); + } else if (st == "block" || st == "maybeprop") { + add(spec.propertyKeywords); + } else if (st == "prop" || st == "parens" || st == "at" || st == "params") { + add(spec.valueKeywords); + add(spec.colorKeywords); + } else if (st == "media" || st == "media_parens") { + add(spec.mediaTypes); + add(spec.mediaFeatures); + } + + if (result.length) return { + list: result, + from: CodeMirror.Pos(cur.line, start), + to: CodeMirror.Pos(cur.line, end) + }; + }); +}); diff --git a/Upload/admin/jscripts/codemirror/addon/hint/html-hint.js b/Upload/admin/jscripts/codemirror/addon/hint/html-hint.js new file mode 100644 index 0000000..addd9b7 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/hint/html-hint.js @@ -0,0 +1,348 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var langs = "ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu".split(" "); + var targets = ["_blank", "_self", "_top", "_parent"]; + var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"]; + var methods = ["get", "post", "put", "delete"]; + var encs = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]; + var media = ["all", "screen", "print", "embossed", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "speech", + "3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait", + "orientation:landscape", "device-height: [X]", "device-width: [X]"]; + var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags + + var data = { + a: { + attrs: { + href: null, ping: null, type: null, + media: media, + target: targets, + hreflang: langs + } + }, + abbr: s, + acronym: s, + address: s, + applet: s, + area: { + attrs: { + alt: null, coords: null, href: null, target: null, ping: null, + media: media, hreflang: langs, type: null, + shape: ["default", "rect", "circle", "poly"] + } + }, + article: s, + aside: s, + audio: { + attrs: { + src: null, mediagroup: null, + crossorigin: ["anonymous", "use-credentials"], + preload: ["none", "metadata", "auto"], + autoplay: ["", "autoplay"], + loop: ["", "loop"], + controls: ["", "controls"] + } + }, + b: s, + base: { attrs: { href: null, target: targets } }, + basefont: s, + bdi: s, + bdo: s, + big: s, + blockquote: { attrs: { cite: null } }, + body: s, + br: s, + button: { + attrs: { + form: null, formaction: null, name: null, value: null, + autofocus: ["", "autofocus"], + disabled: ["", "autofocus"], + formenctype: encs, + formmethod: methods, + formnovalidate: ["", "novalidate"], + formtarget: targets, + type: ["submit", "reset", "button"] + } + }, + canvas: { attrs: { width: null, height: null } }, + caption: s, + center: s, + cite: s, + code: s, + col: { attrs: { span: null } }, + colgroup: { attrs: { span: null } }, + command: { + attrs: { + type: ["command", "checkbox", "radio"], + label: null, icon: null, radiogroup: null, command: null, title: null, + disabled: ["", "disabled"], + checked: ["", "checked"] + } + }, + data: { attrs: { value: null } }, + datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } }, + datalist: { attrs: { data: null } }, + dd: s, + del: { attrs: { cite: null, datetime: null } }, + details: { attrs: { open: ["", "open"] } }, + dfn: s, + dir: s, + div: s, + dl: s, + dt: s, + em: s, + embed: { attrs: { src: null, type: null, width: null, height: null } }, + eventsource: { attrs: { src: null } }, + fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } }, + figcaption: s, + figure: s, + font: s, + footer: s, + form: { + attrs: { + action: null, name: null, + "accept-charset": charsets, + autocomplete: ["on", "off"], + enctype: encs, + method: methods, + novalidate: ["", "novalidate"], + target: targets + } + }, + frame: s, + frameset: s, + h1: s, h2: s, h3: s, h4: s, h5: s, h6: s, + head: { + attrs: {}, + children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"] + }, + header: s, + hgroup: s, + hr: s, + html: { + attrs: { manifest: null }, + children: ["head", "body"] + }, + i: s, + iframe: { + attrs: { + src: null, srcdoc: null, name: null, width: null, height: null, + sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"], + seamless: ["", "seamless"] + } + }, + img: { + attrs: { + alt: null, src: null, ismap: null, usemap: null, width: null, height: null, + crossorigin: ["anonymous", "use-credentials"] + } + }, + input: { + attrs: { + alt: null, dirname: null, form: null, formaction: null, + height: null, list: null, max: null, maxlength: null, min: null, + name: null, pattern: null, placeholder: null, size: null, src: null, + step: null, value: null, width: null, + accept: ["audio/*", "video/*", "image/*"], + autocomplete: ["on", "off"], + autofocus: ["", "autofocus"], + checked: ["", "checked"], + disabled: ["", "disabled"], + formenctype: encs, + formmethod: methods, + formnovalidate: ["", "novalidate"], + formtarget: targets, + multiple: ["", "multiple"], + readonly: ["", "readonly"], + required: ["", "required"], + type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month", + "week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio", + "file", "submit", "image", "reset", "button"] + } + }, + ins: { attrs: { cite: null, datetime: null } }, + kbd: s, + keygen: { + attrs: { + challenge: null, form: null, name: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + keytype: ["RSA"] + } + }, + label: { attrs: { "for": null, form: null } }, + legend: s, + li: { attrs: { value: null } }, + link: { + attrs: { + href: null, type: null, + hreflang: langs, + media: media, + sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"] + } + }, + map: { attrs: { name: null } }, + mark: s, + menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } }, + meta: { + attrs: { + content: null, + charset: charsets, + name: ["viewport", "application-name", "author", "description", "generator", "keywords"], + "http-equiv": ["content-language", "content-type", "default-style", "refresh"] + } + }, + meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } }, + nav: s, + noframes: s, + noscript: s, + object: { + attrs: { + data: null, type: null, name: null, usemap: null, form: null, width: null, height: null, + typemustmatch: ["", "typemustmatch"] + } + }, + ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } }, + optgroup: { attrs: { disabled: ["", "disabled"], label: null } }, + option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } }, + output: { attrs: { "for": null, form: null, name: null } }, + p: s, + param: { attrs: { name: null, value: null } }, + pre: s, + progress: { attrs: { value: null, max: null } }, + q: { attrs: { cite: null } }, + rp: s, + rt: s, + ruby: s, + s: s, + samp: s, + script: { + attrs: { + type: ["text/javascript"], + src: null, + async: ["", "async"], + defer: ["", "defer"], + charset: charsets + } + }, + section: s, + select: { + attrs: { + form: null, name: null, size: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + multiple: ["", "multiple"] + } + }, + small: s, + source: { attrs: { src: null, type: null, media: null } }, + span: s, + strike: s, + strong: s, + style: { + attrs: { + type: ["text/css"], + media: media, + scoped: null + } + }, + sub: s, + summary: s, + sup: s, + table: s, + tbody: s, + td: { attrs: { colspan: null, rowspan: null, headers: null } }, + textarea: { + attrs: { + dirname: null, form: null, maxlength: null, name: null, placeholder: null, + rows: null, cols: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + readonly: ["", "readonly"], + required: ["", "required"], + wrap: ["soft", "hard"] + } + }, + tfoot: s, + th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } }, + thead: s, + time: { attrs: { datetime: null } }, + title: s, + tr: s, + track: { + attrs: { + src: null, label: null, "default": null, + kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"], + srclang: langs + } + }, + tt: s, + u: s, + ul: s, + "var": s, + video: { + attrs: { + src: null, poster: null, width: null, height: null, + crossorigin: ["anonymous", "use-credentials"], + preload: ["auto", "metadata", "none"], + autoplay: ["", "autoplay"], + mediagroup: ["movie"], + muted: ["", "muted"], + controls: ["", "controls"] + } + }, + wbr: s + }; + + var globalAttrs = { + accesskey: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], + "class": null, + contenteditable: ["true", "false"], + contextmenu: null, + dir: ["ltr", "rtl", "auto"], + draggable: ["true", "false", "auto"], + dropzone: ["copy", "move", "link", "string:", "file:"], + hidden: ["hidden"], + id: null, + inert: ["inert"], + itemid: null, + itemprop: null, + itemref: null, + itemscope: ["itemscope"], + itemtype: null, + lang: ["en", "es"], + spellcheck: ["true", "false"], + style: null, + tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"], + title: null, + translate: ["yes", "no"], + onclick: null, + rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"] + }; + function populate(obj) { + for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr)) + obj.attrs[attr] = globalAttrs[attr]; + } + + populate(s); + for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s) + populate(data[tag]); + + CodeMirror.htmlSchema = data; + function htmlHint(cm, options) { + var local = {schemaInfo: data}; + if (options) for (var opt in options) local[opt] = options[opt]; + return CodeMirror.hint.xml(cm, local); + } + CodeMirror.registerHelper("hint", "html", htmlHint); +}); diff --git a/Upload/admin/jscripts/codemirror/addon/hint/javascript-hint.js b/Upload/admin/jscripts/codemirror/addon/hint/javascript-hint.js new file mode 100644 index 0000000..c729246 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/hint/javascript-hint.js @@ -0,0 +1,141 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var Pos = CodeMirror.Pos; + + function forEach(arr, f) { + for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); + } + + function arrayContains(arr, item) { + if (!Array.prototype.indexOf) { + var i = arr.length; + while (i--) { + if (arr[i] === item) { + return true; + } + } + return false; + } + return arr.indexOf(item) != -1; + } + + function scriptHint(editor, keywords, getToken, options) { + // Find the token at the cursor + var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token; + if (/\b(?:string|comment)\b/.test(token.type)) return; + token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; + + // If it's not a 'word-style' token, ignore the token. + if (!/^[\w$_]*$/.test(token.string)) { + token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state, + type: token.string == "." ? "property" : null}; + } + // If it is a property, find out what it is a property of. + while (tprop.type == "property") { + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (tprop.string != ".") return; + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (!context) var context = []; + context.push(tprop); + } + return {list: getCompletions(token, context, keywords, options), + from: Pos(cur.line, token.start), + to: Pos(cur.line, token.end)}; + } + + function javascriptHint(editor, options) { + return scriptHint(editor, javascriptKeywords, + function (e, cur) {return e.getTokenAt(cur);}, + options); + }; + CodeMirror.registerHelper("hint", "javascript", javascriptHint); + + function getCoffeeScriptToken(editor, cur) { + // This getToken, it is for coffeescript, imitates the behavior of + // getTokenAt method in javascript.js, that is, returning "property" + // type and treat "." as indepenent token. + var token = editor.getTokenAt(cur); + if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { + token.end = token.start; + token.string = '.'; + token.type = "property"; + } + else if (/^\.[\w$_]*$/.test(token.string)) { + token.type = "property"; + token.start++; + token.string = token.string.replace(/\./, ''); + } + return token; + } + + function coffeescriptHint(editor, options) { + return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); + } + CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint); + + var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + + "toUpperCase toLowerCase split concat match replace search").split(" "); + var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + + "lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); + var funcProps = "prototype apply call bind".split(" "); + var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " + + "if in instanceof new null return switch throw true try typeof var void while with").split(" "); + var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + + "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); + + function getCompletions(token, context, keywords, options) { + var found = [], start = token.string; + function maybeAdd(str) { + if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str); + } + function gatherCompletions(obj) { + if (typeof obj == "string") forEach(stringProps, maybeAdd); + else if (obj instanceof Array) forEach(arrayProps, maybeAdd); + else if (obj instanceof Function) forEach(funcProps, maybeAdd); + for (var name in obj) maybeAdd(name); + } + + if (context && context.length) { + // If this is a property, see if it belongs to some object we can + // find in the current environment. + var obj = context.pop(), base; + if (obj.type && obj.type.indexOf("variable") === 0) { + if (options && options.additionalContext) + base = options.additionalContext[obj.string]; + if (!options || options.useGlobalScope !== false) + base = base || window[obj.string]; + } else if (obj.type == "string") { + base = ""; + } else if (obj.type == "atom") { + base = 1; + } else if (obj.type == "function") { + if (window.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && + (typeof window.jQuery == 'function')) + base = window.jQuery(); + else if (window._ != null && (obj.string == '_') && (typeof window._ == 'function')) + base = window._(); + } + while (base != null && context.length) + base = base[context.pop().string]; + if (base != null) gatherCompletions(base); + } else { + // If not, just look in the window object and any local scope + // (reading into JS mode internals to get at the local and global variables) + for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); + for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); + if (!options || options.useGlobalScope !== false) + gatherCompletions(window); + forEach(keywords, maybeAdd); + } + return found; + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/hint/python-hint.js b/Upload/admin/jscripts/codemirror/addon/hint/python-hint.js new file mode 100644 index 0000000..1b97f6a --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/hint/python-hint.js @@ -0,0 +1,102 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function forEach(arr, f) { + for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); + } + + function arrayContains(arr, item) { + if (!Array.prototype.indexOf) { + var i = arr.length; + while (i--) { + if (arr[i] === item) { + return true; + } + } + return false; + } + return arr.indexOf(item) != -1; + } + + function scriptHint(editor, _keywords, getToken) { + // Find the token at the cursor + var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token; + // If it's not a 'word-style' token, ignore the token. + + if (!/^[\w$_]*$/.test(token.string)) { + token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state, + className: token.string == ":" ? "python-type" : null}; + } + + if (!context) var context = []; + context.push(tprop); + + var completionList = getCompletions(token, context); + completionList = completionList.sort(); + + return {list: completionList, + from: CodeMirror.Pos(cur.line, token.start), + to: CodeMirror.Pos(cur.line, token.end)}; + } + + function pythonHint(editor) { + return scriptHint(editor, pythonKeywordsU, function (e, cur) {return e.getTokenAt(cur);}); + } + CodeMirror.registerHelper("hint", "python", pythonHint); + + var pythonKeywords = "and del from not while as elif global or with assert else if pass yield" ++ "break except import print class exec in raise continue finally is return def for lambda try"; + var pythonKeywordsL = pythonKeywords.split(" "); + var pythonKeywordsU = pythonKeywords.toUpperCase().split(" "); + + var pythonBuiltins = "abs divmod input open staticmethod all enumerate int ord str " ++ "any eval isinstance pow sum basestring execfile issubclass print super" ++ "bin file iter property tuple bool filter len range type" ++ "bytearray float list raw_input unichr callable format locals reduce unicode" ++ "chr frozenset long reload vars classmethod getattr map repr xrange" ++ "cmp globals max reversed zip compile hasattr memoryview round __import__" ++ "complex hash min set apply delattr help next setattr buffer" ++ "dict hex object slice coerce dir id oct sorted intern "; + var pythonBuiltinsL = pythonBuiltins.split(" ").join("() ").split(" "); + var pythonBuiltinsU = pythonBuiltins.toUpperCase().split(" ").join("() ").split(" "); + + function getCompletions(token, context) { + var found = [], start = token.string; + function maybeAdd(str) { + if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str); + } + + function gatherCompletions(_obj) { + forEach(pythonBuiltinsL, maybeAdd); + forEach(pythonBuiltinsU, maybeAdd); + forEach(pythonKeywordsL, maybeAdd); + forEach(pythonKeywordsU, maybeAdd); + } + + if (context) { + // If this is a property, see if it belongs to some object we can + // find in the current environment. + var obj = context.pop(), base; + + if (obj.type == "variable") + base = obj.string; + else if(obj.type == "variable-3") + base = ":" + obj.string; + + while (base != null && context.length) + base = base[context.pop().string]; + if (base != null) gatherCompletions(base); + } + return found; + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/hint/show-hint.css b/Upload/admin/jscripts/codemirror/addon/hint/show-hint.css new file mode 100644 index 0000000..8a4ff05 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/hint/show-hint.css @@ -0,0 +1,38 @@ +.CodeMirror-hints { + position: absolute; + z-index: 10; + overflow: hidden; + list-style: none; + + margin: 0; + padding: 2px; + + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + box-shadow: 2px 3px 5px rgba(0,0,0,.2); + border-radius: 3px; + border: 1px solid silver; + + background: white; + font-size: 90%; + font-family: monospace; + + max-height: 20em; + overflow-y: auto; +} + +.CodeMirror-hint { + margin: 0; + padding: 0 4px; + border-radius: 2px; + max-width: 19em; + overflow: hidden; + white-space: pre; + color: black; + cursor: pointer; +} + +.CodeMirror-hint-active { + background: #08f; + color: white; +} diff --git a/Upload/admin/jscripts/codemirror/addon/hint/show-hint.js b/Upload/admin/jscripts/codemirror/addon/hint/show-hint.js new file mode 100644 index 0000000..f43ca00 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/hint/show-hint.js @@ -0,0 +1,389 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var HINT_ELEMENT_CLASS = "CodeMirror-hint"; + var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; + + // This is the old interface, kept around for now to stay + // backwards-compatible. + CodeMirror.showHint = function(cm, getHints, options) { + if (!getHints) return cm.showHint(options); + if (options && options.async) getHints.async = true; + var newOpts = {hint: getHints}; + if (options) for (var prop in options) newOpts[prop] = options[prop]; + return cm.showHint(newOpts); + }; + + CodeMirror.defineExtension("showHint", function(options) { + // We want a single cursor position. + if (this.listSelections().length > 1 || this.somethingSelected()) return; + + if (this.state.completionActive) this.state.completionActive.close(); + var completion = this.state.completionActive = new Completion(this, options); + var getHints = completion.options.hint; + if (!getHints) return; + + CodeMirror.signal(this, "startCompletion", this); + if (getHints.async) + getHints(this, function(hints) { completion.showHints(hints); }, completion.options); + else + return completion.showHints(getHints(this, completion.options)); + }); + + function Completion(cm, options) { + this.cm = cm; + this.options = this.buildOptions(options); + this.widget = this.onClose = null; + } + + Completion.prototype = { + close: function() { + if (!this.active()) return; + this.cm.state.completionActive = null; + + if (this.widget) this.widget.close(); + if (this.onClose) this.onClose(); + CodeMirror.signal(this.cm, "endCompletion", this.cm); + }, + + active: function() { + return this.cm.state.completionActive == this; + }, + + pick: function(data, i) { + var completion = data.list[i]; + if (completion.hint) completion.hint(this.cm, data, completion); + else this.cm.replaceRange(getText(completion), completion.from || data.from, + completion.to || data.to, "complete"); + CodeMirror.signal(data, "pick", completion); + this.close(); + }, + + showHints: function(data) { + if (!data || !data.list.length || !this.active()) return this.close(); + + if (this.options.completeSingle && data.list.length == 1) + this.pick(data, 0); + else + this.showWidget(data); + }, + + showWidget: function(data) { + this.widget = new Widget(this, data); + CodeMirror.signal(data, "shown"); + + var debounce = 0, completion = this, finished; + var closeOn = this.options.closeCharacters; + var startPos = this.cm.getCursor(), startLen = this.cm.getLine(startPos.line).length; + + var requestAnimationFrame = window.requestAnimationFrame || function(fn) { + return setTimeout(fn, 1000/60); + }; + var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; + + function done() { + if (finished) return; + finished = true; + completion.close(); + completion.cm.off("cursorActivity", activity); + if (data) CodeMirror.signal(data, "close"); + } + + function update() { + if (finished) return; + CodeMirror.signal(data, "update"); + var getHints = completion.options.hint; + if (getHints.async) + getHints(completion.cm, finishUpdate, completion.options); + else + finishUpdate(getHints(completion.cm, completion.options)); + } + function finishUpdate(data_) { + data = data_; + if (finished) return; + if (!data || !data.list.length) return done(); + if (completion.widget) completion.widget.close(); + completion.widget = new Widget(completion, data); + } + + function clearDebounce() { + if (debounce) { + cancelAnimationFrame(debounce); + debounce = 0; + } + } + + function activity() { + clearDebounce(); + var pos = completion.cm.getCursor(), line = completion.cm.getLine(pos.line); + if (pos.line != startPos.line || line.length - pos.ch != startLen - startPos.ch || + pos.ch < startPos.ch || completion.cm.somethingSelected() || + (pos.ch && closeOn.test(line.charAt(pos.ch - 1)))) { + completion.close(); + } else { + debounce = requestAnimationFrame(update); + if (completion.widget) completion.widget.close(); + } + } + this.cm.on("cursorActivity", activity); + this.onClose = done; + }, + + buildOptions: function(options) { + var editor = this.cm.options.hintOptions; + var out = {}; + for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; + if (editor) for (var prop in editor) + if (editor[prop] !== undefined) out[prop] = editor[prop]; + if (options) for (var prop in options) + if (options[prop] !== undefined) out[prop] = options[prop]; + return out; + } + }; + + function getText(completion) { + if (typeof completion == "string") return completion; + else return completion.text; + } + + function buildKeyMap(completion, handle) { + var baseMap = { + Up: function() {handle.moveFocus(-1);}, + Down: function() {handle.moveFocus(1);}, + PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, + PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, + Home: function() {handle.setFocus(0);}, + End: function() {handle.setFocus(handle.length - 1);}, + Enter: handle.pick, + Tab: handle.pick, + Esc: handle.close + }; + var custom = completion.options.customKeys; + var ourMap = custom ? {} : baseMap; + function addBinding(key, val) { + var bound; + if (typeof val != "string") + bound = function(cm) { return val(cm, handle); }; + // This mechanism is deprecated + else if (baseMap.hasOwnProperty(val)) + bound = baseMap[val]; + else + bound = val; + ourMap[key] = bound; + } + if (custom) + for (var key in custom) if (custom.hasOwnProperty(key)) + addBinding(key, custom[key]); + var extra = completion.options.extraKeys; + if (extra) + for (var key in extra) if (extra.hasOwnProperty(key)) + addBinding(key, extra[key]); + return ourMap; + } + + function getHintElement(hintsElement, el) { + while (el && el != hintsElement) { + if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; + el = el.parentNode; + } + } + + function Widget(completion, data) { + this.completion = completion; + this.data = data; + var widget = this, cm = completion.cm; + + var hints = this.hints = document.createElement("ul"); + hints.className = "CodeMirror-hints"; + this.selectedHint = data.selectedHint || 0; + + var completions = data.list; + for (var i = 0; i < completions.length; ++i) { + var elt = hints.appendChild(document.createElement("li")), cur = completions[i]; + var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); + if (cur.className != null) className = cur.className + " " + className; + elt.className = className; + if (cur.render) cur.render(elt, data, cur); + else elt.appendChild(document.createTextNode(cur.displayText || getText(cur))); + elt.hintId = i; + } + + var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); + var left = pos.left, top = pos.bottom, below = true; + hints.style.left = left + "px"; + hints.style.top = top + "px"; + // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. + var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); + var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); + (completion.options.container || document.body).appendChild(hints); + var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; + if (overlapY > 0) { + var height = box.bottom - box.top, curTop = box.top - (pos.bottom - pos.top); + if (curTop - height > 0) { // Fits above cursor + hints.style.top = (top = curTop - height) + "px"; + below = false; + } else if (height > winH) { + hints.style.height = (winH - 5) + "px"; + hints.style.top = (top = pos.bottom - box.top) + "px"; + var cursor = cm.getCursor(); + if (data.from.ch != cursor.ch) { + pos = cm.cursorCoords(cursor); + hints.style.left = (left = pos.left) + "px"; + box = hints.getBoundingClientRect(); + } + } + } + var overlapX = box.left - winW; + if (overlapX > 0) { + if (box.right - box.left > winW) { + hints.style.width = (winW - 5) + "px"; + overlapX -= (box.right - box.left) - winW; + } + hints.style.left = (left = pos.left - overlapX) + "px"; + } + + cm.addKeyMap(this.keyMap = buildKeyMap(completion, { + moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, + setFocus: function(n) { widget.changeActive(n); }, + menuSize: function() { return widget.screenAmount(); }, + length: completions.length, + close: function() { completion.close(); }, + pick: function() { widget.pick(); }, + data: data + })); + + if (completion.options.closeOnUnfocus) { + var closingOnBlur; + cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); + cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); + } + + var startScroll = cm.getScrollInfo(); + cm.on("scroll", this.onScroll = function() { + var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); + var newTop = top + startScroll.top - curScroll.top; + var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop); + if (!below) point += hints.offsetHeight; + if (point <= editor.top || point >= editor.bottom) return completion.close(); + hints.style.top = newTop + "px"; + hints.style.left = (left + startScroll.left - curScroll.left) + "px"; + }); + + CodeMirror.on(hints, "dblclick", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();} + }); + + CodeMirror.on(hints, "click", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) { + widget.changeActive(t.hintId); + if (completion.options.completeOnSingleClick) widget.pick(); + } + }); + + CodeMirror.on(hints, "mousedown", function() { + setTimeout(function(){cm.focus();}, 20); + }); + + CodeMirror.signal(data, "select", completions[0], hints.firstChild); + return true; + } + + Widget.prototype = { + close: function() { + if (this.completion.widget != this) return; + this.completion.widget = null; + this.hints.parentNode.removeChild(this.hints); + this.completion.cm.removeKeyMap(this.keyMap); + + var cm = this.completion.cm; + if (this.completion.options.closeOnUnfocus) { + cm.off("blur", this.onBlur); + cm.off("focus", this.onFocus); + } + cm.off("scroll", this.onScroll); + }, + + pick: function() { + this.completion.pick(this.data, this.selectedHint); + }, + + changeActive: function(i, avoidWrap) { + if (i >= this.data.list.length) + i = avoidWrap ? this.data.list.length - 1 : 0; + else if (i < 0) + i = avoidWrap ? 0 : this.data.list.length - 1; + if (this.selectedHint == i) return; + var node = this.hints.childNodes[this.selectedHint]; + node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); + node = this.hints.childNodes[this.selectedHint = i]; + node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; + if (node.offsetTop < this.hints.scrollTop) + this.hints.scrollTop = node.offsetTop - 3; + else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) + this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; + CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); + }, + + screenAmount: function() { + return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; + } + }; + + CodeMirror.registerHelper("hint", "auto", function(cm, options) { + var helpers = cm.getHelpers(cm.getCursor(), "hint"), words; + if (helpers.length) { + for (var i = 0; i < helpers.length; i++) { + var cur = helpers[i](cm, options); + if (cur && cur.list.length) return cur; + } + } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { + if (words) return CodeMirror.hint.fromList(cm, {words: words}); + } else if (CodeMirror.hint.anyword) { + return CodeMirror.hint.anyword(cm, options); + } + }); + + CodeMirror.registerHelper("hint", "fromList", function(cm, options) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var found = []; + for (var i = 0; i < options.words.length; i++) { + var word = options.words[i]; + if (word.slice(0, token.string.length) == token.string) + found.push(word); + } + + if (found.length) return { + list: found, + from: CodeMirror.Pos(cur.line, token.start), + to: CodeMirror.Pos(cur.line, token.end) + }; + }); + + CodeMirror.commands.autocomplete = CodeMirror.showHint; + + var defaultOptions = { + hint: CodeMirror.hint.auto, + completeSingle: true, + alignWithWord: true, + closeCharacters: /[\s()\[\]{};:>,]/, + closeOnUnfocus: true, + completeOnSingleClick: false, + container: null, + customKeys: null, + extraKeys: null + }; + + CodeMirror.defineOption("hintOptions", null); +}); diff --git a/Upload/admin/jscripts/codemirror/addon/hint/sql-hint.js b/Upload/admin/jscripts/codemirror/addon/hint/sql-hint.js new file mode 100644 index 0000000..fd58b88 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/hint/sql-hint.js @@ -0,0 +1,164 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../../mode/sql/sql")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../../mode/sql/sql"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var tables; + var keywords; + var CONS = { + QUERY_DIV: ";", + ALIAS_KEYWORD: "AS" + }; + var Pos = CodeMirror.Pos; + + function getKeywords(editor) { + var mode = editor.doc.modeOption; + if(mode === "sql") mode = "text/x-sql"; + return CodeMirror.resolveMode(mode).keywords; + } + + function match(string, word) { + var len = string.length; + var sub = word.substr(0, len); + return string.toUpperCase() === sub.toUpperCase(); + } + + function addMatches(result, search, wordlist, formatter) { + for(var word in wordlist) { + if(!wordlist.hasOwnProperty(word)) continue; + if(Array.isArray(wordlist)) { + word = wordlist[word]; + } + if(match(search, word)) { + result.push(formatter(word)); + } + } + } + + function columnCompletion(result, editor) { + var cur = editor.getCursor(); + var token = editor.getTokenAt(cur); + var string = token.string.substr(1); + var prevCur = Pos(cur.line, token.start); + var table = editor.getTokenAt(prevCur).string; + if( !tables.hasOwnProperty( table ) ){ + table = findTableByAlias(table, editor); + } + var columns = tables[table]; + if(!columns) { + return; + } + addMatches(result, string, columns, + function(w) {return "." + w;}); + } + + function eachWord(lineText, f) { + if( !lineText ){return;} + var excepted = /[,;]/g; + var words = lineText.split( " " ); + for( var i = 0; i < words.length; i++ ){ + f( words[i]?words[i].replace( excepted, '' ) : '' ); + } + } + + function convertCurToNumber( cur ){ + // max characters of a line is 999,999. + return cur.line + cur.ch / Math.pow( 10, 6 ); + } + + function convertNumberToCur( num ){ + return Pos(Math.floor( num ), +num.toString().split( '.' ).pop()); + } + + function findTableByAlias(alias, editor) { + var doc = editor.doc; + var fullQuery = doc.getValue(); + var aliasUpperCase = alias.toUpperCase(); + var previousWord = ""; + var table = ""; + var separator = []; + var validRange = { + start: Pos( 0, 0 ), + end: Pos( editor.lastLine(), editor.getLineHandle( editor.lastLine() ).length ) + }; + + //add separator + var indexOfSeparator = fullQuery.indexOf( CONS.QUERY_DIV ); + while( indexOfSeparator != -1 ){ + separator.push( doc.posFromIndex(indexOfSeparator)); + indexOfSeparator = fullQuery.indexOf( CONS.QUERY_DIV, indexOfSeparator+1); + } + separator.unshift( Pos( 0, 0 ) ); + separator.push( Pos( editor.lastLine(), editor.getLineHandle( editor.lastLine() ).text.length ) ); + + //find valieRange + var prevItem = 0; + var current = convertCurToNumber( editor.getCursor() ); + for( var i=0; i< separator.length; i++){ + var _v = convertCurToNumber( separator[i] ); + if( current > prevItem && current <= _v ){ + validRange = { start: convertNumberToCur( prevItem ), end: convertNumberToCur( _v ) }; + break; + } + prevItem = _v; + } + + var query = doc.getRange(validRange.start, validRange.end, false); + + for(var i=0; i < query.length; i++){ + var lineText = query[i]; + eachWord( lineText, function( word ){ + var wordUpperCase = word.toUpperCase(); + if( wordUpperCase === aliasUpperCase && tables.hasOwnProperty( previousWord ) ){ + table = previousWord; + } + if( wordUpperCase !== CONS.ALIAS_KEYWORD ){ + previousWord = word; + } + }); + if( table ){ break; } + } + return table; + } + + function sqlHint(editor, options) { + tables = (options && options.tables) || {}; + keywords = keywords || getKeywords(editor); + var cur = editor.getCursor(); + var token = editor.getTokenAt(cur), end = token.end; + var result = []; + var search = token.string.trim(); + + if (search.charAt(0) == ".") { + columnCompletion(result, editor); + if (!result.length) { + while (token.start && search.charAt(0) == ".") { + token = editor.getTokenAt(Pos(cur.line, token.start - 1)); + search = token.string + search; + } + addMatches(result, search, tables, + function(w) {return w;}); + } + } else { + addMatches(result, search, keywords, + function(w) {return w.toUpperCase();}); + addMatches(result, search, tables, + function(w) {return w;}); + } + + return { + list: result, + from: Pos(cur.line, token.start), + to: Pos(cur.line, end) + }; + } + CodeMirror.registerHelper("hint", "sql", sqlHint); +}); diff --git a/Upload/admin/jscripts/codemirror/addon/hint/xml-hint.js b/Upload/admin/jscripts/codemirror/addon/hint/xml-hint.js new file mode 100644 index 0000000..e31b09b --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/hint/xml-hint.js @@ -0,0 +1,103 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var Pos = CodeMirror.Pos; + + function getHints(cm, options) { + var tags = options && options.schemaInfo; + var quote = (options && options.quoteChar) || '"'; + if (!tags) return; + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var inner = CodeMirror.innerMode(cm.getMode(), token.state); + if (inner.mode.name != "xml") return; + var result = [], replaceToken = false, prefix; + var tag = /\btag\b/.test(token.type), tagName = tag && /^\w/.test(token.string), tagStart; + if (tagName) { + var before = cm.getLine(cur.line).slice(Math.max(0, token.start - 2), token.start); + var tagType = /<\/$/.test(before) ? "close" : /<$/.test(before) ? "open" : null; + if (tagType) tagStart = token.start - (tagType == "close" ? 2 : 1); + } else if (tag && token.string == "<") { + tagType = "open"; + } else if (tag && token.string == ""); + } else { + // Attribute completion + var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs; + var globalAttrs = tags["!attrs"]; + if (!attrs && !globalAttrs) return; + if (!attrs) { + attrs = globalAttrs; + } else if (globalAttrs) { // Combine tag-local and global attributes + var set = {}; + for (var nm in globalAttrs) if (globalAttrs.hasOwnProperty(nm)) set[nm] = globalAttrs[nm]; + for (var nm in attrs) if (attrs.hasOwnProperty(nm)) set[nm] = attrs[nm]; + attrs = set; + } + if (token.type == "string" || token.string == "=") { // A value + var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)), + Pos(cur.line, token.type == "string" ? token.start : token.end)); + var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues; + if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return; + if (typeof atValues == 'function') atValues = atValues.call(this, cm); // Functions can be used to supply values for autocomplete widget + if (token.type == "string") { + prefix = token.string; + var n = 0; + if (/['"]/.test(token.string.charAt(0))) { + quote = token.string.charAt(0); + prefix = token.string.slice(1); + n++; + } + var len = token.string.length; + if (/['"]/.test(token.string.charAt(len - 1))) { + quote = token.string.charAt(len - 1); + prefix = token.string.substr(n, len - 2); + } + replaceToken = true; + } + for (var i = 0; i < atValues.length; ++i) if (!prefix || atValues[i].lastIndexOf(prefix, 0) == 0) + result.push(quote + atValues[i] + quote); + } else { // An attribute name + if (token.type == "attribute") { + prefix = token.string; + replaceToken = true; + } + for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || attr.lastIndexOf(prefix, 0) == 0)) + result.push(attr); + } + } + return { + list: result, + from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur, + to: replaceToken ? Pos(cur.line, token.end) : cur + }; + } + + CodeMirror.registerHelper("hint", "xml", getHints); +}); diff --git a/Upload/admin/jscripts/codemirror/addon/index.html b/Upload/admin/jscripts/codemirror/addon/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/jscripts/codemirror/addon/lint/coffeescript-lint.js b/Upload/admin/jscripts/codemirror/addon/lint/coffeescript-lint.js new file mode 100644 index 0000000..7e39428 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/lint/coffeescript-lint.js @@ -0,0 +1,41 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js + +// declare global: coffeelint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "coffeescript", function(text) { + var found = []; + var parseError = function(err) { + var loc = err.lineNumber; + found.push({from: CodeMirror.Pos(loc-1, 0), + to: CodeMirror.Pos(loc, 0), + severity: err.level, + message: err.message}); + }; + try { + var res = coffeelint.lint(text); + for(var i = 0; i < res.length; i++) { + parseError(res[i]); + } + } catch(e) { + found.push({from: CodeMirror.Pos(e.location.first_line, 0), + to: CodeMirror.Pos(e.location.last_line, e.location.last_column), + severity: 'error', + message: e.message}); + } + return found; +}); + +}); diff --git a/Upload/admin/jscripts/codemirror/addon/lint/css-lint.js b/Upload/admin/jscripts/codemirror/addon/lint/css-lint.js new file mode 100644 index 0000000..1f61b47 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/lint/css-lint.js @@ -0,0 +1,35 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Depends on csslint.js from https://github.com/stubbornella/csslint + +// declare global: CSSLint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "css", function(text) { + var found = []; + if (!window.CSSLint) return found; + var results = CSSLint.verify(text), messages = results.messages, message = null; + for ( var i = 0; i < messages.length; i++) { + message = messages[i]; + var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col; + found.push({ + from: CodeMirror.Pos(startLine, startCol), + to: CodeMirror.Pos(endLine, endCol), + message: message.message, + severity : message.type + }); + } + return found; +}); + +}); diff --git a/Upload/admin/jscripts/codemirror/addon/lint/javascript-lint.js b/Upload/admin/jscripts/codemirror/addon/lint/javascript-lint.js new file mode 100644 index 0000000..3d65ba6 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/lint/javascript-lint.js @@ -0,0 +1,136 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + // declare global: JSHINT + + var bogus = [ "Dangerous comment" ]; + + var warnings = [ [ "Expected '{'", + "Statement body should be inside '{ }' braces." ] ]; + + var errors = [ "Missing semicolon", "Extra comma", "Missing property name", + "Unmatched ", " and instead saw", " is not defined", + "Unclosed string", "Stopping, unable to continue" ]; + + function validator(text, options) { + if (!window.JSHINT) return []; + JSHINT(text, options); + var errors = JSHINT.data().errors, result = []; + if (errors) parseErrors(errors, result); + return result; + } + + CodeMirror.registerHelper("lint", "javascript", validator); + + function cleanup(error) { + // All problems are warnings by default + fixWith(error, warnings, "warning", true); + fixWith(error, errors, "error"); + + return isBogus(error) ? null : error; + } + + function fixWith(error, fixes, severity, force) { + var description, fix, find, replace, found; + + description = error.description; + + for ( var i = 0; i < fixes.length; i++) { + fix = fixes[i]; + find = (typeof fix === "string" ? fix : fix[0]); + replace = (typeof fix === "string" ? null : fix[1]); + found = description.indexOf(find) !== -1; + + if (force || found) { + error.severity = severity; + } + if (found && replace) { + error.description = replace; + } + } + } + + function isBogus(error) { + var description = error.description; + for ( var i = 0; i < bogus.length; i++) { + if (description.indexOf(bogus[i]) !== -1) { + return true; + } + } + return false; + } + + function parseErrors(errors, output) { + for ( var i = 0; i < errors.length; i++) { + var error = errors[i]; + if (error) { + var linetabpositions, index; + + linetabpositions = []; + + // This next block is to fix a problem in jshint. Jshint + // replaces + // all tabs with spaces then performs some checks. The error + // positions (character/space) are then reported incorrectly, + // not taking the replacement step into account. Here we look + // at the evidence line and try to adjust the character position + // to the correct value. + if (error.evidence) { + // Tab positions are computed once per line and cached + var tabpositions = linetabpositions[error.line]; + if (!tabpositions) { + var evidence = error.evidence; + tabpositions = []; + // ugggh phantomjs does not like this + // forEachChar(evidence, function(item, index) { + Array.prototype.forEach.call(evidence, function(item, + index) { + if (item === '\t') { + // First col is 1 (not 0) to match error + // positions + tabpositions.push(index + 1); + } + }); + linetabpositions[error.line] = tabpositions; + } + if (tabpositions.length > 0) { + var pos = error.character; + tabpositions.forEach(function(tabposition) { + if (pos > tabposition) pos -= 1; + }); + error.character = pos; + } + } + + var start = error.character - 1, end = start + 1; + if (error.evidence) { + index = error.evidence.substring(start).search(/.\b/); + if (index > -1) { + end += index; + } + } + + // Convert to format expected by validation service + error.description = error.reason;// + "(jshint)"; + error.start = error.character; + error.end = end; + error = cleanup(error); + + if (error) + output.push({message: error.description, + severity: error.severity, + from: CodeMirror.Pos(error.line - 1, start), + to: CodeMirror.Pos(error.line - 1, end)}); + } + } + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/lint/json-lint.js b/Upload/admin/jscripts/codemirror/addon/lint/json-lint.js new file mode 100644 index 0000000..9dbb616 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/lint/json-lint.js @@ -0,0 +1,31 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Depends on jsonlint.js from https://github.com/zaach/jsonlint + +// declare global: jsonlint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "json", function(text) { + var found = []; + jsonlint.parseError = function(str, hash) { + var loc = hash.loc; + found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column), + to: CodeMirror.Pos(loc.last_line - 1, loc.last_column), + message: str}); + }; + try { jsonlint.parse(text); } + catch(e) {} + return found; +}); + +}); diff --git a/Upload/admin/jscripts/codemirror/addon/lint/lint.css b/Upload/admin/jscripts/codemirror/addon/lint/lint.css new file mode 100644 index 0000000..414a9a0 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/lint/lint.css @@ -0,0 +1,73 @@ +/* The lint marker gutter */ +.CodeMirror-lint-markers { + width: 16px; +} + +.CodeMirror-lint-tooltip { + background-color: infobackground; + border: 1px solid black; + border-radius: 4px 4px 4px 4px; + color: infotext; + font-family: monospace; + font-size: 10pt; + overflow: hidden; + padding: 2px 5px; + position: fixed; + white-space: pre; + white-space: pre-wrap; + z-index: 100; + max-width: 600px; + opacity: 0; + transition: opacity .4s; + -moz-transition: opacity .4s; + -webkit-transition: opacity .4s; + -o-transition: opacity .4s; + -ms-transition: opacity .4s; +} + +.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { + background-position: left bottom; + background-repeat: repeat-x; +} + +.CodeMirror-lint-mark-error { + background-image: + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") + ; +} + +.CodeMirror-lint-mark-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { + background-position: center center; + background-repeat: no-repeat; + cursor: pointer; + display: inline-block; + height: 16px; + width: 16px; + vertical-align: middle; + position: relative; +} + +.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { + padding-left: 18px; + background-position: top left; + background-repeat: no-repeat; +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-multiple { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); + background-repeat: no-repeat; + background-position: right bottom; + width: 100%; height: 100%; +} diff --git a/Upload/admin/jscripts/codemirror/addon/lint/lint.js b/Upload/admin/jscripts/codemirror/addon/lint/lint.js new file mode 100644 index 0000000..604e2e6 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/lint/lint.js @@ -0,0 +1,210 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var GUTTER_ID = "CodeMirror-lint-markers"; + var SEVERITIES = /^(?:error|warning)$/; + + function showTooltip(e, content) { + var tt = document.createElement("div"); + tt.className = "CodeMirror-lint-tooltip"; + tt.appendChild(content.cloneNode(true)); + document.body.appendChild(tt); + + function position(e) { + if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); + tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px"; + tt.style.left = (e.clientX + 5) + "px"; + } + CodeMirror.on(document, "mousemove", position); + position(e); + if (tt.style.opacity != null) tt.style.opacity = 1; + return tt; + } + function rm(elt) { + if (elt.parentNode) elt.parentNode.removeChild(elt); + } + function hideTooltip(tt) { + if (!tt.parentNode) return; + if (tt.style.opacity == null) rm(tt); + tt.style.opacity = 0; + setTimeout(function() { rm(tt); }, 600); + } + + function showTooltipFor(e, content, node) { + var tooltip = showTooltip(e, content); + function hide() { + CodeMirror.off(node, "mouseout", hide); + if (tooltip) { hideTooltip(tooltip); tooltip = null; } + } + var poll = setInterval(function() { + if (tooltip) for (var n = node;; n = n.parentNode) { + if (n == document.body) return; + if (!n) { hide(); break; } + } + if (!tooltip) return clearInterval(poll); + }, 400); + CodeMirror.on(node, "mouseout", hide); + } + + function LintState(cm, options, hasGutter) { + this.marked = []; + this.options = options; + this.timeout = null; + this.hasGutter = hasGutter; + this.onMouseOver = function(e) { onMouseOver(cm, e); }; + } + + function parseOptions(cm, options) { + if (options instanceof Function) return {getAnnotations: options}; + if (!options || options === true) options = {}; + if (!options.getAnnotations) options.getAnnotations = cm.getHelper(CodeMirror.Pos(0, 0), "lint"); + if (!options.getAnnotations) throw new Error("Required option 'getAnnotations' missing (lint addon)"); + return options; + } + + function clearMarks(cm) { + var state = cm.state.lint; + if (state.hasGutter) cm.clearGutter(GUTTER_ID); + for (var i = 0; i < state.marked.length; ++i) + state.marked[i].clear(); + state.marked.length = 0; + } + + function makeMarker(labels, severity, multiple, tooltips) { + var marker = document.createElement("div"), inner = marker; + marker.className = "CodeMirror-lint-marker-" + severity; + if (multiple) { + inner = marker.appendChild(document.createElement("div")); + inner.className = "CodeMirror-lint-marker-multiple"; + } + + if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) { + showTooltipFor(e, labels, inner); + }); + + return marker; + } + + function getMaxSeverity(a, b) { + if (a == "error") return a; + else return b; + } + + function groupByLine(annotations) { + var lines = []; + for (var i = 0; i < annotations.length; ++i) { + var ann = annotations[i], line = ann.from.line; + (lines[line] || (lines[line] = [])).push(ann); + } + return lines; + } + + function annotationTooltip(ann) { + var severity = ann.severity; + if (!SEVERITIES.test(severity)) severity = "error"; + var tip = document.createElement("div"); + tip.className = "CodeMirror-lint-message-" + severity; + tip.appendChild(document.createTextNode(ann.message)); + return tip; + } + + function startLinting(cm) { + var state = cm.state.lint, options = state.options; + if (options.async) + options.getAnnotations(cm, updateLinting, options); + else + updateLinting(cm, options.getAnnotations(cm.getValue(), options.options)); + } + + function updateLinting(cm, annotationsNotSorted) { + clearMarks(cm); + var state = cm.state.lint, options = state.options; + + var annotations = groupByLine(annotationsNotSorted); + + for (var line = 0; line < annotations.length; ++line) { + var anns = annotations[line]; + if (!anns) continue; + + var maxSeverity = null; + var tipLabel = state.hasGutter && document.createDocumentFragment(); + + for (var i = 0; i < anns.length; ++i) { + var ann = anns[i]; + var severity = ann.severity; + if (!SEVERITIES.test(severity)) severity = "error"; + maxSeverity = getMaxSeverity(maxSeverity, severity); + + if (options.formatAnnotation) ann = options.formatAnnotation(ann); + if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); + + if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { + className: "CodeMirror-lint-mark-" + severity, + __annotation: ann + })); + } + + if (state.hasGutter) + cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1, + state.options.tooltips)); + } + if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); + } + + function onChange(cm) { + var state = cm.state.lint; + clearTimeout(state.timeout); + state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500); + } + + function popupSpanTooltip(ann, e) { + var target = e.target || e.srcElement; + showTooltipFor(e, annotationTooltip(ann), target); + } + + // When the mouseover fires, the cursor might not actually be over + // the character itself yet. These pairs of x,y offsets are used to + // probe a few nearby points when no suitable marked range is found. + var nearby = [0, 0, 0, 5, 0, -5, 5, 0, -5, 0]; + + function onMouseOver(cm, e) { + if (!/\bCodeMirror-lint-mark-/.test((e.target || e.srcElement).className)) return; + for (var i = 0; i < nearby.length; i += 2) { + var spans = cm.findMarksAt(cm.coordsChar({left: e.clientX + nearby[i], + top: e.clientY + nearby[i + 1]}, "client")); + for (var j = 0; j < spans.length; ++j) { + var span = spans[j], ann = span.__annotation; + if (ann) return popupSpanTooltip(ann, e); + } + } + } + + CodeMirror.defineOption("lint", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + clearMarks(cm); + cm.off("change", onChange); + CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); + delete cm.state.lint; + } + + if (val) { + var gutters = cm.getOption("gutters"), hasLintGutter = false; + for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; + var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter); + cm.on("change", onChange); + if (state.options.tooltips != false) + CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); + + startLinting(cm); + } + }); +}); diff --git a/Upload/admin/jscripts/codemirror/addon/lint/yaml-lint.js b/Upload/admin/jscripts/codemirror/addon/lint/yaml-lint.js new file mode 100644 index 0000000..3f77e52 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/lint/yaml-lint.js @@ -0,0 +1,28 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +// Depends on js-yaml.js from https://github.com/nodeca/js-yaml + +// declare global: jsyaml + +CodeMirror.registerHelper("lint", "yaml", function(text) { + var found = []; + try { jsyaml.load(text); } + catch(e) { + var loc = e.mark; + found.push({ from: CodeMirror.Pos(loc.line, loc.column), to: CodeMirror.Pos(loc.line, loc.column), message: e.message }); + } + return found; +}); + +}); diff --git a/Upload/admin/jscripts/codemirror/addon/merge/merge.css b/Upload/admin/jscripts/codemirror/addon/merge/merge.css new file mode 100644 index 0000000..63237fc --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/merge/merge.css @@ -0,0 +1,92 @@ +.CodeMirror-merge { + position: relative; + border: 1px solid #ddd; + white-space: pre; +} + +.CodeMirror-merge, .CodeMirror-merge .CodeMirror { + height: 350px; +} + +.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; } +.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; } +.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; } +.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; } + +.CodeMirror-merge-pane { + display: inline-block; + white-space: normal; + vertical-align: top; +} +.CodeMirror-merge-pane-rightmost { + position: absolute; + right: 0px; + z-index: 1; +} + +.CodeMirror-merge-gap { + z-index: 2; + display: inline-block; + height: 100%; + -moz-box-sizing: border-box; + box-sizing: border-box; + overflow: hidden; + border-left: 1px solid #ddd; + border-right: 1px solid #ddd; + position: relative; + background: #f8f8f8; +} + +.CodeMirror-merge-scrolllock-wrap { + position: absolute; + bottom: 0; left: 50%; +} +.CodeMirror-merge-scrolllock { + position: relative; + left: -50%; + cursor: pointer; + color: #555; + line-height: 1; +} + +.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right { + position: absolute; + left: 0; top: 0; + right: 0; bottom: 0; + line-height: 1; +} + +.CodeMirror-merge-copy { + position: absolute; + cursor: pointer; + color: #44c; +} + +.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; } +.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; } + +.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==); + background-position: bottom left; + background-repeat: repeat-x; +} + +.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==); + background-position: bottom left; + background-repeat: repeat-x; +} + +.CodeMirror-merge-r-chunk { background: #ffffe0; } +.CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; } +.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; } +.CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; } + +.CodeMirror-merge-l-chunk { background: #eef; } +.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; } +.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; } +.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; } + +.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; } +.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; } +.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; } diff --git a/Upload/admin/jscripts/codemirror/addon/merge/merge.js b/Upload/admin/jscripts/codemirror/addon/merge/merge.js new file mode 100644 index 0000000..3583936 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/merge/merge.js @@ -0,0 +1,513 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + // declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL + + var Pos = CodeMirror.Pos; + var svgNS = "http://www.w3.org/2000/svg"; + + function DiffView(mv, type) { + this.mv = mv; + this.type = type; + this.classes = type == "left" + ? {chunk: "CodeMirror-merge-l-chunk", + start: "CodeMirror-merge-l-chunk-start", + end: "CodeMirror-merge-l-chunk-end", + insert: "CodeMirror-merge-l-inserted", + del: "CodeMirror-merge-l-deleted", + connect: "CodeMirror-merge-l-connect"} + : {chunk: "CodeMirror-merge-r-chunk", + start: "CodeMirror-merge-r-chunk-start", + end: "CodeMirror-merge-r-chunk-end", + insert: "CodeMirror-merge-r-inserted", + del: "CodeMirror-merge-r-deleted", + connect: "CodeMirror-merge-r-connect"}; + } + + DiffView.prototype = { + constructor: DiffView, + init: function(pane, orig, options) { + this.edit = this.mv.edit; + this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: true}, copyObj(options))); + + this.diff = getDiff(asString(orig), asString(options.value)); + this.diffOutOfDate = false; + + this.showDifferences = options.showDifferences !== false; + this.forceUpdate = registerUpdate(this); + setScrollLock(this, true, false); + registerScroll(this); + }, + setShowDifferences: function(val) { + val = val !== false; + if (val != this.showDifferences) { + this.showDifferences = val; + this.forceUpdate("full"); + } + } + }; + + function ensureDiff(dv) { + if (dv.diffOutOfDate) { + dv.diff = getDiff(dv.orig.getValue(), dv.edit.getValue()); + dv.diffOutOfDate = false; + CodeMirror.signal(dv.edit, "updateDiff", dv.diff); + } + } + + function registerUpdate(dv) { + var edit = {from: 0, to: 0, marked: []}; + var orig = {from: 0, to: 0, marked: []}; + var debounceChange; + function update(mode) { + if (mode == "full") { + if (dv.svg) clear(dv.svg); + clear(dv.copyButtons); + clearMarks(dv.edit, edit.marked, dv.classes); + clearMarks(dv.orig, orig.marked, dv.classes); + edit.from = edit.to = orig.from = orig.to = 0; + } + ensureDiff(dv); + if (dv.showDifferences) { + updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes); + updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes); + } + drawConnectors(dv); + } + function set(slow) { + clearTimeout(debounceChange); + debounceChange = setTimeout(update, slow == true ? 250 : 100); + } + function change() { + if (!dv.diffOutOfDate) { + dv.diffOutOfDate = true; + edit.from = edit.to = orig.from = orig.to = 0; + } + set(true); + } + dv.edit.on("change", change); + dv.orig.on("change", change); + dv.edit.on("markerAdded", set); + dv.edit.on("markerCleared", set); + dv.orig.on("markerAdded", set); + dv.orig.on("markerCleared", set); + dv.edit.on("viewportChange", set); + dv.orig.on("viewportChange", set); + update(); + return update; + } + + function registerScroll(dv) { + dv.edit.on("scroll", function() { + syncScroll(dv, DIFF_INSERT) && drawConnectors(dv); + }); + dv.orig.on("scroll", function() { + syncScroll(dv, DIFF_DELETE) && drawConnectors(dv); + }); + } + + function syncScroll(dv, type) { + // Change handler will do a refresh after a timeout when diff is out of date + if (dv.diffOutOfDate) return false; + if (!dv.lockScroll) return true; + var editor, other, now = +new Date; + if (type == DIFF_INSERT) { editor = dv.edit; other = dv.orig; } + else { editor = dv.orig; other = dv.edit; } + // Don't take action if the position of this editor was recently set + // (to prevent feedback loops) + if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 50 > now) return false; + + var sInfo = editor.getScrollInfo(), halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen; + var mid = editor.lineAtHeight(midY, "local"); + var around = chunkBoundariesAround(dv.diff, mid, type == DIFF_INSERT); + var off = getOffsets(editor, type == DIFF_INSERT ? around.edit : around.orig); + var offOther = getOffsets(other, type == DIFF_INSERT ? around.orig : around.edit); + var ratio = (midY - off.top) / (off.bot - off.top); + var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top); + + var botDist, mix; + // Some careful tweaking to make sure no space is left out of view + // when scrolling to top or bottom. + if (targetPos > sInfo.top && (mix = sInfo.top / halfScreen) < 1) { + targetPos = targetPos * mix + sInfo.top * (1 - mix); + } else if ((botDist = sInfo.height - sInfo.clientHeight - sInfo.top) < halfScreen) { + var otherInfo = other.getScrollInfo(); + var botDistOther = otherInfo.height - otherInfo.clientHeight - targetPos; + if (botDistOther > botDist && (mix = botDist / halfScreen) < 1) + targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix); + } + + other.scrollTo(sInfo.left, targetPos); + other.state.scrollSetAt = now; + other.state.scrollSetBy = dv; + return true; + } + + function getOffsets(editor, around) { + var bot = around.after; + if (bot == null) bot = editor.lastLine() + 1; + return {top: editor.heightAtLine(around.before || 0, "local"), + bot: editor.heightAtLine(bot, "local")}; + } + + function setScrollLock(dv, val, action) { + dv.lockScroll = val; + if (val && action != false) syncScroll(dv, DIFF_INSERT) && drawConnectors(dv); + dv.lockButton.innerHTML = val ? "\u21db\u21da" : "\u21db  \u21da"; + } + + // Updating the marks for editor content + + function clearMarks(editor, arr, classes) { + for (var i = 0; i < arr.length; ++i) { + var mark = arr[i]; + if (mark instanceof CodeMirror.TextMarker) { + mark.clear(); + } else if (mark.parent) { + editor.removeLineClass(mark, "background", classes.chunk); + editor.removeLineClass(mark, "background", classes.start); + editor.removeLineClass(mark, "background", classes.end); + } + } + arr.length = 0; + } + + // FIXME maybe add a margin around viewport to prevent too many updates + function updateMarks(editor, diff, state, type, classes) { + var vp = editor.getViewport(); + editor.operation(function() { + if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { + clearMarks(editor, state.marked, classes); + markChanges(editor, diff, type, state.marked, vp.from, vp.to, classes); + state.from = vp.from; state.to = vp.to; + } else { + if (vp.from < state.from) { + markChanges(editor, diff, type, state.marked, vp.from, state.from, classes); + state.from = vp.from; + } + if (vp.to > state.to) { + markChanges(editor, diff, type, state.marked, state.to, vp.to, classes); + state.to = vp.to; + } + } + }); + } + + function markChanges(editor, diff, type, marks, from, to, classes) { + var pos = Pos(0, 0); + var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1)); + var cls = type == DIFF_DELETE ? classes.del : classes.insert; + function markChunk(start, end) { + var bfrom = Math.max(from, start), bto = Math.min(to, end); + for (var i = bfrom; i < bto; ++i) { + var line = editor.addLineClass(i, "background", classes.chunk); + if (i == start) editor.addLineClass(line, "background", classes.start); + if (i == end - 1) editor.addLineClass(line, "background", classes.end); + marks.push(line); + } + // When the chunk is empty, make sure a horizontal line shows up + if (start == end && bfrom == end && bto == end) { + if (bfrom) + marks.push(editor.addLineClass(bfrom - 1, "background", classes.end)); + else + marks.push(editor.addLineClass(bfrom, "background", classes.start)); + } + } + + var chunkStart = 0; + for (var i = 0; i < diff.length; ++i) { + var part = diff[i], tp = part[0], str = part[1]; + if (tp == DIFF_EQUAL) { + var cleanFrom = pos.line + (startOfLineClean(diff, i) ? 0 : 1); + moveOver(pos, str); + var cleanTo = pos.line + (endOfLineClean(diff, i) ? 1 : 0); + if (cleanTo > cleanFrom) { + if (i) markChunk(chunkStart, cleanFrom); + chunkStart = cleanTo; + } + } else { + if (tp == type) { + var end = moveOver(pos, str, true); + var a = posMax(top, pos), b = posMin(bot, end); + if (!posEq(a, b)) + marks.push(editor.markText(a, b, {className: cls})); + pos = end; + } + } + } + if (chunkStart <= pos.line) markChunk(chunkStart, pos.line + 1); + } + + // Updating the gap between editor and original + + function drawConnectors(dv) { + if (!dv.showDifferences) return; + + if (dv.svg) { + clear(dv.svg); + var w = dv.gap.offsetWidth; + attrs(dv.svg, "width", w, "height", dv.gap.offsetHeight); + } + clear(dv.copyButtons); + + var flip = dv.type == "left"; + var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport(); + var sTopEdit = dv.edit.getScrollInfo().top, sTopOrig = dv.orig.getScrollInfo().top; + iterateChunks(dv.diff, function(topOrig, botOrig, topEdit, botEdit) { + if (topEdit > vpEdit.to || botEdit < vpEdit.from || + topOrig > vpOrig.to || botOrig < vpOrig.from) + return; + var topLpx = dv.orig.heightAtLine(topOrig, "local") - sTopOrig, top = topLpx; + if (dv.svg) { + var topRpx = dv.edit.heightAtLine(topEdit, "local") - sTopEdit; + if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; } + var botLpx = dv.orig.heightAtLine(botOrig, "local") - sTopOrig; + var botRpx = dv.edit.heightAtLine(botEdit, "local") - sTopEdit; + if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; } + var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx; + var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx; + attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")), + "d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z", + "class", dv.classes.connect); + } + var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc", + "CodeMirror-merge-copy")); + copy.title = "Revert chunk"; + copy.chunk = {topEdit: topEdit, botEdit: botEdit, topOrig: topOrig, botOrig: botOrig}; + copy.style.top = top + "px"; + }); + } + + function copyChunk(dv, chunk) { + if (dv.diffOutOfDate) return; + dv.edit.replaceRange(dv.orig.getRange(Pos(chunk.topOrig, 0), Pos(chunk.botOrig, 0)), + Pos(chunk.topEdit, 0), Pos(chunk.botEdit, 0)); + } + + // Merge view, containing 0, 1, or 2 diff views. + + var MergeView = CodeMirror.MergeView = function(node, options) { + if (!(this instanceof MergeView)) return new MergeView(node, options); + + var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight; + var hasLeft = origLeft != null, hasRight = origRight != null; + var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0); + var wrap = [], left = this.left = null, right = this.right = null; + + if (hasLeft) { + left = this.left = new DiffView(this, "left"); + var leftPane = elt("div", null, "CodeMirror-merge-pane"); + wrap.push(leftPane); + wrap.push(buildGap(left)); + } + + var editPane = elt("div", null, "CodeMirror-merge-pane"); + wrap.push(editPane); + + if (hasRight) { + right = this.right = new DiffView(this, "right"); + wrap.push(buildGap(right)); + var rightPane = elt("div", null, "CodeMirror-merge-pane"); + wrap.push(rightPane); + } + + (hasRight ? rightPane : editPane).className += " CodeMirror-merge-pane-rightmost"; + + wrap.push(elt("div", null, null, "height: 0; clear: both;")); + var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-merge CodeMirror-merge-" + panes + "pane")); + this.edit = CodeMirror(editPane, copyObj(options)); + + if (left) left.init(leftPane, origLeft, options); + if (right) right.init(rightPane, origRight, options); + + var onResize = function() { + if (left) drawConnectors(left); + if (right) drawConnectors(right); + }; + CodeMirror.on(window, "resize", onResize); + var resizeInterval = setInterval(function() { + for (var p = wrapElt.parentNode; p && p != document.body; p = p.parentNode) {} + if (!p) { clearInterval(resizeInterval); CodeMirror.off(window, "resize", onResize); } + }, 5000); + }; + + function buildGap(dv) { + var lock = dv.lockButton = elt("div", null, "CodeMirror-merge-scrolllock"); + lock.title = "Toggle locked scrolling"; + var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap"); + CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); }); + dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type); + CodeMirror.on(dv.copyButtons, "click", function(e) { + var node = e.target || e.srcElement; + if (node.chunk) copyChunk(dv, node.chunk); + }); + var gapElts = [dv.copyButtons, lockWrap]; + var svg = document.createElementNS && document.createElementNS(svgNS, "svg"); + if (svg && !svg.createSVGRect) svg = null; + dv.svg = svg; + if (svg) gapElts.push(svg); + + return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap"); + } + + MergeView.prototype = { + constuctor: MergeView, + editor: function() { return this.edit; }, + rightOriginal: function() { return this.right && this.right.orig; }, + leftOriginal: function() { return this.left && this.left.orig; }, + setShowDifferences: function(val) { + if (this.right) this.right.setShowDifferences(val); + if (this.left) this.left.setShowDifferences(val); + }, + rightChunks: function() { + return this.right && getChunks(this.right); + }, + leftChunks: function() { + return this.left && getChunks(this.left); + } + }; + + function asString(obj) { + if (typeof obj == "string") return obj; + else return obj.getValue(); + } + + // Operations on diffs + + var dmp = new diff_match_patch(); + function getDiff(a, b) { + var diff = dmp.diff_main(a, b); + dmp.diff_cleanupSemantic(diff); + // The library sometimes leaves in empty parts, which confuse the algorithm + for (var i = 0; i < diff.length; ++i) { + var part = diff[i]; + if (!part[1]) { + diff.splice(i--, 1); + } else if (i && diff[i - 1][0] == part[0]) { + diff.splice(i--, 1); + diff[i][1] += part[1]; + } + } + return diff; + } + + function iterateChunks(diff, f) { + var startEdit = 0, startOrig = 0; + var edit = Pos(0, 0), orig = Pos(0, 0); + for (var i = 0; i < diff.length; ++i) { + var part = diff[i], tp = part[0]; + if (tp == DIFF_EQUAL) { + var startOff = startOfLineClean(diff, i) ? 0 : 1; + var cleanFromEdit = edit.line + startOff, cleanFromOrig = orig.line + startOff; + moveOver(edit, part[1], null, orig); + var endOff = endOfLineClean(diff, i) ? 1 : 0; + var cleanToEdit = edit.line + endOff, cleanToOrig = orig.line + endOff; + if (cleanToEdit > cleanFromEdit) { + if (i) f(startOrig, cleanFromOrig, startEdit, cleanFromEdit); + startEdit = cleanToEdit; startOrig = cleanToOrig; + } + } else { + moveOver(tp == DIFF_INSERT ? edit : orig, part[1]); + } + } + if (startEdit <= edit.line || startOrig <= orig.line) + f(startOrig, orig.line + 1, startEdit, edit.line + 1); + } + + function getChunks(dv) { + ensureDiff(dv); + var collect = []; + iterateChunks(dv.diff, function(topOrig, botOrig, topEdit, botEdit) { + collect.push({origFrom: topOrig, origTo: botOrig, + editFrom: topEdit, editTo: botEdit}); + }); + return collect; + } + + function endOfLineClean(diff, i) { + if (i == diff.length - 1) return true; + var next = diff[i + 1][1]; + if (next.length == 1 || next.charCodeAt(0) != 10) return false; + if (i == diff.length - 2) return true; + next = diff[i + 2][1]; + return next.length > 1 && next.charCodeAt(0) == 10; + } + + function startOfLineClean(diff, i) { + if (i == 0) return true; + var last = diff[i - 1][1]; + if (last.charCodeAt(last.length - 1) != 10) return false; + if (i == 1) return true; + last = diff[i - 2][1]; + return last.charCodeAt(last.length - 1) == 10; + } + + function chunkBoundariesAround(diff, n, nInEdit) { + var beforeE, afterE, beforeO, afterO; + iterateChunks(diff, function(fromOrig, toOrig, fromEdit, toEdit) { + var fromLocal = nInEdit ? fromEdit : fromOrig; + var toLocal = nInEdit ? toEdit : toOrig; + if (afterE == null) { + if (fromLocal > n) { afterE = fromEdit; afterO = fromOrig; } + else if (toLocal > n) { afterE = toEdit; afterO = toOrig; } + } + if (toLocal <= n) { beforeE = toEdit; beforeO = toOrig; } + else if (fromLocal <= n) { beforeE = fromEdit; beforeO = fromOrig; } + }); + return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}}; + } + + // General utilities + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + function clear(node) { + for (var count = node.childNodes.length; count > 0; --count) + node.removeChild(node.firstChild); + } + + function attrs(elt) { + for (var i = 1; i < arguments.length; i += 2) + elt.setAttribute(arguments[i], arguments[i+1]); + } + + function copyObj(obj, target) { + if (!target) target = {}; + for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop]; + return target; + } + + function moveOver(pos, str, copy, other) { + var out = copy ? Pos(pos.line, pos.ch) : pos, at = 0; + for (;;) { + var nl = str.indexOf("\n", at); + if (nl == -1) break; + ++out.line; + if (other) ++other.line; + at = nl + 1; + } + out.ch = (at ? 0 : out.ch) + (str.length - at); + if (other) other.ch = (at ? 0 : other.ch) + (str.length - at); + return out; + } + + function posMin(a, b) { return (a.line - b.line || a.ch - b.ch) < 0 ? a : b; } + function posMax(a, b) { return (a.line - b.line || a.ch - b.ch) > 0 ? a : b; } + function posEq(a, b) { return a.line == b.line && a.ch == b.ch; } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/mode/loadmode.js b/Upload/admin/jscripts/codemirror/addon/mode/loadmode.js new file mode 100644 index 0000000..8042158 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/mode/loadmode.js @@ -0,0 +1,61 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js"; + + var loading = {}; + function splitCallback(cont, n) { + var countDown = n; + return function() { if (--countDown == 0) cont(); }; + } + function ensureDeps(mode, cont) { + var deps = CodeMirror.modes[mode].dependencies; + if (!deps) return cont(); + var missing = []; + for (var i = 0; i < deps.length; ++i) { + if (!CodeMirror.modes.hasOwnProperty(deps[i])) + missing.push(deps[i]); + } + if (!missing.length) return cont(); + var split = splitCallback(cont, missing.length); + for (var i = 0; i < missing.length; ++i) + CodeMirror.requireMode(missing[i], split); + } + + CodeMirror.requireMode = function(mode, cont) { + if (typeof mode != "string") mode = mode.name; + if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont); + if (loading.hasOwnProperty(mode)) return loading[mode].push(cont); + + var script = document.createElement("script"); + script.src = CodeMirror.modeURL.replace(/%N/g, mode); + var others = document.getElementsByTagName("script")[0]; + others.parentNode.insertBefore(script, others); + var list = loading[mode] = [cont]; + var count = 0, poll = setInterval(function() { + if (++count > 100) return clearInterval(poll); + if (CodeMirror.modes.hasOwnProperty(mode)) { + clearInterval(poll); + loading[mode] = null; + ensureDeps(mode, function() { + for (var i = 0; i < list.length; ++i) list[i](); + }); + } + }, 200); + }; + + CodeMirror.autoLoadMode = function(instance, mode) { + if (!CodeMirror.modes.hasOwnProperty(mode)) + CodeMirror.requireMode(mode, function() { + instance.setOption("mode", instance.getOption("mode")); + }); + }; +}); diff --git a/Upload/admin/jscripts/codemirror/addon/mode/multiplex.js b/Upload/admin/jscripts/codemirror/addon/mode/multiplex.js new file mode 100644 index 0000000..6a95b32 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/mode/multiplex.js @@ -0,0 +1,118 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.multiplexingMode = function(outer /*, others */) { + // Others should be {open, close, mode [, delimStyle] [, innerStyle]} objects + var others = Array.prototype.slice.call(arguments, 1); + var n_others = others.length; + + function indexOf(string, pattern, from) { + if (typeof pattern == "string") return string.indexOf(pattern, from); + var m = pattern.exec(from ? string.slice(from) : string); + return m ? m.index + from : -1; + } + + return { + startState: function() { + return { + outer: CodeMirror.startState(outer), + innerActive: null, + inner: null + }; + }, + + copyState: function(state) { + return { + outer: CodeMirror.copyState(outer, state.outer), + innerActive: state.innerActive, + inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner) + }; + }, + + token: function(stream, state) { + if (!state.innerActive) { + var cutOff = Infinity, oldContent = stream.string; + for (var i = 0; i < n_others; ++i) { + var other = others[i]; + var found = indexOf(oldContent, other.open, stream.pos); + if (found == stream.pos) { + stream.match(other.open); + state.innerActive = other; + state.inner = CodeMirror.startState(other.mode, outer.indent ? outer.indent(state.outer, "") : 0); + return other.delimStyle; + } else if (found != -1 && found < cutOff) { + cutOff = found; + } + } + if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff); + var outerToken = outer.token(stream, state.outer); + if (cutOff != Infinity) stream.string = oldContent; + return outerToken; + } else { + var curInner = state.innerActive, oldContent = stream.string; + if (!curInner.close && stream.sol()) { + state.innerActive = state.inner = null; + return this.token(stream, state); + } + var found = curInner.close ? indexOf(oldContent, curInner.close, stream.pos) : -1; + if (found == stream.pos) { + stream.match(curInner.close); + state.innerActive = state.inner = null; + return curInner.delimStyle; + } + if (found > -1) stream.string = oldContent.slice(0, found); + var innerToken = curInner.mode.token(stream, state.inner); + if (found > -1) stream.string = oldContent; + + if (curInner.innerStyle) { + if (innerToken) innerToken = innerToken + ' ' + curInner.innerStyle; + else innerToken = curInner.innerStyle; + } + + return innerToken; + } + }, + + indent: function(state, textAfter) { + var mode = state.innerActive ? state.innerActive.mode : outer; + if (!mode.indent) return CodeMirror.Pass; + return mode.indent(state.innerActive ? state.inner : state.outer, textAfter); + }, + + blankLine: function(state) { + var mode = state.innerActive ? state.innerActive.mode : outer; + if (mode.blankLine) { + mode.blankLine(state.innerActive ? state.inner : state.outer); + } + if (!state.innerActive) { + for (var i = 0; i < n_others; ++i) { + var other = others[i]; + if (other.open === "\n") { + state.innerActive = other; + state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "") : 0); + } + } + } else if (state.innerActive.close === "\n") { + state.innerActive = state.inner = null; + } + }, + + electricChars: outer.electricChars, + + innerMode: function(state) { + return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer}; + } + }; +}; + +}); diff --git a/Upload/admin/jscripts/codemirror/addon/mode/multiplex_test.js b/Upload/admin/jscripts/codemirror/addon/mode/multiplex_test.js new file mode 100644 index 0000000..d339434 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/mode/multiplex_test.js @@ -0,0 +1,33 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + CodeMirror.defineMode("markdown_with_stex", function(){ + var inner = CodeMirror.getMode({}, "stex"); + var outer = CodeMirror.getMode({}, "markdown"); + + var innerOptions = { + open: '$', + close: '$', + mode: inner, + delimStyle: 'delim', + innerStyle: 'inner' + }; + + return CodeMirror.multiplexingMode(outer, innerOptions); + }); + + var mode = CodeMirror.getMode({}, "markdown_with_stex"); + + function MT(name) { + test.mode( + name, + mode, + Array.prototype.slice.call(arguments, 1), + 'multiplexing'); + } + + MT( + "stexInsideMarkdown", + "[strong **Equation:**] [delim $][inner&tag \\pi][delim $]"); +})(); diff --git a/Upload/admin/jscripts/codemirror/addon/mode/overlay.js b/Upload/admin/jscripts/codemirror/addon/mode/overlay.js new file mode 100644 index 0000000..393054d --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/mode/overlay.js @@ -0,0 +1,85 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Utility function that allows modes to be combined. The mode given +// as the base argument takes care of most of the normal mode +// functionality, but a second (typically simple) mode is used, which +// can override the style of text. Both modes get to parse all of the +// text, but when both assign a non-null style to a piece of code, the +// overlay wins, unless the combine argument was true and not overridden, +// or state.overlay.combineTokens was true, in which case the styles are +// combined. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.overlayMode = function(base, overlay, combine) { + return { + startState: function() { + return { + base: CodeMirror.startState(base), + overlay: CodeMirror.startState(overlay), + basePos: 0, baseCur: null, + overlayPos: 0, overlayCur: null, + lineSeen: null + }; + }, + copyState: function(state) { + return { + base: CodeMirror.copyState(base, state.base), + overlay: CodeMirror.copyState(overlay, state.overlay), + basePos: state.basePos, baseCur: null, + overlayPos: state.overlayPos, overlayCur: null + }; + }, + + token: function(stream, state) { + if (stream.sol() || stream.string != state.lineSeen || + Math.min(state.basePos, state.overlayPos) < stream.start) { + state.lineSeen = stream.string; + state.basePos = state.overlayPos = stream.start; + } + + if (stream.start == state.basePos) { + state.baseCur = base.token(stream, state.base); + state.basePos = stream.pos; + } + if (stream.start == state.overlayPos) { + stream.pos = stream.start; + state.overlayCur = overlay.token(stream, state.overlay); + state.overlayPos = stream.pos; + } + stream.pos = Math.min(state.basePos, state.overlayPos); + + // state.overlay.combineTokens always takes precedence over combine, + // unless set to null + if (state.overlayCur == null) return state.baseCur; + else if (state.baseCur != null && + state.overlay.combineTokens || + combine && state.overlay.combineTokens == null) + return state.baseCur + " " + state.overlayCur; + else return state.overlayCur; + }, + + indent: base.indent && function(state, textAfter) { + return base.indent(state.base, textAfter); + }, + electricChars: base.electricChars, + + innerMode: function(state) { return {state: state.base, mode: base}; }, + + blankLine: function(state) { + if (base.blankLine) base.blankLine(state.base); + if (overlay.blankLine) overlay.blankLine(state.overlay); + } + }; +}; + +}); diff --git a/Upload/admin/jscripts/codemirror/addon/runmode/colorize.js b/Upload/admin/jscripts/codemirror/addon/runmode/colorize.js new file mode 100644 index 0000000..eb7060d --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/runmode/colorize.js @@ -0,0 +1,40 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./runmode")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./runmode"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/; + + function textContent(node, out) { + if (node.nodeType == 3) return out.push(node.nodeValue); + for (var ch = node.firstChild; ch; ch = ch.nextSibling) { + textContent(ch, out); + if (isBlock.test(node.nodeType)) out.push("\n"); + } + } + + CodeMirror.colorize = function(collection, defaultMode) { + if (!collection) collection = document.body.getElementsByTagName("pre"); + + for (var i = 0; i < collection.length; ++i) { + var node = collection[i]; + var mode = node.getAttribute("data-lang") || defaultMode; + if (!mode) continue; + + var text = []; + textContent(node, text); + node.innerHTML = ""; + CodeMirror.runMode(text.join(""), mode, node); + + node.className += " cm-s-default"; + } + }; +}); diff --git a/Upload/admin/jscripts/codemirror/addon/runmode/runmode-standalone.js b/Upload/admin/jscripts/codemirror/addon/runmode/runmode-standalone.js new file mode 100644 index 0000000..0dd0c28 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/runmode/runmode-standalone.js @@ -0,0 +1,153 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +window.CodeMirror = {}; + +(function() { +"use strict"; + +function splitLines(string){ return string.split(/\r?\n|\r/); }; + +function StringStream(string) { + this.pos = this.start = 0; + this.string = string; + this.lineStart = 0; +} +StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == 0;}, + peek: function() {return this.string.charAt(this.pos) || null;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() {return this.start - this.lineStart;}, + indentation: function() {return 0;}, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + } +}; +CodeMirror.StringStream = StringStream; + +CodeMirror.startState = function (mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; +}; + +var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; +CodeMirror.defineMode = function (name, mode) { modes[name] = mode; }; +CodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; }; +CodeMirror.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + spec = mimeModes[spec.name]; + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; +}; +CodeMirror.getMode = function (options, spec) { + spec = CodeMirror.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) throw new Error("Unknown mode: " + spec); + return mfactory(options, spec); +}; +CodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min; +CodeMirror.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; +}); +CodeMirror.defineMIME("text/plain", "null"); + +CodeMirror.runMode = function (string, modespec, callback, options) { + var mode = CodeMirror.getMode({ indentUnit: 2 }, modespec); + + if (callback.nodeType == 1) { + var tabSize = (options && options.tabSize) || 4; + var node = callback, col = 0; + node.innerHTML = ""; + callback = function (text, style) { + if (text == "\n") { + node.appendChild(document.createElement("br")); + col = 0; + return; + } + var content = ""; + // replace tabs + for (var pos = 0; ;) { + var idx = text.indexOf("\t", pos); + if (idx == -1) { + content += text.slice(pos); + col += text.length - pos; + break; + } else { + col += idx - pos; + content += text.slice(pos, idx); + var size = tabSize - col % tabSize; + col += size; + for (var i = 0; i < size; ++i) content += " "; + pos = idx + 1; + } + } + + if (style) { + var sp = node.appendChild(document.createElement("span")); + sp.className = "cm-" + style.replace(/ +/g, " cm-"); + sp.appendChild(document.createTextNode(content)); + } else { + node.appendChild(document.createTextNode(content)); + } + }; + } + + var lines = splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); + for (var i = 0, e = lines.length; i < e; ++i) { + if (i) callback("\n"); + var stream = new CodeMirror.StringStream(lines[i]); + if (!stream.string && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start, state); + stream.start = stream.pos; + } + } +}; +})(); diff --git a/Upload/admin/jscripts/codemirror/addon/runmode/runmode.js b/Upload/admin/jscripts/codemirror/addon/runmode/runmode.js new file mode 100644 index 0000000..07d2279 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/runmode/runmode.js @@ -0,0 +1,72 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.runMode = function(string, modespec, callback, options) { + var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); + var ie = /MSIE \d/.test(navigator.userAgent); + var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); + + if (callback.nodeType == 1) { + var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; + var node = callback, col = 0; + node.innerHTML = ""; + callback = function(text, style) { + if (text == "\n") { + // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. + // Emitting a carriage return makes everything ok. + node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); + col = 0; + return; + } + var content = ""; + // replace tabs + for (var pos = 0;;) { + var idx = text.indexOf("\t", pos); + if (idx == -1) { + content += text.slice(pos); + col += text.length - pos; + break; + } else { + col += idx - pos; + content += text.slice(pos, idx); + var size = tabSize - col % tabSize; + col += size; + for (var i = 0; i < size; ++i) content += " "; + pos = idx + 1; + } + } + + if (style) { + var sp = node.appendChild(document.createElement("span")); + sp.className = "cm-" + style.replace(/ +/g, " cm-"); + sp.appendChild(document.createTextNode(content)); + } else { + node.appendChild(document.createTextNode(content)); + } + }; + } + + var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); + for (var i = 0, e = lines.length; i < e; ++i) { + if (i) callback("\n"); + var stream = new CodeMirror.StringStream(lines[i]); + if (!stream.string && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start, state); + stream.start = stream.pos; + } + } +}; + +}); diff --git a/Upload/admin/jscripts/codemirror/addon/runmode/runmode.node.js b/Upload/admin/jscripts/codemirror/addon/runmode/runmode.node.js new file mode 100644 index 0000000..f64b8a1 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/runmode/runmode.node.js @@ -0,0 +1,122 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/* Just enough of CodeMirror to run runMode under node.js */ + +// declare global: StringStream + +function splitLines(string){ return string.split(/\r?\n|\r/); }; + +function StringStream(string) { + this.pos = this.start = 0; + this.string = string; + this.lineStart = 0; +} +StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == 0;}, + peek: function() {return this.string.charAt(this.pos) || null;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() {return this.start - this.lineStart;}, + indentation: function() {return 0;}, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + } +}; +exports.StringStream = StringStream; + +exports.startState = function(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; +}; + +var modes = exports.modes = {}, mimeModes = exports.mimeModes = {}; +exports.defineMode = function(name, mode) { + if (arguments.length > 2) { + mode.dependencies = []; + for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]); + } + modes[name] = mode; +}; +exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; }; + +exports.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; +}); +exports.defineMIME("text/plain", "null"); + +exports.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + spec = mimeModes[spec.name]; + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; +}; +exports.getMode = function(options, spec) { + spec = exports.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) throw new Error("Unknown mode: " + spec); + return mfactory(options, spec); +}; +exports.registerHelper = exports.registerGlobalHelper = Math.min; + +exports.runMode = function(string, modespec, callback, options) { + var mode = exports.getMode({indentUnit: 2}, modespec); + var lines = splitLines(string), state = (options && options.state) || exports.startState(mode); + for (var i = 0, e = lines.length; i < e; ++i) { + if (i) callback("\n"); + var stream = new exports.StringStream(lines[i]); + if (!stream.string && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start, state); + stream.start = stream.pos; + } + } +}; + +require.cache[require.resolve("../../lib/codemirror")] = require.cache[require.resolve("./runmode.node")]; diff --git a/Upload/admin/jscripts/codemirror/addon/scroll/scrollpastend.js b/Upload/admin/jscripts/codemirror/addon/scroll/scrollpastend.js new file mode 100644 index 0000000..008ae4c --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/scroll/scrollpastend.js @@ -0,0 +1,46 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("scrollPastEnd", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.off("change", onChange); + cm.off("refresh", updateBottomMargin); + cm.display.lineSpace.parentNode.style.paddingBottom = ""; + cm.state.scrollPastEndPadding = null; + } + if (val) { + cm.on("change", onChange); + cm.on("refresh", updateBottomMargin); + updateBottomMargin(cm); + } + }); + + function onChange(cm, change) { + if (CodeMirror.changeEnd(change).line == cm.lastLine()) + updateBottomMargin(cm); + } + + function updateBottomMargin(cm) { + var padding = ""; + if (cm.lineCount() > 1) { + var totalH = cm.display.scroller.clientHeight - 30, + lastLineH = cm.getLineHandle(cm.lastLine()).height; + padding = (totalH - lastLineH) + "px"; + } + if (cm.state.scrollPastEndPadding != padding) { + cm.state.scrollPastEndPadding = padding; + cm.display.lineSpace.parentNode.style.paddingBottom = padding; + cm.setSize(); + } + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/search/index.html b/Upload/admin/jscripts/codemirror/addon/search/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/search/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/jscripts/codemirror/addon/search/match-highlighter.js b/Upload/admin/jscripts/codemirror/addon/search/match-highlighter.js new file mode 100644 index 0000000..14dd4d4 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/search/match-highlighter.js @@ -0,0 +1,104 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Highlighting text that matches the selection +// +// Defines an option highlightSelectionMatches, which, when enabled, +// will style strings that match the selection throughout the +// document. +// +// The option can be set to true to simply enable it, or to a +// {minChars, style, showToken} object to explicitly configure it. +// minChars is the minimum amount of characters that should be +// selected for the behavior to occur, and style is the token style to +// apply to the matches. This will be prefixed by "cm-" to create an +// actual CSS class name. showToken, when enabled, will cause the +// current token to be highlighted when nothing is selected. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var DEFAULT_MIN_CHARS = 2; + var DEFAULT_TOKEN_STYLE = "matchhighlight"; + var DEFAULT_DELAY = 100; + + function State(options) { + if (typeof options == "object") { + this.minChars = options.minChars; + this.style = options.style; + this.showToken = options.showToken; + this.delay = options.delay; + } + if (this.style == null) this.style = DEFAULT_TOKEN_STYLE; + if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS; + if (this.delay == null) this.delay = DEFAULT_DELAY; + this.overlay = this.timeout = null; + } + + CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + var over = cm.state.matchHighlighter.overlay; + if (over) cm.removeOverlay(over); + clearTimeout(cm.state.matchHighlighter.timeout); + cm.state.matchHighlighter = null; + cm.off("cursorActivity", cursorActivity); + } + if (val) { + cm.state.matchHighlighter = new State(val); + highlightMatches(cm); + cm.on("cursorActivity", cursorActivity); + } + }); + + function cursorActivity(cm) { + var state = cm.state.matchHighlighter; + clearTimeout(state.timeout); + state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay); + } + + function highlightMatches(cm) { + cm.operation(function() { + var state = cm.state.matchHighlighter; + if (state.overlay) { + cm.removeOverlay(state.overlay); + state.overlay = null; + } + if (!cm.somethingSelected() && state.showToken) { + var re = state.showToken === true ? /[\w$]/ : state.showToken; + var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start; + while (start && re.test(line.charAt(start - 1))) --start; + while (end < line.length && re.test(line.charAt(end))) ++end; + if (start < end) + cm.addOverlay(state.overlay = makeOverlay(line.slice(start, end), re, state.style)); + return; + } + var from = cm.getCursor("from"), to = cm.getCursor("to"); + if (from.line != to.line) return; + var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, ""); + if (selection.length >= state.minChars) + cm.addOverlay(state.overlay = makeOverlay(selection, false, state.style)); + }); + } + + function boundariesAround(stream, re) { + return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) && + (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos))); + } + + function makeOverlay(query, hasBoundary, style) { + return {token: function(stream) { + if (stream.match(query) && + (!hasBoundary || boundariesAround(stream, hasBoundary))) + return style; + stream.next(); + stream.skipTo(query.charAt(0)) || stream.skipToEnd(); + }}; + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/search/search.js b/Upload/admin/jscripts/codemirror/addon/search/search.js new file mode 100644 index 0000000..3ce7cc9 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/search/search.js @@ -0,0 +1,158 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Define search commands. Depends on dialog.js or another +// implementation of the openDialog method. + +// Replace works a little oddly -- it will do the replace on the next +// Ctrl-G (or whatever is bound to findNext) press. You prevent a +// replace by making sure the match is no longer selected when hitting +// Ctrl-G. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + function searchOverlay(query, caseInsensitive) { + if (typeof query == "string") + query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g"); + else if (!query.global) + query = new RegExp(query.source, query.ignoreCase ? "gi" : "g"); + + return {token: function(stream) { + query.lastIndex = stream.pos; + var match = query.exec(stream.string); + if (match && match.index == stream.pos) { + stream.pos += match[0].length; + return "searching"; + } else if (match) { + stream.pos = match.index; + } else { + stream.skipToEnd(); + } + }}; + } + + function SearchState() { + this.posFrom = this.posTo = this.query = null; + this.overlay = null; + } + function getSearchState(cm) { + return cm.state.search || (cm.state.search = new SearchState()); + } + function queryCaseInsensitive(query) { + return typeof query == "string" && query == query.toLowerCase(); + } + function getSearchCursor(cm, query, pos) { + // Heuristic: if the query string is all lowercase, do a case insensitive search. + return cm.getSearchCursor(query, pos, queryCaseInsensitive(query)); + } + function dialog(cm, text, shortText, deflt, f) { + if (cm.openDialog) cm.openDialog(text, f, {value: deflt}); + else f(prompt(shortText, deflt)); + } + function confirmDialog(cm, text, shortText, fs) { + if (cm.openConfirm) cm.openConfirm(text, fs); + else if (confirm(shortText)) fs[0](); + } + function parseQuery(query) { + var isRE = query.match(/^\/(.*)\/([a-z]*)$/); + if (isRE) { + query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); + if (query.test("")) query = /x^/; + } else if (query == "") { + query = /x^/; + } + return query; + } + var queryDialog = + 'Search: (Use /re/ syntax for regexp search)'; + function doSearch(cm, rev) { + var state = getSearchState(cm); + if (state.query) return findNext(cm, rev); + dialog(cm, queryDialog, "Search for:", cm.getSelection(), function(query) { + cm.operation(function() { + if (!query || state.query) return; + state.query = parseQuery(query); + cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query)); + state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query)); + cm.addOverlay(state.overlay); + state.posFrom = state.posTo = cm.getCursor(); + findNext(cm, rev); + }); + }); + } + function findNext(cm, rev) {cm.operation(function() { + var state = getSearchState(cm); + var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo); + if (!cursor.find(rev)) { + cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0)); + if (!cursor.find(rev)) return; + } + cm.setSelection(cursor.from(), cursor.to()); + cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); + state.posFrom = cursor.from(); state.posTo = cursor.to(); + });} + function clearSearch(cm) {cm.operation(function() { + var state = getSearchState(cm); + if (!state.query) return; + state.query = null; + cm.removeOverlay(state.overlay); + });} + + var replaceQueryDialog = + 'Replace: (Use /re/ syntax for regexp search)'; + var replacementQueryDialog = 'With: '; + var doReplaceConfirm = "Replace? "; + function replace(cm, all) { + dialog(cm, replaceQueryDialog, "Replace:", cm.getSelection(), function(query) { + if (!query) return; + query = parseQuery(query); + dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) { + if (all) { + cm.operation(function() { + for (var cursor = getSearchCursor(cm, query); cursor.findNext();) { + if (typeof query != "string") { + var match = cm.getRange(cursor.from(), cursor.to()).match(query); + cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];})); + } else cursor.replace(text); + } + }); + } else { + clearSearch(cm); + var cursor = getSearchCursor(cm, query, cm.getCursor()); + var advance = function() { + var start = cursor.from(), match; + if (!(match = cursor.findNext())) { + cursor = getSearchCursor(cm, query); + if (!(match = cursor.findNext()) || + (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return; + } + cm.setSelection(cursor.from(), cursor.to()); + cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); + confirmDialog(cm, doReplaceConfirm, "Replace?", + [function() {doReplace(match);}, advance]); + }; + var doReplace = function(match) { + cursor.replace(typeof query == "string" ? text : + text.replace(/\$(\d)/g, function(_, i) {return match[i];})); + advance(); + }; + advance(); + } + }); + }); + } + + CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);}; + CodeMirror.commands.findNext = doSearch; + CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);}; + CodeMirror.commands.clearSearch = clearSearch; + CodeMirror.commands.replace = replace; + CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);}; +}); diff --git a/Upload/admin/jscripts/codemirror/addon/search/searchcursor.js b/Upload/admin/jscripts/codemirror/addon/search/searchcursor.js new file mode 100644 index 0000000..2783308 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/search/searchcursor.js @@ -0,0 +1,189 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var Pos = CodeMirror.Pos; + + function SearchCursor(doc, query, pos, caseFold) { + this.atOccurrence = false; this.doc = doc; + if (caseFold == null && typeof query == "string") caseFold = false; + + pos = pos ? doc.clipPos(pos) : Pos(0, 0); + this.pos = {from: pos, to: pos}; + + // The matches method is filled in based on the type of query. + // It takes a position and a direction, and returns an object + // describing the next occurrence of the query, or null if no + // more matches were found. + if (typeof query != "string") { // Regexp match + if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g"); + this.matches = function(reverse, pos) { + if (reverse) { + query.lastIndex = 0; + var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start; + for (;;) { + query.lastIndex = cutOff; + var newMatch = query.exec(line); + if (!newMatch) break; + match = newMatch; + start = match.index; + cutOff = match.index + (match[0].length || 1); + if (cutOff == line.length) break; + } + var matchLen = (match && match[0].length) || 0; + if (!matchLen) { + if (start == 0 && line.length == 0) {match = undefined;} + else if (start != doc.getLine(pos.line).length) { + matchLen++; + } + } + } else { + query.lastIndex = pos.ch; + var line = doc.getLine(pos.line), match = query.exec(line); + var matchLen = (match && match[0].length) || 0; + var start = match && match.index; + if (start + matchLen != line.length && !matchLen) matchLen = 1; + } + if (match && matchLen) + return {from: Pos(pos.line, start), + to: Pos(pos.line, start + matchLen), + match: match}; + }; + } else { // String query + var origQuery = query; + if (caseFold) query = query.toLowerCase(); + var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;}; + var target = query.split("\n"); + // Different methods for single-line and multi-line queries + if (target.length == 1) { + if (!query.length) { + // Empty string would match anything and never progress, so + // we define it to match nothing instead. + this.matches = function() {}; + } else { + this.matches = function(reverse, pos) { + if (reverse) { + var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig); + var match = line.lastIndexOf(query); + if (match > -1) { + match = adjustPos(orig, line, match); + return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)}; + } + } else { + var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig); + var match = line.indexOf(query); + if (match > -1) { + match = adjustPos(orig, line, match) + pos.ch; + return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)}; + } + } + }; + } + } else { + var origTarget = origQuery.split("\n"); + this.matches = function(reverse, pos) { + var last = target.length - 1; + if (reverse) { + if (pos.line - (target.length - 1) < doc.firstLine()) return; + if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return; + var to = Pos(pos.line, origTarget[last].length); + for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln) + if (target[i] != fold(doc.getLine(ln))) return; + var line = doc.getLine(ln), cut = line.length - origTarget[0].length; + if (fold(line.slice(cut)) != target[0]) return; + return {from: Pos(ln, cut), to: to}; + } else { + if (pos.line + (target.length - 1) > doc.lastLine()) return; + var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length; + if (fold(line.slice(cut)) != target[0]) return; + var from = Pos(pos.line, cut); + for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln) + if (target[i] != fold(doc.getLine(ln))) return; + if (doc.getLine(ln).slice(0, origTarget[last].length) != target[last]) return; + return {from: from, to: Pos(ln, origTarget[last].length)}; + } + }; + } + } + } + + SearchCursor.prototype = { + findNext: function() {return this.find(false);}, + findPrevious: function() {return this.find(true);}, + + find: function(reverse) { + var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to); + function savePosAndFail(line) { + var pos = Pos(line, 0); + self.pos = {from: pos, to: pos}; + self.atOccurrence = false; + return false; + } + + for (;;) { + if (this.pos = this.matches(reverse, pos)) { + this.atOccurrence = true; + return this.pos.match || true; + } + if (reverse) { + if (!pos.line) return savePosAndFail(0); + pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length); + } + else { + var maxLine = this.doc.lineCount(); + if (pos.line == maxLine - 1) return savePosAndFail(maxLine); + pos = Pos(pos.line + 1, 0); + } + } + }, + + from: function() {if (this.atOccurrence) return this.pos.from;}, + to: function() {if (this.atOccurrence) return this.pos.to;}, + + replace: function(newText) { + if (!this.atOccurrence) return; + var lines = CodeMirror.splitLines(newText); + this.doc.replaceRange(lines, this.pos.from, this.pos.to); + this.pos.to = Pos(this.pos.from.line + lines.length - 1, + lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0)); + } + }; + + // Maps a position in a case-folded line back to a position in the original line + // (compensating for codepoints increasing in number during folding) + function adjustPos(orig, folded, pos) { + if (orig.length == folded.length) return pos; + for (var pos1 = Math.min(pos, orig.length);;) { + var len1 = orig.slice(0, pos1).toLowerCase().length; + if (len1 < pos) ++pos1; + else if (len1 > pos) --pos1; + else return pos1; + } + } + + CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) { + return new SearchCursor(this.doc, query, pos, caseFold); + }); + CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) { + return new SearchCursor(this, query, pos, caseFold); + }); + + CodeMirror.defineExtension("selectMatches", function(query, caseFold) { + var ranges = [], next; + var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold); + while (next = cur.findNext()) { + if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break; + ranges.push({anchor: cur.from(), head: cur.to()}); + } + if (ranges.length) + this.setSelections(ranges, 0); + }); +}); diff --git a/Upload/admin/jscripts/codemirror/addon/selection/active-line.js b/Upload/admin/jscripts/codemirror/addon/selection/active-line.js new file mode 100644 index 0000000..22da2e0 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/selection/active-line.js @@ -0,0 +1,71 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Because sometimes you need to style the cursor's line. +// +// Adds an option 'styleActiveLine' which, when enabled, gives the +// active line's wrapping
the CSS class "CodeMirror-activeline", +// and gives its background
the class "CodeMirror-activeline-background". + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var WRAP_CLASS = "CodeMirror-activeline"; + var BACK_CLASS = "CodeMirror-activeline-background"; + + CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm.state.activeLines = []; + updateActiveLines(cm, cm.listSelections()); + cm.on("beforeSelectionChange", selectionChange); + } else if (!val && prev) { + cm.off("beforeSelectionChange", selectionChange); + clearActiveLines(cm); + delete cm.state.activeLines; + } + }); + + function clearActiveLines(cm) { + for (var i = 0; i < cm.state.activeLines.length; i++) { + cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS); + cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS); + } + } + + function sameArray(a, b) { + if (a.length != b.length) return false; + for (var i = 0; i < a.length; i++) + if (a[i] != b[i]) return false; + return true; + } + + function updateActiveLines(cm, ranges) { + var active = []; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (!range.empty()) continue; + var line = cm.getLineHandleVisualStart(range.head.line); + if (active[active.length - 1] != line) active.push(line); + } + if (sameArray(cm.state.activeLines, active)) return; + cm.operation(function() { + clearActiveLines(cm); + for (var i = 0; i < active.length; i++) { + cm.addLineClass(active[i], "wrap", WRAP_CLASS); + cm.addLineClass(active[i], "background", BACK_CLASS); + } + cm.state.activeLines = active; + }); + } + + function selectionChange(cm, sel) { + updateActiveLines(cm, sel.ranges); + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/selection/mark-selection.js b/Upload/admin/jscripts/codemirror/addon/selection/mark-selection.js new file mode 100644 index 0000000..5c42d21 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/selection/mark-selection.js @@ -0,0 +1,118 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Because sometimes you need to mark the selected *text*. +// +// Adds an option 'styleSelectedText' which, when enabled, gives +// selected text the CSS class given as option value, or +// "CodeMirror-selectedtext" when the value is not a string. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm.state.markedSelection = []; + cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext"; + reset(cm); + cm.on("cursorActivity", onCursorActivity); + cm.on("change", onChange); + } else if (!val && prev) { + cm.off("cursorActivity", onCursorActivity); + cm.off("change", onChange); + clear(cm); + cm.state.markedSelection = cm.state.markedSelectionStyle = null; + } + }); + + function onCursorActivity(cm) { + cm.operation(function() { update(cm); }); + } + + function onChange(cm) { + if (cm.state.markedSelection.length) + cm.operation(function() { clear(cm); }); + } + + var CHUNK_SIZE = 8; + var Pos = CodeMirror.Pos; + var cmp = CodeMirror.cmpPos; + + function coverRange(cm, from, to, addAt) { + if (cmp(from, to) == 0) return; + var array = cm.state.markedSelection; + var cls = cm.state.markedSelectionStyle; + for (var line = from.line;;) { + var start = line == from.line ? from : Pos(line, 0); + var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line; + var end = atEnd ? to : Pos(endLine, 0); + var mark = cm.markText(start, end, {className: cls}); + if (addAt == null) array.push(mark); + else array.splice(addAt++, 0, mark); + if (atEnd) break; + line = endLine; + } + } + + function clear(cm) { + var array = cm.state.markedSelection; + for (var i = 0; i < array.length; ++i) array[i].clear(); + array.length = 0; + } + + function reset(cm) { + clear(cm); + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) + coverRange(cm, ranges[i].from(), ranges[i].to()); + } + + function update(cm) { + if (!cm.somethingSelected()) return clear(cm); + if (cm.listSelections().length > 1) return reset(cm); + + var from = cm.getCursor("start"), to = cm.getCursor("end"); + + var array = cm.state.markedSelection; + if (!array.length) return coverRange(cm, from, to); + + var coverStart = array[0].find(), coverEnd = array[array.length - 1].find(); + if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE || + cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0) + return reset(cm); + + while (cmp(from, coverStart.from) > 0) { + array.shift().clear(); + coverStart = array[0].find(); + } + if (cmp(from, coverStart.from) < 0) { + if (coverStart.to.line - from.line < CHUNK_SIZE) { + array.shift().clear(); + coverRange(cm, from, coverStart.to, 0); + } else { + coverRange(cm, from, coverStart.from, 0); + } + } + + while (cmp(to, coverEnd.to) < 0) { + array.pop().clear(); + coverEnd = array[array.length - 1].find(); + } + if (cmp(to, coverEnd.to) > 0) { + if (to.line - coverEnd.from.line < CHUNK_SIZE) { + array.pop().clear(); + coverRange(cm, coverEnd.from, to); + } else { + coverRange(cm, coverEnd.to, to); + } + } + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/tern/tern.css b/Upload/admin/jscripts/codemirror/addon/tern/tern.css new file mode 100644 index 0000000..76fba33 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/tern/tern.css @@ -0,0 +1,86 @@ +.CodeMirror-Tern-completion { + padding-left: 22px; + position: relative; +} +.CodeMirror-Tern-completion:before { + position: absolute; + left: 2px; + bottom: 2px; + border-radius: 50%; + font-size: 12px; + font-weight: bold; + height: 15px; + width: 15px; + line-height: 16px; + text-align: center; + color: white; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.CodeMirror-Tern-completion-unknown:before { + content: "?"; + background: #4bb; +} +.CodeMirror-Tern-completion-object:before { + content: "O"; + background: #77c; +} +.CodeMirror-Tern-completion-fn:before { + content: "F"; + background: #7c7; +} +.CodeMirror-Tern-completion-array:before { + content: "A"; + background: #c66; +} +.CodeMirror-Tern-completion-number:before { + content: "1"; + background: #999; +} +.CodeMirror-Tern-completion-string:before { + content: "S"; + background: #999; +} +.CodeMirror-Tern-completion-bool:before { + content: "B"; + background: #999; +} + +.CodeMirror-Tern-completion-guess { + color: #999; +} + +.CodeMirror-Tern-tooltip { + border: 1px solid silver; + border-radius: 3px; + color: #444; + padding: 2px 5px; + font-size: 90%; + font-family: monospace; + background-color: white; + white-space: pre-wrap; + + max-width: 40em; + position: absolute; + z-index: 10; + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + box-shadow: 2px 3px 5px rgba(0,0,0,.2); + + transition: opacity 1s; + -moz-transition: opacity 1s; + -webkit-transition: opacity 1s; + -o-transition: opacity 1s; + -ms-transition: opacity 1s; +} + +.CodeMirror-Tern-hint-doc { + max-width: 25em; + margin-top: -3px; +} + +.CodeMirror-Tern-fname { color: black; } +.CodeMirror-Tern-farg { color: #70a; } +.CodeMirror-Tern-farg-current { text-decoration: underline; } +.CodeMirror-Tern-type { color: #07c; } +.CodeMirror-Tern-fhint-guess { opacity: .7; } diff --git a/Upload/admin/jscripts/codemirror/addon/tern/tern.js b/Upload/admin/jscripts/codemirror/addon/tern/tern.js new file mode 100644 index 0000000..9bd6944 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/tern/tern.js @@ -0,0 +1,668 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Glue code between CodeMirror and Tern. +// +// Create a CodeMirror.TernServer to wrap an actual Tern server, +// register open documents (CodeMirror.Doc instances) with it, and +// call its methods to activate the assisting functions that Tern +// provides. +// +// Options supported (all optional): +// * defs: An array of JSON definition data structures. +// * plugins: An object mapping plugin names to configuration +// options. +// * getFile: A function(name, c) that can be used to access files in +// the project that haven't been loaded yet. Simply do c(null) to +// indicate that a file is not available. +// * fileFilter: A function(value, docName, doc) that will be applied +// to documents before passing them on to Tern. +// * switchToDoc: A function(name, doc) that should, when providing a +// multi-file view, switch the view or focus to the named file. +// * showError: A function(editor, message) that can be used to +// override the way errors are displayed. +// * completionTip: Customize the content in tooltips for completions. +// Is passed a single argument—the completion's data as returned by +// Tern—and may return a string, DOM node, or null to indicate that +// no tip should be shown. By default the docstring is shown. +// * typeTip: Like completionTip, but for the tooltips shown for type +// queries. +// * responseFilter: A function(doc, query, request, error, data) that +// will be applied to the Tern responses before treating them +// +// +// It is possible to run the Tern server in a web worker by specifying +// these additional options: +// * useWorker: Set to true to enable web worker mode. You'll probably +// want to feature detect the actual value you use here, for example +// !!window.Worker. +// * workerScript: The main script of the worker. Point this to +// wherever you are hosting worker.js from this directory. +// * workerDeps: An array of paths pointing (relative to workerScript) +// to the Acorn and Tern libraries and any Tern plugins you want to +// load. Or, if you minified those into a single script and included +// them in the workerScript, simply leave this undefined. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + // declare global: tern + + CodeMirror.TernServer = function(options) { + var self = this; + this.options = options || {}; + var plugins = this.options.plugins || (this.options.plugins = {}); + if (!plugins.doc_comment) plugins.doc_comment = true; + if (this.options.useWorker) { + this.server = new WorkerServer(this); + } else { + this.server = new tern.Server({ + getFile: function(name, c) { return getFile(self, name, c); }, + async: true, + defs: this.options.defs || [], + plugins: plugins + }); + } + this.docs = Object.create(null); + this.trackChange = function(doc, change) { trackChange(self, doc, change); }; + + this.cachedArgHints = null; + this.activeArgHints = null; + this.jumpStack = []; + + this.getHint = function(cm, c) { return hint(self, cm, c); }; + this.getHint.async = true; + }; + + CodeMirror.TernServer.prototype = { + addDoc: function(name, doc) { + var data = {doc: doc, name: name, changed: null}; + this.server.addFile(name, docValue(this, data)); + CodeMirror.on(doc, "change", this.trackChange); + return this.docs[name] = data; + }, + + delDoc: function(id) { + var found = resolveDoc(this, id); + if (!found) return; + CodeMirror.off(found.doc, "change", this.trackChange); + delete this.docs[found.name]; + this.server.delFile(found.name); + }, + + hideDoc: function(id) { + closeArgHints(this); + var found = resolveDoc(this, id); + if (found && found.changed) sendDoc(this, found); + }, + + complete: function(cm) { + cm.showHint({hint: this.getHint}); + }, + + showType: function(cm, pos, c) { showType(this, cm, pos, c); }, + + updateArgHints: function(cm) { updateArgHints(this, cm); }, + + jumpToDef: function(cm) { jumpToDef(this, cm); }, + + jumpBack: function(cm) { jumpBack(this, cm); }, + + rename: function(cm) { rename(this, cm); }, + + selectName: function(cm) { selectName(this, cm); }, + + request: function (cm, query, c, pos) { + var self = this; + var doc = findDoc(this, cm.getDoc()); + var request = buildRequest(this, doc, query, pos); + + this.server.request(request, function (error, data) { + if (!error && self.options.responseFilter) + data = self.options.responseFilter(doc, query, request, error, data); + c(error, data); + }); + } + }; + + var Pos = CodeMirror.Pos; + var cls = "CodeMirror-Tern-"; + var bigDoc = 250; + + function getFile(ts, name, c) { + var buf = ts.docs[name]; + if (buf) + c(docValue(ts, buf)); + else if (ts.options.getFile) + ts.options.getFile(name, c); + else + c(null); + } + + function findDoc(ts, doc, name) { + for (var n in ts.docs) { + var cur = ts.docs[n]; + if (cur.doc == doc) return cur; + } + if (!name) for (var i = 0;; ++i) { + n = "[doc" + (i || "") + "]"; + if (!ts.docs[n]) { name = n; break; } + } + return ts.addDoc(name, doc); + } + + function resolveDoc(ts, id) { + if (typeof id == "string") return ts.docs[id]; + if (id instanceof CodeMirror) id = id.getDoc(); + if (id instanceof CodeMirror.Doc) return findDoc(ts, id); + } + + function trackChange(ts, doc, change) { + var data = findDoc(ts, doc); + + var argHints = ts.cachedArgHints; + if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) <= 0) + ts.cachedArgHints = null; + + var changed = data.changed; + if (changed == null) + data.changed = changed = {from: change.from.line, to: change.from.line}; + var end = change.from.line + (change.text.length - 1); + if (change.from.line < changed.to) changed.to = changed.to - (change.to.line - end); + if (end >= changed.to) changed.to = end + 1; + if (changed.from > change.from.line) changed.from = change.from.line; + + if (doc.lineCount() > bigDoc && change.to - changed.from > 100) setTimeout(function() { + if (data.changed && data.changed.to - data.changed.from > 100) sendDoc(ts, data); + }, 200); + } + + function sendDoc(ts, doc) { + ts.server.request({files: [{type: "full", name: doc.name, text: docValue(ts, doc)}]}, function(error) { + if (error) window.console.error(error); + else doc.changed = null; + }); + } + + // Completion + + function hint(ts, cm, c) { + ts.request(cm, {type: "completions", types: true, docs: true, urls: true}, function(error, data) { + if (error) return showError(ts, cm, error); + var completions = [], after = ""; + var from = data.start, to = data.end; + if (cm.getRange(Pos(from.line, from.ch - 2), from) == "[\"" && + cm.getRange(to, Pos(to.line, to.ch + 2)) != "\"]") + after = "\"]"; + + for (var i = 0; i < data.completions.length; ++i) { + var completion = data.completions[i], className = typeToIcon(completion.type); + if (data.guess) className += " " + cls + "guess"; + completions.push({text: completion.name + after, + displayText: completion.name, + className: className, + data: completion}); + } + + var obj = {from: from, to: to, list: completions}; + var tooltip = null; + CodeMirror.on(obj, "close", function() { remove(tooltip); }); + CodeMirror.on(obj, "update", function() { remove(tooltip); }); + CodeMirror.on(obj, "select", function(cur, node) { + remove(tooltip); + var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc; + if (content) { + tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset, + node.getBoundingClientRect().top + window.pageYOffset, content); + tooltip.className += " " + cls + "hint-doc"; + } + }); + c(obj); + }); + } + + function typeToIcon(type) { + var suffix; + if (type == "?") suffix = "unknown"; + else if (type == "number" || type == "string" || type == "bool") suffix = type; + else if (/^fn\(/.test(type)) suffix = "fn"; + else if (/^\[/.test(type)) suffix = "array"; + else suffix = "object"; + return cls + "completion " + cls + "completion-" + suffix; + } + + // Type queries + + function showType(ts, cm, pos, c) { + ts.request(cm, "type", function(error, data) { + if (error) return showError(ts, cm, error); + if (ts.options.typeTip) { + var tip = ts.options.typeTip(data); + } else { + var tip = elt("span", null, elt("strong", null, data.type || "not found")); + if (data.doc) + tip.appendChild(document.createTextNode(" — " + data.doc)); + if (data.url) { + tip.appendChild(document.createTextNode(" ")); + tip.appendChild(elt("a", null, "[docs]")).href = data.url; + } + } + tempTooltip(cm, tip); + if (c) c(); + }, pos); + } + + // Maintaining argument hints + + function updateArgHints(ts, cm) { + closeArgHints(ts); + + if (cm.somethingSelected()) return; + var state = cm.getTokenAt(cm.getCursor()).state; + var inner = CodeMirror.innerMode(cm.getMode(), state); + if (inner.mode.name != "javascript") return; + var lex = inner.state.lexical; + if (lex.info != "call") return; + + var ch, argPos = lex.pos || 0, tabSize = cm.getOption("tabSize"); + for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) { + var str = cm.getLine(line), extra = 0; + for (var pos = 0;;) { + var tab = str.indexOf("\t", pos); + if (tab == -1) break; + extra += tabSize - (tab + extra) % tabSize - 1; + pos = tab + 1; + } + ch = lex.column - extra; + if (str.charAt(ch) == "(") {found = true; break;} + } + if (!found) return; + + var start = Pos(line, ch); + var cache = ts.cachedArgHints; + if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0) + return showArgHints(ts, cm, argPos); + + ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) { + if (error || !data.type || !(/^fn\(/).test(data.type)) return; + ts.cachedArgHints = { + start: pos, + type: parseFnType(data.type), + name: data.exprName || data.name || "fn", + guess: data.guess, + doc: cm.getDoc() + }; + showArgHints(ts, cm, argPos); + }); + } + + function showArgHints(ts, cm, pos) { + closeArgHints(ts); + + var cache = ts.cachedArgHints, tp = cache.type; + var tip = elt("span", cache.guess ? cls + "fhint-guess" : null, + elt("span", cls + "fname", cache.name), "("); + for (var i = 0; i < tp.args.length; ++i) { + if (i) tip.appendChild(document.createTextNode(", ")); + var arg = tp.args[i]; + tip.appendChild(elt("span", cls + "farg" + (i == pos ? " " + cls + "farg-current" : ""), arg.name || "?")); + if (arg.type != "?") { + tip.appendChild(document.createTextNode(":\u00a0")); + tip.appendChild(elt("span", cls + "type", arg.type)); + } + } + tip.appendChild(document.createTextNode(tp.rettype ? ") ->\u00a0" : ")")); + if (tp.rettype) tip.appendChild(elt("span", cls + "type", tp.rettype)); + var place = cm.cursorCoords(null, "page"); + ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip); + } + + function parseFnType(text) { + var args = [], pos = 3; + + function skipMatching(upto) { + var depth = 0, start = pos; + for (;;) { + var next = text.charAt(pos); + if (upto.test(next) && !depth) return text.slice(start, pos); + if (/[{\[\(]/.test(next)) ++depth; + else if (/[}\]\)]/.test(next)) --depth; + ++pos; + } + } + + // Parse arguments + if (text.charAt(pos) != ")") for (;;) { + var name = text.slice(pos).match(/^([^, \(\[\{]+): /); + if (name) { + pos += name[0].length; + name = name[1]; + } + args.push({name: name, type: skipMatching(/[\),]/)}); + if (text.charAt(pos) == ")") break; + pos += 2; + } + + var rettype = text.slice(pos).match(/^\) -> (.*)$/); + + return {args: args, rettype: rettype && rettype[1]}; + } + + // Moving to the definition of something + + function jumpToDef(ts, cm) { + function inner(varName) { + var req = {type: "definition", variable: varName || null}; + var doc = findDoc(ts, cm.getDoc()); + ts.server.request(buildRequest(ts, doc, req), function(error, data) { + if (error) return showError(ts, cm, error); + if (!data.file && data.url) { window.open(data.url); return; } + + if (data.file) { + var localDoc = ts.docs[data.file], found; + if (localDoc && (found = findContext(localDoc.doc, data))) { + ts.jumpStack.push({file: doc.name, + start: cm.getCursor("from"), + end: cm.getCursor("to")}); + moveTo(ts, doc, localDoc, found.start, found.end); + return; + } + } + showError(ts, cm, "Could not find a definition."); + }); + } + + if (!atInterestingExpression(cm)) + dialog(cm, "Jump to variable", function(name) { if (name) inner(name); }); + else + inner(); + } + + function jumpBack(ts, cm) { + var pos = ts.jumpStack.pop(), doc = pos && ts.docs[pos.file]; + if (!doc) return; + moveTo(ts, findDoc(ts, cm.getDoc()), doc, pos.start, pos.end); + } + + function moveTo(ts, curDoc, doc, start, end) { + doc.doc.setSelection(start, end); + if (curDoc != doc && ts.options.switchToDoc) { + closeArgHints(ts); + ts.options.switchToDoc(doc.name, doc.doc); + } + } + + // The {line,ch} representation of positions makes this rather awkward. + function findContext(doc, data) { + var before = data.context.slice(0, data.contextOffset).split("\n"); + var startLine = data.start.line - (before.length - 1); + var start = Pos(startLine, (before.length == 1 ? data.start.ch : doc.getLine(startLine).length) - before[0].length); + + var text = doc.getLine(startLine).slice(start.ch); + for (var cur = startLine + 1; cur < doc.lineCount() && text.length < data.context.length; ++cur) + text += "\n" + doc.getLine(cur); + if (text.slice(0, data.context.length) == data.context) return data; + + var cursor = doc.getSearchCursor(data.context, 0, false); + var nearest, nearestDist = Infinity; + while (cursor.findNext()) { + var from = cursor.from(), dist = Math.abs(from.line - start.line) * 10000; + if (!dist) dist = Math.abs(from.ch - start.ch); + if (dist < nearestDist) { nearest = from; nearestDist = dist; } + } + if (!nearest) return null; + + if (before.length == 1) + nearest.ch += before[0].length; + else + nearest = Pos(nearest.line + (before.length - 1), before[before.length - 1].length); + if (data.start.line == data.end.line) + var end = Pos(nearest.line, nearest.ch + (data.end.ch - data.start.ch)); + else + var end = Pos(nearest.line + (data.end.line - data.start.line), data.end.ch); + return {start: nearest, end: end}; + } + + function atInterestingExpression(cm) { + var pos = cm.getCursor("end"), tok = cm.getTokenAt(pos); + if (tok.start < pos.ch && (tok.type == "comment" || tok.type == "string")) return false; + return /\w/.test(cm.getLine(pos.line).slice(Math.max(pos.ch - 1, 0), pos.ch + 1)); + } + + // Variable renaming + + function rename(ts, cm) { + var token = cm.getTokenAt(cm.getCursor()); + if (!/\w/.test(token.string)) return showError(ts, cm, "Not at a variable"); + dialog(cm, "New name for " + token.string, function(newName) { + ts.request(cm, {type: "rename", newName: newName, fullDocs: true}, function(error, data) { + if (error) return showError(ts, cm, error); + applyChanges(ts, data.changes); + }); + }); + } + + function selectName(ts, cm) { + var name = findDoc(ts, cm.doc).name; + ts.request(cm, {type: "refs"}, function(error, data) { + if (error) return showError(ts, cm, error); + var ranges = [], cur = 0; + for (var i = 0; i < data.refs.length; i++) { + var ref = data.refs[i]; + if (ref.file == name) { + ranges.push({anchor: ref.start, head: ref.end}); + if (cmpPos(cur, ref.start) >= 0 && cmpPos(cur, ref.end) <= 0) + cur = ranges.length - 1; + } + } + cm.setSelections(ranges, cur); + }); + } + + var nextChangeOrig = 0; + function applyChanges(ts, changes) { + var perFile = Object.create(null); + for (var i = 0; i < changes.length; ++i) { + var ch = changes[i]; + (perFile[ch.file] || (perFile[ch.file] = [])).push(ch); + } + for (var file in perFile) { + var known = ts.docs[file], chs = perFile[file];; + if (!known) continue; + chs.sort(function(a, b) { return cmpPos(b.start, a.start); }); + var origin = "*rename" + (++nextChangeOrig); + for (var i = 0; i < chs.length; ++i) { + var ch = chs[i]; + known.doc.replaceRange(ch.text, ch.start, ch.end, origin); + } + } + } + + // Generic request-building helper + + function buildRequest(ts, doc, query, pos) { + var files = [], offsetLines = 0, allowFragments = !query.fullDocs; + if (!allowFragments) delete query.fullDocs; + if (typeof query == "string") query = {type: query}; + query.lineCharPositions = true; + if (query.end == null) { + query.end = pos || doc.doc.getCursor("end"); + if (doc.doc.somethingSelected()) + query.start = doc.doc.getCursor("start"); + } + var startPos = query.start || query.end; + + if (doc.changed) { + if (doc.doc.lineCount() > bigDoc && allowFragments !== false && + doc.changed.to - doc.changed.from < 100 && + doc.changed.from <= startPos.line && doc.changed.to > query.end.line) { + files.push(getFragmentAround(doc, startPos, query.end)); + query.file = "#0"; + var offsetLines = files[0].offsetLines; + if (query.start != null) query.start = Pos(query.start.line - -offsetLines, query.start.ch); + query.end = Pos(query.end.line - offsetLines, query.end.ch); + } else { + files.push({type: "full", + name: doc.name, + text: docValue(ts, doc)}); + query.file = doc.name; + doc.changed = null; + } + } else { + query.file = doc.name; + } + for (var name in ts.docs) { + var cur = ts.docs[name]; + if (cur.changed && cur != doc) { + files.push({type: "full", name: cur.name, text: docValue(ts, cur)}); + cur.changed = null; + } + } + + return {query: query, files: files}; + } + + function getFragmentAround(data, start, end) { + var doc = data.doc; + var minIndent = null, minLine = null, endLine, tabSize = 4; + for (var p = start.line - 1, min = Math.max(0, p - 50); p >= min; --p) { + var line = doc.getLine(p), fn = line.search(/\bfunction\b/); + if (fn < 0) continue; + var indent = CodeMirror.countColumn(line, null, tabSize); + if (minIndent != null && minIndent <= indent) continue; + minIndent = indent; + minLine = p; + } + if (minLine == null) minLine = min; + var max = Math.min(doc.lastLine(), end.line + 20); + if (minIndent == null || minIndent == CodeMirror.countColumn(doc.getLine(start.line), null, tabSize)) + endLine = max; + else for (endLine = end.line + 1; endLine < max; ++endLine) { + var indent = CodeMirror.countColumn(doc.getLine(endLine), null, tabSize); + if (indent <= minIndent) break; + } + var from = Pos(minLine, 0); + + return {type: "part", + name: data.name, + offsetLines: from.line, + text: doc.getRange(from, Pos(endLine, 0))}; + } + + // Generic utilities + + var cmpPos = CodeMirror.cmpPos; + + function elt(tagname, cls /*, ... elts*/) { + var e = document.createElement(tagname); + if (cls) e.className = cls; + for (var i = 2; i < arguments.length; ++i) { + var elt = arguments[i]; + if (typeof elt == "string") elt = document.createTextNode(elt); + e.appendChild(elt); + } + return e; + } + + function dialog(cm, text, f) { + if (cm.openDialog) + cm.openDialog(text + ": ", f); + else + f(prompt(text, "")); + } + + // Tooltips + + function tempTooltip(cm, content) { + var where = cm.cursorCoords(); + var tip = makeTooltip(where.right + 1, where.bottom, content); + function clear() { + if (!tip.parentNode) return; + cm.off("cursorActivity", clear); + fadeOut(tip); + } + setTimeout(clear, 1700); + cm.on("cursorActivity", clear); + } + + function makeTooltip(x, y, content) { + var node = elt("div", cls + "tooltip", content); + node.style.left = x + "px"; + node.style.top = y + "px"; + document.body.appendChild(node); + return node; + } + + function remove(node) { + var p = node && node.parentNode; + if (p) p.removeChild(node); + } + + function fadeOut(tooltip) { + tooltip.style.opacity = "0"; + setTimeout(function() { remove(tooltip); }, 1100); + } + + function showError(ts, cm, msg) { + if (ts.options.showError) + ts.options.showError(cm, msg); + else + tempTooltip(cm, String(msg)); + } + + function closeArgHints(ts) { + if (ts.activeArgHints) { remove(ts.activeArgHints); ts.activeArgHints = null; } + } + + function docValue(ts, doc) { + var val = doc.doc.getValue(); + if (ts.options.fileFilter) val = ts.options.fileFilter(val, doc.name, doc.doc); + return val; + } + + // Worker wrapper + + function WorkerServer(ts) { + var worker = new Worker(ts.options.workerScript); + worker.postMessage({type: "init", + defs: ts.options.defs, + plugins: ts.options.plugins, + scripts: ts.options.workerDeps}); + var msgId = 0, pending = {}; + + function send(data, c) { + if (c) { + data.id = ++msgId; + pending[msgId] = c; + } + worker.postMessage(data); + } + worker.onmessage = function(e) { + var data = e.data; + if (data.type == "getFile") { + getFile(ts, data.name, function(err, text) { + send({type: "getFile", err: String(err), text: text, id: data.id}); + }); + } else if (data.type == "debug") { + window.console.log(data.message); + } else if (data.id && pending[data.id]) { + pending[data.id](data.err, data.body); + delete pending[data.id]; + } + }; + worker.onerror = function(e) { + for (var id in pending) pending[id](e); + pending = {}; + }; + + this.addFile = function(name, text) { send({type: "add", name: name, text: text}); }; + this.delFile = function(name) { send({type: "del", name: name}); }; + this.request = function(body, c) { send({type: "req", body: body}, c); }; + } +}); diff --git a/Upload/admin/jscripts/codemirror/addon/tern/worker.js b/Upload/admin/jscripts/codemirror/addon/tern/worker.js new file mode 100644 index 0000000..48277af --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/tern/worker.js @@ -0,0 +1,44 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// declare global: tern, server + +var server; + +this.onmessage = function(e) { + var data = e.data; + switch (data.type) { + case "init": return startServer(data.defs, data.plugins, data.scripts); + case "add": return server.addFile(data.name, data.text); + case "del": return server.delFile(data.name); + case "req": return server.request(data.body, function(err, reqData) { + postMessage({id: data.id, body: reqData, err: err && String(err)}); + }); + case "getFile": + var c = pending[data.id]; + delete pending[data.id]; + return c(data.err, data.text); + default: throw new Error("Unknown message type: " + data.type); + } +}; + +var nextId = 0, pending = {}; +function getFile(file, c) { + postMessage({type: "getFile", name: file, id: ++nextId}); + pending[nextId] = c; +} + +function startServer(defs, plugins, scripts) { + if (scripts) importScripts.apply(null, scripts); + + server = new tern.Server({ + getFile: getFile, + async: true, + defs: defs, + plugins: plugins + }); +} + +var console = { + log: function(v) { postMessage({type: "debug", message: v}); } +}; diff --git a/Upload/admin/jscripts/codemirror/addon/wrap/hardwrap.js b/Upload/admin/jscripts/codemirror/addon/wrap/hardwrap.js new file mode 100644 index 0000000..fe9b4dd --- /dev/null +++ b/Upload/admin/jscripts/codemirror/addon/wrap/hardwrap.js @@ -0,0 +1,139 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var Pos = CodeMirror.Pos; + + function findParagraph(cm, pos, options) { + var startRE = options.paragraphStart || cm.getHelper(pos, "paragraphStart"); + for (var start = pos.line, first = cm.firstLine(); start > first; --start) { + var line = cm.getLine(start); + if (startRE && startRE.test(line)) break; + if (!/\S/.test(line)) { ++start; break; } + } + var endRE = options.paragraphEnd || cm.getHelper(pos, "paragraphEnd"); + for (var end = pos.line + 1, last = cm.lastLine(); end <= last; ++end) { + var line = cm.getLine(end); + if (endRE && endRE.test(line)) { ++end; break; } + if (!/\S/.test(line)) break; + } + return {from: start, to: end}; + } + + function findBreakPoint(text, column, wrapOn, killTrailingSpace) { + for (var at = column; at > 0; --at) + if (wrapOn.test(text.slice(at - 1, at + 1))) break; + if (at == 0) at = column; + var endOfText = at; + if (killTrailingSpace) + while (text.charAt(endOfText - 1) == " ") --endOfText; + return {from: endOfText, to: at}; + } + + function wrapRange(cm, from, to, options) { + from = cm.clipPos(from); to = cm.clipPos(to); + var column = options.column || 80; + var wrapOn = options.wrapOn || /\s\S|-[^\.\d]/; + var killTrailing = options.killTrailingSpace !== false; + var changes = [], curLine = "", curNo = from.line; + var lines = cm.getRange(from, to, false); + if (!lines.length) return null; + var leadingSpace = lines[0].match(/^[ \t]*/)[0]; + + for (var i = 0; i < lines.length; ++i) { + var text = lines[i], oldLen = curLine.length, spaceInserted = 0; + if (curLine && text && !wrapOn.test(curLine.charAt(curLine.length - 1) + text.charAt(0))) { + curLine += " "; + spaceInserted = 1; + } + var spaceTrimmed = ""; + if (i) { + spaceTrimmed = text.match(/^\s*/)[0]; + text = text.slice(spaceTrimmed.length); + } + curLine += text; + if (i) { + var firstBreak = curLine.length > column && leadingSpace == spaceTrimmed && + findBreakPoint(curLine, column, wrapOn, killTrailing); + // If this isn't broken, or is broken at a different point, remove old break + if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) { + changes.push({text: [spaceInserted ? " " : ""], + from: Pos(curNo, oldLen), + to: Pos(curNo + 1, spaceTrimmed.length)}); + } else { + curLine = leadingSpace + text; + ++curNo; + } + } + while (curLine.length > column) { + var bp = findBreakPoint(curLine, column, wrapOn, killTrailing); + changes.push({text: ["", leadingSpace], + from: Pos(curNo, bp.from), + to: Pos(curNo, bp.to)}); + curLine = leadingSpace + curLine.slice(bp.to); + ++curNo; + } + } + if (changes.length) cm.operation(function() { + for (var i = 0; i < changes.length; ++i) { + var change = changes[i]; + cm.replaceRange(change.text, change.from, change.to); + } + }); + return changes.length ? {from: changes[0].from, to: CodeMirror.changeEnd(changes[changes.length - 1])} : null; + } + + CodeMirror.defineExtension("wrapParagraph", function(pos, options) { + options = options || {}; + if (!pos) pos = this.getCursor(); + var para = findParagraph(this, pos, options); + return wrapRange(this, Pos(para.from, 0), Pos(para.to - 1), options); + }); + + CodeMirror.commands.wrapLines = function(cm) { + cm.operation(function() { + var ranges = cm.listSelections(), at = cm.lastLine() + 1; + for (var i = ranges.length - 1; i >= 0; i--) { + var range = ranges[i], span; + if (range.empty()) { + var para = findParagraph(cm, range.head, {}); + span = {from: Pos(para.from, 0), to: Pos(para.to - 1)}; + } else { + span = {from: range.from(), to: range.to()}; + } + if (span.to.line >= at) continue; + at = span.from.line; + wrapRange(cm, span.from, span.to, {}); + } + }); + }; + + CodeMirror.defineExtension("wrapRange", function(from, to, options) { + return wrapRange(this, from, to, options || {}); + }); + + CodeMirror.defineExtension("wrapParagraphsInRange", function(from, to, options) { + options = options || {}; + var cm = this, paras = []; + for (var line = from.line; line <= to.line;) { + var para = findParagraph(cm, Pos(line, 0), options); + paras.push(para); + line = para.to; + } + var madeChange = false; + if (paras.length) cm.operation(function() { + for (var i = paras.length - 1; i >= 0; --i) + madeChange = madeChange || wrapRange(cm, Pos(paras[i].from, 0), Pos(paras[i].to - 1), options); + }); + return madeChange; + }); +}); diff --git a/Upload/admin/jscripts/codemirror/index.html b/Upload/admin/jscripts/codemirror/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/jscripts/codemirror/keymap/emacs.js b/Upload/admin/jscripts/codemirror/keymap/emacs.js new file mode 100644 index 0000000..ba8149c --- /dev/null +++ b/Upload/admin/jscripts/codemirror/keymap/emacs.js @@ -0,0 +1,402 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var Pos = CodeMirror.Pos; + function posEq(a, b) { return a.line == b.line && a.ch == b.ch; } + + // Kill 'ring' + + var killRing = []; + function addToRing(str) { + killRing.push(str); + if (killRing.length > 50) killRing.shift(); + } + function growRingTop(str) { + if (!killRing.length) return addToRing(str); + killRing[killRing.length - 1] += str; + } + function getFromRing(n) { return killRing[killRing.length - (n ? Math.min(n, 1) : 1)] || ""; } + function popFromRing() { if (killRing.length > 1) killRing.pop(); return getFromRing(); } + + var lastKill = null; + + function kill(cm, from, to, mayGrow, text) { + if (text == null) text = cm.getRange(from, to); + + if (mayGrow && lastKill && lastKill.cm == cm && posEq(from, lastKill.pos) && cm.isClean(lastKill.gen)) + growRingTop(text); + else + addToRing(text); + cm.replaceRange("", from, to, "+delete"); + + if (mayGrow) lastKill = {cm: cm, pos: from, gen: cm.changeGeneration()}; + else lastKill = null; + } + + // Boundaries of various units + + function byChar(cm, pos, dir) { + return cm.findPosH(pos, dir, "char", true); + } + + function byWord(cm, pos, dir) { + return cm.findPosH(pos, dir, "word", true); + } + + function byLine(cm, pos, dir) { + return cm.findPosV(pos, dir, "line", cm.doc.sel.goalColumn); + } + + function byPage(cm, pos, dir) { + return cm.findPosV(pos, dir, "page", cm.doc.sel.goalColumn); + } + + function byParagraph(cm, pos, dir) { + var no = pos.line, line = cm.getLine(no); + var sawText = /\S/.test(dir < 0 ? line.slice(0, pos.ch) : line.slice(pos.ch)); + var fst = cm.firstLine(), lst = cm.lastLine(); + for (;;) { + no += dir; + if (no < fst || no > lst) + return cm.clipPos(Pos(no - dir, dir < 0 ? 0 : null)); + line = cm.getLine(no); + var hasText = /\S/.test(line); + if (hasText) sawText = true; + else if (sawText) return Pos(no, 0); + } + } + + function bySentence(cm, pos, dir) { + var line = pos.line, ch = pos.ch; + var text = cm.getLine(pos.line), sawWord = false; + for (;;) { + var next = text.charAt(ch + (dir < 0 ? -1 : 0)); + if (!next) { // End/beginning of line reached + if (line == (dir < 0 ? cm.firstLine() : cm.lastLine())) return Pos(line, ch); + text = cm.getLine(line + dir); + if (!/\S/.test(text)) return Pos(line, ch); + line += dir; + ch = dir < 0 ? text.length : 0; + continue; + } + if (sawWord && /[!?.]/.test(next)) return Pos(line, ch + (dir > 0 ? 1 : 0)); + if (!sawWord) sawWord = /\w/.test(next); + ch += dir; + } + } + + function byExpr(cm, pos, dir) { + var wrap; + if (cm.findMatchingBracket && (wrap = cm.findMatchingBracket(pos, true)) + && wrap.match && (wrap.forward ? 1 : -1) == dir) + return dir > 0 ? Pos(wrap.to.line, wrap.to.ch + 1) : wrap.to; + + for (var first = true;; first = false) { + var token = cm.getTokenAt(pos); + var after = Pos(pos.line, dir < 0 ? token.start : token.end); + if (first && dir > 0 && token.end == pos.ch || !/\w/.test(token.string)) { + var newPos = cm.findPosH(after, dir, "char"); + if (posEq(after, newPos)) return pos; + else pos = newPos; + } else { + return after; + } + } + } + + // Prefixes (only crudely supported) + + function getPrefix(cm, precise) { + var digits = cm.state.emacsPrefix; + if (!digits) return precise ? null : 1; + clearPrefix(cm); + return digits == "-" ? -1 : Number(digits); + } + + function repeated(cmd) { + var f = typeof cmd == "string" ? function(cm) { cm.execCommand(cmd); } : cmd; + return function(cm) { + var prefix = getPrefix(cm); + f(cm); + for (var i = 1; i < prefix; ++i) f(cm); + }; + } + + function findEnd(cm, by, dir) { + var pos = cm.getCursor(), prefix = getPrefix(cm); + if (prefix < 0) { dir = -dir; prefix = -prefix; } + for (var i = 0; i < prefix; ++i) { + var newPos = by(cm, pos, dir); + if (posEq(newPos, pos)) break; + pos = newPos; + } + return pos; + } + + function move(by, dir) { + var f = function(cm) { + cm.extendSelection(findEnd(cm, by, dir)); + }; + f.motion = true; + return f; + } + + function killTo(cm, by, dir) { + kill(cm, cm.getCursor(), findEnd(cm, by, dir), true); + } + + function addPrefix(cm, digit) { + if (cm.state.emacsPrefix) { + if (digit != "-") cm.state.emacsPrefix += digit; + return; + } + // Not active yet + cm.state.emacsPrefix = digit; + cm.on("keyHandled", maybeClearPrefix); + cm.on("inputRead", maybeDuplicateInput); + } + + var prefixPreservingKeys = {"Alt-G": true, "Ctrl-X": true, "Ctrl-Q": true, "Ctrl-U": true}; + + function maybeClearPrefix(cm, arg) { + if (!cm.state.emacsPrefixMap && !prefixPreservingKeys.hasOwnProperty(arg)) + clearPrefix(cm); + } + + function clearPrefix(cm) { + cm.state.emacsPrefix = null; + cm.off("keyHandled", maybeClearPrefix); + cm.off("inputRead", maybeDuplicateInput); + } + + function maybeDuplicateInput(cm, event) { + var dup = getPrefix(cm); + if (dup > 1 && event.origin == "+input") { + var one = event.text.join("\n"), txt = ""; + for (var i = 1; i < dup; ++i) txt += one; + cm.replaceSelection(txt); + } + } + + function addPrefixMap(cm) { + cm.state.emacsPrefixMap = true; + cm.addKeyMap(prefixMap); + cm.on("keyHandled", maybeRemovePrefixMap); + cm.on("inputRead", maybeRemovePrefixMap); + } + + function maybeRemovePrefixMap(cm, arg) { + if (typeof arg == "string" && (/^\d$/.test(arg) || arg == "Ctrl-U")) return; + cm.removeKeyMap(prefixMap); + cm.state.emacsPrefixMap = false; + cm.off("keyHandled", maybeRemovePrefixMap); + cm.off("inputRead", maybeRemovePrefixMap); + } + + // Utilities + + function setMark(cm) { + cm.setCursor(cm.getCursor()); + cm.setExtending(!cm.getExtending()); + cm.on("change", function() { cm.setExtending(false); }); + } + + function clearMark(cm) { + cm.setExtending(false); + cm.setCursor(cm.getCursor()); + } + + function getInput(cm, msg, f) { + if (cm.openDialog) + cm.openDialog(msg + ": ", f, {bottom: true}); + else + f(prompt(msg, "")); + } + + function operateOnWord(cm, op) { + var start = cm.getCursor(), end = cm.findPosH(start, 1, "word"); + cm.replaceRange(op(cm.getRange(start, end)), start, end); + cm.setCursor(end); + } + + function toEnclosingExpr(cm) { + var pos = cm.getCursor(), line = pos.line, ch = pos.ch; + var stack = []; + while (line >= cm.firstLine()) { + var text = cm.getLine(line); + for (var i = ch == null ? text.length : ch; i > 0;) { + var ch = text.charAt(--i); + if (ch == ")") + stack.push("("); + else if (ch == "]") + stack.push("["); + else if (ch == "}") + stack.push("{"); + else if (/[\(\{\[]/.test(ch) && (!stack.length || stack.pop() != ch)) + return cm.extendSelection(Pos(line, i)); + } + --line; ch = null; + } + } + + function quit(cm) { + cm.execCommand("clearSearch"); + clearMark(cm); + } + + // Actual keymap + + var keyMap = CodeMirror.keyMap.emacs = { + "Ctrl-W": function(cm) {kill(cm, cm.getCursor("start"), cm.getCursor("end"));}, + "Ctrl-K": repeated(function(cm) { + var start = cm.getCursor(), end = cm.clipPos(Pos(start.line)); + var text = cm.getRange(start, end); + if (!/\S/.test(text)) { + text += "\n"; + end = Pos(start.line + 1, 0); + } + kill(cm, start, end, true, text); + }), + "Alt-W": function(cm) { + addToRing(cm.getSelection()); + clearMark(cm); + }, + "Ctrl-Y": function(cm) { + var start = cm.getCursor(); + cm.replaceRange(getFromRing(getPrefix(cm)), start, start, "paste"); + cm.setSelection(start, cm.getCursor()); + }, + "Alt-Y": function(cm) {cm.replaceSelection(popFromRing(), "around", "paste");}, + + "Ctrl-Space": setMark, "Ctrl-Shift-2": setMark, + + "Ctrl-F": move(byChar, 1), "Ctrl-B": move(byChar, -1), + "Right": move(byChar, 1), "Left": move(byChar, -1), + "Ctrl-D": function(cm) { killTo(cm, byChar, 1); }, + "Delete": function(cm) { killTo(cm, byChar, 1); }, + "Ctrl-H": function(cm) { killTo(cm, byChar, -1); }, + "Backspace": function(cm) { killTo(cm, byChar, -1); }, + + "Alt-F": move(byWord, 1), "Alt-B": move(byWord, -1), + "Alt-D": function(cm) { killTo(cm, byWord, 1); }, + "Alt-Backspace": function(cm) { killTo(cm, byWord, -1); }, + + "Ctrl-N": move(byLine, 1), "Ctrl-P": move(byLine, -1), + "Down": move(byLine, 1), "Up": move(byLine, -1), + "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", + "End": "goLineEnd", "Home": "goLineStart", + + "Alt-V": move(byPage, -1), "Ctrl-V": move(byPage, 1), + "PageUp": move(byPage, -1), "PageDown": move(byPage, 1), + + "Ctrl-Up": move(byParagraph, -1), "Ctrl-Down": move(byParagraph, 1), + + "Alt-A": move(bySentence, -1), "Alt-E": move(bySentence, 1), + "Alt-K": function(cm) { killTo(cm, bySentence, 1); }, + + "Ctrl-Alt-K": function(cm) { killTo(cm, byExpr, 1); }, + "Ctrl-Alt-Backspace": function(cm) { killTo(cm, byExpr, -1); }, + "Ctrl-Alt-F": move(byExpr, 1), "Ctrl-Alt-B": move(byExpr, -1), + + "Shift-Ctrl-Alt-2": function(cm) { + cm.setSelection(findEnd(cm, byExpr, 1), cm.getCursor()); + }, + "Ctrl-Alt-T": function(cm) { + var leftStart = byExpr(cm, cm.getCursor(), -1), leftEnd = byExpr(cm, leftStart, 1); + var rightEnd = byExpr(cm, leftEnd, 1), rightStart = byExpr(cm, rightEnd, -1); + cm.replaceRange(cm.getRange(rightStart, rightEnd) + cm.getRange(leftEnd, rightStart) + + cm.getRange(leftStart, leftEnd), leftStart, rightEnd); + }, + "Ctrl-Alt-U": repeated(toEnclosingExpr), + + "Alt-Space": function(cm) { + var pos = cm.getCursor(), from = pos.ch, to = pos.ch, text = cm.getLine(pos.line); + while (from && /\s/.test(text.charAt(from - 1))) --from; + while (to < text.length && /\s/.test(text.charAt(to))) ++to; + cm.replaceRange(" ", Pos(pos.line, from), Pos(pos.line, to)); + }, + "Ctrl-O": repeated(function(cm) { cm.replaceSelection("\n", "start"); }), + "Ctrl-T": repeated(function(cm) { + cm.execCommand("transposeChars"); + }), + + "Alt-C": repeated(function(cm) { + operateOnWord(cm, function(w) { + var letter = w.search(/\w/); + if (letter == -1) return w; + return w.slice(0, letter) + w.charAt(letter).toUpperCase() + w.slice(letter + 1).toLowerCase(); + }); + }), + "Alt-U": repeated(function(cm) { + operateOnWord(cm, function(w) { return w.toUpperCase(); }); + }), + "Alt-L": repeated(function(cm) { + operateOnWord(cm, function(w) { return w.toLowerCase(); }); + }), + + "Alt-;": "toggleComment", + + "Ctrl-/": repeated("undo"), "Shift-Ctrl--": repeated("undo"), + "Ctrl-Z": repeated("undo"), "Cmd-Z": repeated("undo"), + "Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd", + "Ctrl-S": "findNext", "Ctrl-R": "findPrev", "Ctrl-G": quit, "Shift-Alt-5": "replace", + "Alt-/": "autocomplete", + "Ctrl-J": "newlineAndIndent", "Enter": false, "Tab": "indentAuto", + + "Alt-G": function(cm) {cm.setOption("keyMap", "emacs-Alt-G");}, + "Ctrl-X": function(cm) {cm.setOption("keyMap", "emacs-Ctrl-X");}, + "Ctrl-Q": function(cm) {cm.setOption("keyMap", "emacs-Ctrl-Q");}, + "Ctrl-U": addPrefixMap + }; + + CodeMirror.keyMap["emacs-Ctrl-X"] = { + "Tab": function(cm) { + cm.indentSelection(getPrefix(cm, true) || cm.getOption("indentUnit")); + }, + "Ctrl-X": function(cm) { + cm.setSelection(cm.getCursor("head"), cm.getCursor("anchor")); + }, + + "Ctrl-S": "save", "Ctrl-W": "save", "S": "saveAll", "F": "open", "U": repeated("undo"), "K": "close", + "Delete": function(cm) { kill(cm, cm.getCursor(), bySentence(cm, cm.getCursor(), 1), true); }, + auto: "emacs", nofallthrough: true, disableInput: true + }; + + CodeMirror.keyMap["emacs-Alt-G"] = { + "G": function(cm) { + var prefix = getPrefix(cm, true); + if (prefix != null && prefix > 0) return cm.setCursor(prefix - 1); + + getInput(cm, "Goto line", function(str) { + var num; + if (str && !isNaN(num = Number(str)) && num == num|0 && num > 0) + cm.setCursor(num - 1); + }); + }, + auto: "emacs", nofallthrough: true, disableInput: true + }; + + CodeMirror.keyMap["emacs-Ctrl-Q"] = { + "Tab": repeated("insertTab"), + auto: "emacs", nofallthrough: true + }; + + var prefixMap = {"Ctrl-G": clearPrefix}; + function regPrefix(d) { + prefixMap[d] = function(cm) { addPrefix(cm, d); }; + keyMap["Ctrl-" + d] = function(cm) { addPrefix(cm, d); }; + prefixPreservingKeys["Ctrl-" + d] = true; + } + for (var i = 0; i < 10; ++i) regPrefix(String(i)); + regPrefix("-"); +}); diff --git a/Upload/admin/jscripts/codemirror/keymap/sublime.js b/Upload/admin/jscripts/codemirror/keymap/sublime.js new file mode 100644 index 0000000..4d46938 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/keymap/sublime.js @@ -0,0 +1,520 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// A rough approximation of Sublime Text's keybindings +// Depends on addon/search/searchcursor.js and optionally addon/dialog/dialogs.js + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../lib/codemirror"), require("../addon/search/searchcursor"), require("../addon/edit/matchbrackets")); + else if (typeof define == "function" && define.amd) // AMD + define(["../lib/codemirror", "../addon/search/searchcursor", "../addon/edit/matchbrackets"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var map = CodeMirror.keyMap.sublime = {fallthrough: "default"}; + var cmds = CodeMirror.commands; + var Pos = CodeMirror.Pos; + var ctrl = CodeMirror.keyMap["default"] == CodeMirror.keyMap.pcDefault ? "Ctrl-" : "Cmd-"; + + // This is not exactly Sublime's algorithm. I couldn't make heads or tails of that. + function findPosSubword(doc, start, dir) { + if (dir < 0 && start.ch == 0) return doc.clipPos(Pos(start.line - 1)); + var line = doc.getLine(start.line); + if (dir > 0 && start.ch >= line.length) return doc.clipPos(Pos(start.line + 1, 0)); + var state = "start", type; + for (var pos = start.ch, e = dir < 0 ? 0 : line.length, i = 0; pos != e; pos += dir, i++) { + var next = line.charAt(dir < 0 ? pos - 1 : pos); + var cat = next != "_" && CodeMirror.isWordChar(next) ? "w" : "o"; + if (cat == "w" && next.toUpperCase() == next) cat = "W"; + if (state == "start") { + if (cat != "o") { state = "in"; type = cat; } + } else if (state == "in") { + if (type != cat) { + if (type == "w" && cat == "W" && dir < 0) pos--; + if (type == "W" && cat == "w" && dir > 0) { type = "w"; continue; } + break; + } + } + } + return Pos(start.line, pos); + } + + function moveSubword(cm, dir) { + cm.extendSelectionsBy(function(range) { + if (cm.display.shift || cm.doc.extend || range.empty()) + return findPosSubword(cm.doc, range.head, dir); + else + return dir < 0 ? range.from() : range.to(); + }); + } + + cmds[map["Alt-Left"] = "goSubwordLeft"] = function(cm) { moveSubword(cm, -1); }; + cmds[map["Alt-Right"] = "goSubwordRight"] = function(cm) { moveSubword(cm, 1); }; + + cmds[map[ctrl + "Up"] = "scrollLineUp"] = function(cm) { + var info = cm.getScrollInfo(); + if (!cm.somethingSelected()) { + var visibleBottomLine = cm.lineAtHeight(info.top + info.clientHeight, "local"); + if (cm.getCursor().line >= visibleBottomLine) + cm.execCommand("goLineUp"); + } + cm.scrollTo(null, info.top - cm.defaultTextHeight()); + }; + cmds[map[ctrl + "Down"] = "scrollLineDown"] = function(cm) { + var info = cm.getScrollInfo(); + if (!cm.somethingSelected()) { + var visibleTopLine = cm.lineAtHeight(info.top, "local")+1; + if (cm.getCursor().line <= visibleTopLine) + cm.execCommand("goLineDown"); + } + cm.scrollTo(null, info.top + cm.defaultTextHeight()); + }; + + cmds[map["Shift-" + ctrl + "L"] = "splitSelectionByLine"] = function(cm) { + var ranges = cm.listSelections(), lineRanges = []; + for (var i = 0; i < ranges.length; i++) { + var from = ranges[i].from(), to = ranges[i].to(); + for (var line = from.line; line <= to.line; ++line) + if (!(to.line > from.line && line == to.line && to.ch == 0)) + lineRanges.push({anchor: line == from.line ? from : Pos(line, 0), + head: line == to.line ? to : Pos(line)}); + } + cm.setSelections(lineRanges, 0); + }; + + map["Shift-Tab"] = "indentLess"; + + cmds[map["Esc"] = "singleSelectionTop"] = function(cm) { + var range = cm.listSelections()[0]; + cm.setSelection(range.anchor, range.head, {scroll: false}); + }; + + cmds[map[ctrl + "L"] = "selectLine"] = function(cm) { + var ranges = cm.listSelections(), extended = []; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + extended.push({anchor: Pos(range.from().line, 0), + head: Pos(range.to().line + 1, 0)}); + } + cm.setSelections(extended); + }; + + map["Shift-" + ctrl + "K"] = "deleteLine"; + + function insertLine(cm, above) { + cm.operation(function() { + var len = cm.listSelections().length, newSelection = [], last = -1; + for (var i = 0; i < len; i++) { + var head = cm.listSelections()[i].head; + if (head.line <= last) continue; + var at = Pos(head.line + (above ? 0 : 1), 0); + cm.replaceRange("\n", at, null, "+insertLine"); + cm.indentLine(at.line, null, true); + newSelection.push({head: at, anchor: at}); + last = head.line + 1; + } + cm.setSelections(newSelection); + }); + } + + cmds[map[ctrl + "Enter"] = "insertLineAfter"] = function(cm) { insertLine(cm, false); }; + + cmds[map["Shift-" + ctrl + "Enter"] = "insertLineBefore"] = function(cm) { insertLine(cm, true); }; + + function wordAt(cm, pos) { + var start = pos.ch, end = start, line = cm.getLine(pos.line); + while (start && CodeMirror.isWordChar(line.charAt(start - 1))) --start; + while (end < line.length && CodeMirror.isWordChar(line.charAt(end))) ++end; + return {from: Pos(pos.line, start), to: Pos(pos.line, end), word: line.slice(start, end)}; + } + + cmds[map[ctrl + "D"] = "selectNextOccurrence"] = function(cm) { + var from = cm.getCursor("from"), to = cm.getCursor("to"); + var fullWord = cm.state.sublimeFindFullWord == cm.doc.sel; + if (CodeMirror.cmpPos(from, to) == 0) { + var word = wordAt(cm, from); + if (!word.word) return; + cm.setSelection(word.from, word.to); + fullWord = true; + } else { + var text = cm.getRange(from, to); + var query = fullWord ? new RegExp("\\b" + text + "\\b") : text; + var cur = cm.getSearchCursor(query, to); + if (cur.findNext()) { + cm.addSelection(cur.from(), cur.to()); + } else { + cur = cm.getSearchCursor(query, Pos(cm.firstLine(), 0)); + if (cur.findNext()) + cm.addSelection(cur.from(), cur.to()); + } + } + if (fullWord) + cm.state.sublimeFindFullWord = cm.doc.sel; + }; + + var mirror = "(){}[]"; + function selectBetweenBrackets(cm) { + var pos = cm.getCursor(), opening = cm.scanForBracket(pos, -1); + if (!opening) return; + for (;;) { + var closing = cm.scanForBracket(pos, 1); + if (!closing) return; + if (closing.ch == mirror.charAt(mirror.indexOf(opening.ch) + 1)) { + cm.setSelection(Pos(opening.pos.line, opening.pos.ch + 1), closing.pos, false); + return true; + } + pos = Pos(closing.pos.line, closing.pos.ch + 1); + } + } + + cmds[map["Shift-" + ctrl + "Space"] = "selectScope"] = function(cm) { + selectBetweenBrackets(cm) || cm.execCommand("selectAll"); + }; + cmds[map["Shift-" + ctrl + "M"] = "selectBetweenBrackets"] = function(cm) { + if (!selectBetweenBrackets(cm)) return CodeMirror.Pass; + }; + + cmds[map[ctrl + "M"] = "goToBracket"] = function(cm) { + cm.extendSelectionsBy(function(range) { + var next = cm.scanForBracket(range.head, 1); + if (next && CodeMirror.cmpPos(next.pos, range.head) != 0) return next.pos; + var prev = cm.scanForBracket(range.head, -1); + return prev && Pos(prev.pos.line, prev.pos.ch + 1) || range.head; + }); + }; + + cmds[map["Shift-" + ctrl + "Up"] = "swapLineUp"] = function(cm) { + var ranges = cm.listSelections(), linesToMove = [], at = cm.firstLine() - 1, newSels = []; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i], from = range.from().line - 1, to = range.to().line; + newSels.push({anchor: Pos(range.anchor.line - 1, range.anchor.ch), + head: Pos(range.head.line - 1, range.head.ch)}); + if (range.to().ch == 0 && !range.empty()) --to; + if (from > at) linesToMove.push(from, to); + else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to; + at = to; + } + cm.operation(function() { + for (var i = 0; i < linesToMove.length; i += 2) { + var from = linesToMove[i], to = linesToMove[i + 1]; + var line = cm.getLine(from); + cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine"); + if (to > cm.lastLine()) + cm.replaceRange("\n" + line, Pos(cm.lastLine()), null, "+swapLine"); + else + cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine"); + } + cm.setSelections(newSels); + cm.scrollIntoView(); + }); + }; + + cmds[map["Shift-" + ctrl + "Down"] = "swapLineDown"] = function(cm) { + var ranges = cm.listSelections(), linesToMove = [], at = cm.lastLine() + 1; + for (var i = ranges.length - 1; i >= 0; i--) { + var range = ranges[i], from = range.to().line + 1, to = range.from().line; + if (range.to().ch == 0 && !range.empty()) from--; + if (from < at) linesToMove.push(from, to); + else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to; + at = to; + } + cm.operation(function() { + for (var i = linesToMove.length - 2; i >= 0; i -= 2) { + var from = linesToMove[i], to = linesToMove[i + 1]; + var line = cm.getLine(from); + if (from == cm.lastLine()) + cm.replaceRange("", Pos(from - 1), Pos(from), "+swapLine"); + else + cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine"); + cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine"); + } + cm.scrollIntoView(); + }); + }; + + map[ctrl + "/"] = "toggleComment"; + + cmds[map[ctrl + "J"] = "joinLines"] = function(cm) { + var ranges = cm.listSelections(), joined = []; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i], from = range.from(); + var start = from.line, end = range.to().line; + while (i < ranges.length - 1 && ranges[i + 1].from().line == end) + end = ranges[++i].to().line; + joined.push({start: start, end: end, anchor: !range.empty() && from}); + } + cm.operation(function() { + var offset = 0, ranges = []; + for (var i = 0; i < joined.length; i++) { + var obj = joined[i]; + var anchor = obj.anchor && Pos(obj.anchor.line - offset, obj.anchor.ch), head; + for (var line = obj.start; line <= obj.end; line++) { + var actual = line - offset; + if (line == obj.end) head = Pos(actual, cm.getLine(actual).length + 1); + if (actual < cm.lastLine()) { + cm.replaceRange(" ", Pos(actual), Pos(actual + 1, /^\s*/.exec(cm.getLine(actual + 1))[0].length)); + ++offset; + } + } + ranges.push({anchor: anchor || head, head: head}); + } + cm.setSelections(ranges, 0); + }); + }; + + cmds[map["Shift-" + ctrl + "D"] = "duplicateLine"] = function(cm) { + cm.operation(function() { + var rangeCount = cm.listSelections().length; + for (var i = 0; i < rangeCount; i++) { + var range = cm.listSelections()[i]; + if (range.empty()) + cm.replaceRange(cm.getLine(range.head.line) + "\n", Pos(range.head.line, 0)); + else + cm.replaceRange(cm.getRange(range.from(), range.to()), range.from()); + } + cm.scrollIntoView(); + }); + }; + + map[ctrl + "T"] = "transposeChars"; + + function sortLines(cm, caseSensitive) { + var ranges = cm.listSelections(), toSort = [], selected; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (range.empty()) continue; + var from = range.from().line, to = range.to().line; + while (i < ranges.length - 1 && ranges[i + 1].from().line == to) + to = range[++i].to().line; + toSort.push(from, to); + } + if (toSort.length) selected = true; + else toSort.push(cm.firstLine(), cm.lastLine()); + + cm.operation(function() { + var ranges = []; + for (var i = 0; i < toSort.length; i += 2) { + var from = toSort[i], to = toSort[i + 1]; + var start = Pos(from, 0), end = Pos(to); + var lines = cm.getRange(start, end, false); + if (caseSensitive) + lines.sort(); + else + lines.sort(function(a, b) { + var au = a.toUpperCase(), bu = b.toUpperCase(); + if (au != bu) { a = au; b = bu; } + return a < b ? -1 : a == b ? 0 : 1; + }); + cm.replaceRange(lines, start, end); + if (selected) ranges.push({anchor: start, head: end}); + } + if (selected) cm.setSelections(ranges, 0); + }); + } + + cmds[map["F9"] = "sortLines"] = function(cm) { sortLines(cm, true); }; + cmds[map[ctrl + "F9"] = "sortLinesInsensitive"] = function(cm) { sortLines(cm, false); }; + + cmds[map["F2"] = "nextBookmark"] = function(cm) { + var marks = cm.state.sublimeBookmarks; + if (marks) while (marks.length) { + var current = marks.shift(); + var found = current.find(); + if (found) { + marks.push(current); + return cm.setSelection(found.from, found.to); + } + } + }; + + cmds[map["Shift-F2"] = "prevBookmark"] = function(cm) { + var marks = cm.state.sublimeBookmarks; + if (marks) while (marks.length) { + marks.unshift(marks.pop()); + var found = marks[marks.length - 1].find(); + if (!found) + marks.pop(); + else + return cm.setSelection(found.from, found.to); + } + }; + + cmds[map[ctrl + "F2"] = "toggleBookmark"] = function(cm) { + var ranges = cm.listSelections(); + var marks = cm.state.sublimeBookmarks || (cm.state.sublimeBookmarks = []); + for (var i = 0; i < ranges.length; i++) { + var from = ranges[i].from(), to = ranges[i].to(); + var found = cm.findMarks(from, to); + for (var j = 0; j < found.length; j++) { + if (found[j].sublimeBookmark) { + found[j].clear(); + for (var k = 0; k < marks.length; k++) + if (marks[k] == found[j]) + marks.splice(k--, 1); + break; + } + } + if (j == found.length) + marks.push(cm.markText(from, to, {sublimeBookmark: true, clearWhenEmpty: false})); + } + }; + + cmds[map["Shift-" + ctrl + "F2"] = "clearBookmarks"] = function(cm) { + var marks = cm.state.sublimeBookmarks; + if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear(); + marks.length = 0; + }; + + cmds[map["Alt-F2"] = "selectBookmarks"] = function(cm) { + var marks = cm.state.sublimeBookmarks, ranges = []; + if (marks) for (var i = 0; i < marks.length; i++) { + var found = marks[i].find(); + if (!found) + marks.splice(i--, 0); + else + ranges.push({anchor: found.from, head: found.to}); + } + if (ranges.length) + cm.setSelections(ranges, 0); + }; + + map["Alt-Q"] = "wrapLines"; + + var mapK = CodeMirror.keyMap["sublime-Ctrl-K"] = {auto: "sublime", nofallthrough: true}; + + map[ctrl + "K"] = function(cm) {cm.setOption("keyMap", "sublime-Ctrl-K");}; + + function modifyWordOrSelection(cm, mod) { + cm.operation(function() { + var ranges = cm.listSelections(), indices = [], replacements = []; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (range.empty()) { indices.push(i); replacements.push(""); } + else replacements.push(mod(cm.getRange(range.from(), range.to()))); + } + cm.replaceSelections(replacements, "around", "case"); + for (var i = indices.length - 1, at; i >= 0; i--) { + var range = ranges[indices[i]]; + if (at && CodeMirror.cmpPos(range.head, at) > 0) continue; + var word = wordAt(cm, range.head); + at = word.from; + cm.replaceRange(mod(word.word), word.from, word.to); + } + }); + } + + mapK[ctrl + "Backspace"] = "delLineLeft"; + + cmds[mapK[ctrl + "K"] = "delLineRight"] = function(cm) { + cm.operation(function() { + var ranges = cm.listSelections(); + for (var i = ranges.length - 1; i >= 0; i--) + cm.replaceRange("", ranges[i].anchor, Pos(ranges[i].to().line), "+delete"); + cm.scrollIntoView(); + }); + }; + + cmds[mapK[ctrl + "U"] = "upcaseAtCursor"] = function(cm) { + modifyWordOrSelection(cm, function(str) { return str.toUpperCase(); }); + }; + cmds[mapK[ctrl + "L"] = "downcaseAtCursor"] = function(cm) { + modifyWordOrSelection(cm, function(str) { return str.toLowerCase(); }); + }; + + cmds[mapK[ctrl + "Space"] = "setSublimeMark"] = function(cm) { + if (cm.state.sublimeMark) cm.state.sublimeMark.clear(); + cm.state.sublimeMark = cm.setBookmark(cm.getCursor()); + }; + cmds[mapK[ctrl + "A"] = "selectToSublimeMark"] = function(cm) { + var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); + if (found) cm.setSelection(cm.getCursor(), found); + }; + cmds[mapK[ctrl + "W"] = "deleteToSublimeMark"] = function(cm) { + var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); + if (found) { + var from = cm.getCursor(), to = found; + if (CodeMirror.cmpPos(from, to) > 0) { var tmp = to; to = from; from = tmp; } + cm.state.sublimeKilled = cm.getRange(from, to); + cm.replaceRange("", from, to); + } + }; + cmds[mapK[ctrl + "X"] = "swapWithSublimeMark"] = function(cm) { + var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); + if (found) { + cm.state.sublimeMark.clear(); + cm.state.sublimeMark = cm.setBookmark(cm.getCursor()); + cm.setCursor(found); + } + }; + cmds[mapK[ctrl + "Y"] = "sublimeYank"] = function(cm) { + if (cm.state.sublimeKilled != null) + cm.replaceSelection(cm.state.sublimeKilled, null, "paste"); + }; + + mapK[ctrl + "G"] = "clearBookmarks"; + cmds[mapK[ctrl + "C"] = "showInCenter"] = function(cm) { + var pos = cm.cursorCoords(null, "local"); + cm.scrollTo(null, (pos.top + pos.bottom) / 2 - cm.getScrollInfo().clientHeight / 2); + }; + + cmds[map["Shift-Alt-Up"] = "selectLinesUpward"] = function(cm) { + cm.operation(function() { + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (range.head.line > cm.firstLine()) + cm.addSelection(Pos(range.head.line - 1, range.head.ch)); + } + }); + }; + cmds[map["Shift-Alt-Down"] = "selectLinesDownward"] = function(cm) { + cm.operation(function() { + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (range.head.line < cm.lastLine()) + cm.addSelection(Pos(range.head.line + 1, range.head.ch)); + } + }); + }; + + function findAndGoTo(cm, forward) { + var from = cm.getCursor("from"), to = cm.getCursor("to"); + if (CodeMirror.cmpPos(from, to) == 0) { + var word = wordAt(cm, from); + if (!word.word) return; + from = word.from; + to = word.to; + } + + var query = cm.getRange(from, to); + var cur = cm.getSearchCursor(query, forward ? to : from); + + if (forward ? cur.findNext() : cur.findPrevious()) { + cm.setSelection(cur.from(), cur.to()); + } else { + cur = cm.getSearchCursor(query, forward ? Pos(cm.firstLine(), 0) + : cm.clipPos(Pos(cm.lastLine()))); + if (forward ? cur.findNext() : cur.findPrevious()) + cm.setSelection(cur.from(), cur.to()); + else if (word) + cm.setSelection(from, to); + } + }; + cmds[map[ctrl + "F3"] = "findUnder"] = function(cm) { findAndGoTo(cm, true); }; + cmds[map["Shift-" + ctrl + "F3"] = "findUnderPrevious"] = function(cm) { findAndGoTo(cm,false); }; + + map["Shift-" + ctrl + "["] = "fold"; + map["Shift-" + ctrl + "]"] = "unfold"; + mapK[ctrl + "0"] = mapK[ctrl + "j"] = "unfoldAll"; + + map[ctrl + "I"] = "findIncremental"; + map["Shift-" + ctrl + "I"] = "findIncrementalReverse"; + map[ctrl + "H"] = "replace"; + map["F3"] = "findNext"; + map["Shift-F3"] = "findPrev"; + +}); diff --git a/Upload/admin/jscripts/codemirror/keymap/vim.js b/Upload/admin/jscripts/codemirror/keymap/vim.js new file mode 100644 index 0000000..3a099a0 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/keymap/vim.js @@ -0,0 +1,4466 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/** + * Supported keybindings: + * + * Motion: + * h, j, k, l + * gj, gk + * e, E, w, W, b, B, ge, gE + * f, F, t, T + * $, ^, 0, -, +, _ + * gg, G + * % + * ', ` + * + * Operator: + * d, y, c + * dd, yy, cc + * g~, g~g~ + * >, <, >>, << + * + * Operator-Motion: + * x, X, D, Y, C, ~ + * + * Action: + * a, i, s, A, I, S, o, O + * zz, z., z, zt, zb, z- + * J + * u, Ctrl-r + * m + * r + * + * Modes: + * ESC - leave insert mode, visual mode, and clear input state. + * Ctrl-[, Ctrl-c - same as ESC. + * + * Registers: unnamed, -, a-z, A-Z, 0-9 + * (Does not respect the special case for number registers when delete + * operator is made with these commands: %, (, ), , /, ?, n, N, {, } ) + * TODO: Implement the remaining registers. + * Marks: a-z, A-Z, and 0-9 + * TODO: Implement the remaining special marks. They have more complex + * behavior. + * + * Events: + * 'vim-mode-change' - raised on the editor anytime the current mode changes, + * Event object: {mode: "visual", subMode: "linewise"} + * + * Code structure: + * 1. Default keymap + * 2. Variable declarations and short basic helpers + * 3. Instance (External API) implementation + * 4. Internal state tracking objects (input state, counter) implementation + * and instanstiation + * 5. Key handler (the main command dispatcher) implementation + * 6. Motion, operator, and action implementations + * 7. Helper functions for the key handler, motions, operators, and actions + * 8. Set up Vim to work as a keymap for CodeMirror. + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../lib/codemirror"), require("../addon/search/searchcursor"), require("../addon/dialog/dialog"), require("../addon/edit/matchbrackets.js")); + else if (typeof define == "function" && define.amd) // AMD + define(["../lib/codemirror", "../addon/search/searchcursor", "../addon/dialog/dialog", "../addon/edit/matchbrackets"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + 'use strict'; + + var defaultKeymap = [ + // Key to key mapping. This goes first to make it possible to override + // existing mappings. + { keys: [''], type: 'keyToKey', toKeys: ['h'] }, + { keys: [''], type: 'keyToKey', toKeys: ['l'] }, + { keys: [''], type: 'keyToKey', toKeys: ['k'] }, + { keys: [''], type: 'keyToKey', toKeys: ['j'] }, + { keys: [''], type: 'keyToKey', toKeys: ['l'] }, + { keys: [''], type: 'keyToKey', toKeys: ['h'] }, + { keys: [''], type: 'keyToKey', toKeys: ['W'] }, + { keys: [''], type: 'keyToKey', toKeys: ['B'] }, + { keys: [''], type: 'keyToKey', toKeys: ['w'] }, + { keys: [''], type: 'keyToKey', toKeys: ['b'] }, + { keys: [''], type: 'keyToKey', toKeys: ['j'] }, + { keys: [''], type: 'keyToKey', toKeys: ['k'] }, + { keys: [''], type: 'keyToKey', toKeys: [''] }, + { keys: [''], type: 'keyToKey', toKeys: [''] }, + { keys: ['s'], type: 'keyToKey', toKeys: ['c', 'l'], context: 'normal' }, + { keys: ['s'], type: 'keyToKey', toKeys: ['x', 'i'], context: 'visual'}, + { keys: ['S'], type: 'keyToKey', toKeys: ['c', 'c'], context: 'normal' }, + { keys: ['S'], type: 'keyToKey', toKeys: ['d', 'c', 'c'], context: 'visual' }, + { keys: [''], type: 'keyToKey', toKeys: ['0'] }, + { keys: [''], type: 'keyToKey', toKeys: ['$'] }, + { keys: [''], type: 'keyToKey', toKeys: [''] }, + { keys: [''], type: 'keyToKey', toKeys: [''] }, + { keys: [''], type: 'keyToKey', toKeys: ['j', '^'], context: 'normal' }, + // Motions + { keys: ['H'], type: 'motion', + motion: 'moveToTopLine', + motionArgs: { linewise: true, toJumplist: true }}, + { keys: ['M'], type: 'motion', + motion: 'moveToMiddleLine', + motionArgs: { linewise: true, toJumplist: true }}, + { keys: ['L'], type: 'motion', + motion: 'moveToBottomLine', + motionArgs: { linewise: true, toJumplist: true }}, + { keys: ['h'], type: 'motion', + motion: 'moveByCharacters', + motionArgs: { forward: false }}, + { keys: ['l'], type: 'motion', + motion: 'moveByCharacters', + motionArgs: { forward: true }}, + { keys: ['j'], type: 'motion', + motion: 'moveByLines', + motionArgs: { forward: true, linewise: true }}, + { keys: ['k'], type: 'motion', + motion: 'moveByLines', + motionArgs: { forward: false, linewise: true }}, + { keys: ['g','j'], type: 'motion', + motion: 'moveByDisplayLines', + motionArgs: { forward: true }}, + { keys: ['g','k'], type: 'motion', + motion: 'moveByDisplayLines', + motionArgs: { forward: false }}, + { keys: ['w'], type: 'motion', + motion: 'moveByWords', + motionArgs: { forward: true, wordEnd: false }}, + { keys: ['W'], type: 'motion', + motion: 'moveByWords', + motionArgs: { forward: true, wordEnd: false, bigWord: true }}, + { keys: ['e'], type: 'motion', + motion: 'moveByWords', + motionArgs: { forward: true, wordEnd: true, inclusive: true }}, + { keys: ['E'], type: 'motion', + motion: 'moveByWords', + motionArgs: { forward: true, wordEnd: true, bigWord: true, + inclusive: true }}, + { keys: ['b'], type: 'motion', + motion: 'moveByWords', + motionArgs: { forward: false, wordEnd: false }}, + { keys: ['B'], type: 'motion', + motion: 'moveByWords', + motionArgs: { forward: false, wordEnd: false, bigWord: true }}, + { keys: ['g', 'e'], type: 'motion', + motion: 'moveByWords', + motionArgs: { forward: false, wordEnd: true, inclusive: true }}, + { keys: ['g', 'E'], type: 'motion', + motion: 'moveByWords', + motionArgs: { forward: false, wordEnd: true, bigWord: true, + inclusive: true }}, + { keys: ['{'], type: 'motion', motion: 'moveByParagraph', + motionArgs: { forward: false, toJumplist: true }}, + { keys: ['}'], type: 'motion', motion: 'moveByParagraph', + motionArgs: { forward: true, toJumplist: true }}, + { keys: [''], type: 'motion', + motion: 'moveByPage', motionArgs: { forward: true }}, + { keys: [''], type: 'motion', + motion: 'moveByPage', motionArgs: { forward: false }}, + { keys: [''], type: 'motion', + motion: 'moveByScroll', + motionArgs: { forward: true, explicitRepeat: true }}, + { keys: [''], type: 'motion', + motion: 'moveByScroll', + motionArgs: { forward: false, explicitRepeat: true }}, + { keys: ['g', 'g'], type: 'motion', + motion: 'moveToLineOrEdgeOfDocument', + motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true }}, + { keys: ['G'], type: 'motion', + motion: 'moveToLineOrEdgeOfDocument', + motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true }}, + { keys: ['0'], type: 'motion', motion: 'moveToStartOfLine' }, + { keys: ['^'], type: 'motion', + motion: 'moveToFirstNonWhiteSpaceCharacter' }, + { keys: ['+'], type: 'motion', + motion: 'moveByLines', + motionArgs: { forward: true, toFirstChar:true }}, + { keys: ['-'], type: 'motion', + motion: 'moveByLines', + motionArgs: { forward: false, toFirstChar:true }}, + { keys: ['_'], type: 'motion', + motion: 'moveByLines', + motionArgs: { forward: true, toFirstChar:true, repeatOffset:-1 }}, + { keys: ['$'], type: 'motion', + motion: 'moveToEol', + motionArgs: { inclusive: true }}, + { keys: ['%'], type: 'motion', + motion: 'moveToMatchedSymbol', + motionArgs: { inclusive: true, toJumplist: true }}, + { keys: ['f', 'character'], type: 'motion', + motion: 'moveToCharacter', + motionArgs: { forward: true , inclusive: true }}, + { keys: ['F', 'character'], type: 'motion', + motion: 'moveToCharacter', + motionArgs: { forward: false }}, + { keys: ['t', 'character'], type: 'motion', + motion: 'moveTillCharacter', + motionArgs: { forward: true, inclusive: true }}, + { keys: ['T', 'character'], type: 'motion', + motion: 'moveTillCharacter', + motionArgs: { forward: false }}, + { keys: [';'], type: 'motion', motion: 'repeatLastCharacterSearch', + motionArgs: { forward: true }}, + { keys: [','], type: 'motion', motion: 'repeatLastCharacterSearch', + motionArgs: { forward: false }}, + { keys: ['\'', 'character'], type: 'motion', motion: 'goToMark', + motionArgs: {toJumplist: true, linewise: true}}, + { keys: ['`', 'character'], type: 'motion', motion: 'goToMark', + motionArgs: {toJumplist: true}}, + { keys: [']', '`'], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } }, + { keys: ['[', '`'], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } }, + { keys: [']', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } }, + { keys: ['[', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } }, + // the next two aren't motions but must come before more general motion declarations + { keys: [']', 'p'], type: 'action', action: 'paste', isEdit: true, + actionArgs: { after: true, isEdit: true, matchIndent: true}}, + { keys: ['[', 'p'], type: 'action', action: 'paste', isEdit: true, + actionArgs: { after: false, isEdit: true, matchIndent: true}}, + { keys: [']', 'character'], type: 'motion', + motion: 'moveToSymbol', + motionArgs: { forward: true, toJumplist: true}}, + { keys: ['[', 'character'], type: 'motion', + motion: 'moveToSymbol', + motionArgs: { forward: false, toJumplist: true}}, + { keys: ['|'], type: 'motion', + motion: 'moveToColumn', + motionArgs: { }}, + { keys: ['o'], type: 'motion', motion: 'moveToOtherHighlightedEnd', motionArgs: { },context:'visual'}, + // Operators + { keys: ['d'], type: 'operator', operator: 'delete' }, + { keys: ['y'], type: 'operator', operator: 'yank' }, + { keys: ['c'], type: 'operator', operator: 'change' }, + { keys: ['>'], type: 'operator', operator: 'indent', + operatorArgs: { indentRight: true }}, + { keys: ['<'], type: 'operator', operator: 'indent', + operatorArgs: { indentRight: false }}, + { keys: ['g', '~'], type: 'operator', operator: 'swapcase' }, + { keys: ['n'], type: 'motion', motion: 'findNext', + motionArgs: { forward: true, toJumplist: true }}, + { keys: ['N'], type: 'motion', motion: 'findNext', + motionArgs: { forward: false, toJumplist: true }}, + // Operator-Motion dual commands + { keys: ['x'], type: 'operatorMotion', operator: 'delete', + motion: 'moveByCharacters', motionArgs: { forward: true }, + operatorMotionArgs: { visualLine: false }}, + { keys: ['X'], type: 'operatorMotion', operator: 'delete', + motion: 'moveByCharacters', motionArgs: { forward: false }, + operatorMotionArgs: { visualLine: true }}, + { keys: ['D'], type: 'operatorMotion', operator: 'delete', + motion: 'moveToEol', motionArgs: { inclusive: true }, + operatorMotionArgs: { visualLine: true }}, + { keys: ['Y'], type: 'operatorMotion', operator: 'yank', + motion: 'moveToEol', motionArgs: { inclusive: true }, + operatorMotionArgs: { visualLine: true }}, + { keys: ['C'], type: 'operatorMotion', + operator: 'change', + motion: 'moveToEol', motionArgs: { inclusive: true }, + operatorMotionArgs: { visualLine: true }}, + { keys: ['~'], type: 'operatorMotion', + operator: 'swapcase', operatorArgs: { shouldMoveCursor: true }, + motion: 'moveByCharacters', motionArgs: { forward: true }}, + // Actions + { keys: [''], type: 'action', action: 'jumpListWalk', + actionArgs: { forward: true }}, + { keys: [''], type: 'action', action: 'jumpListWalk', + actionArgs: { forward: false }}, + { keys: [''], type: 'action', + action: 'scroll', + actionArgs: { forward: true, linewise: true }}, + { keys: [''], type: 'action', + action: 'scroll', + actionArgs: { forward: false, linewise: true }}, + { keys: ['a'], type: 'action', action: 'enterInsertMode', isEdit: true, + actionArgs: { insertAt: 'charAfter' }}, + { keys: ['A'], type: 'action', action: 'enterInsertMode', isEdit: true, + actionArgs: { insertAt: 'eol' }}, + { keys: ['A'], type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'endOfSelectedArea' }, context: 'visual' }, + { keys: ['i'], type: 'action', action: 'enterInsertMode', isEdit: true, + actionArgs: { insertAt: 'inplace' }}, + { keys: ['I'], type: 'action', action: 'enterInsertMode', isEdit: true, + actionArgs: { insertAt: 'firstNonBlank' }}, + { keys: ['o'], type: 'action', action: 'newLineAndEnterInsertMode', + isEdit: true, interlaceInsertRepeat: true, + actionArgs: { after: true }}, + { keys: ['O'], type: 'action', action: 'newLineAndEnterInsertMode', + isEdit: true, interlaceInsertRepeat: true, + actionArgs: { after: false }}, + { keys: ['v'], type: 'action', action: 'toggleVisualMode' }, + { keys: ['V'], type: 'action', action: 'toggleVisualMode', + actionArgs: { linewise: true }}, + { keys: ['g', 'v'], type: 'action', action: 'reselectLastSelection' }, + { keys: ['J'], type: 'action', action: 'joinLines', isEdit: true }, + { keys: ['p'], type: 'action', action: 'paste', isEdit: true, + actionArgs: { after: true, isEdit: true }}, + { keys: ['P'], type: 'action', action: 'paste', isEdit: true, + actionArgs: { after: false, isEdit: true }}, + { keys: ['r', 'character'], type: 'action', action: 'replace', isEdit: true }, + { keys: ['@', 'character'], type: 'action', action: 'replayMacro' }, + { keys: ['q', 'character'], type: 'action', action: 'enterMacroRecordMode' }, + // Handle Replace-mode as a special case of insert mode. + { keys: ['R'], type: 'action', action: 'enterInsertMode', isEdit: true, + actionArgs: { replace: true }}, + { keys: ['u'], type: 'action', action: 'undo' }, + { keys: ['u'], type: 'action', action: 'changeCase', actionArgs: {toLower: true}, context: 'visual', isEdit: true }, + { keys: ['U'],type: 'action', action: 'changeCase', actionArgs: {toLower: false}, context: 'visual', isEdit: true }, + { keys: [''], type: 'action', action: 'redo' }, + { keys: ['m', 'character'], type: 'action', action: 'setMark' }, + { keys: ['"', 'character'], type: 'action', action: 'setRegister' }, + { keys: ['z', 'z'], type: 'action', action: 'scrollToCursor', + actionArgs: { position: 'center' }}, + { keys: ['z', '.'], type: 'action', action: 'scrollToCursor', + actionArgs: { position: 'center' }, + motion: 'moveToFirstNonWhiteSpaceCharacter' }, + { keys: ['z', 't'], type: 'action', action: 'scrollToCursor', + actionArgs: { position: 'top' }}, + { keys: ['z', ''], type: 'action', action: 'scrollToCursor', + actionArgs: { position: 'top' }, + motion: 'moveToFirstNonWhiteSpaceCharacter' }, + { keys: ['z', '-'], type: 'action', action: 'scrollToCursor', + actionArgs: { position: 'bottom' }}, + { keys: ['z', 'b'], type: 'action', action: 'scrollToCursor', + actionArgs: { position: 'bottom' }, + motion: 'moveToFirstNonWhiteSpaceCharacter' }, + { keys: ['.'], type: 'action', action: 'repeatLastEdit' }, + { keys: [''], type: 'action', action: 'incrementNumberToken', + isEdit: true, + actionArgs: {increase: true, backtrack: false}}, + { keys: [''], type: 'action', action: 'incrementNumberToken', + isEdit: true, + actionArgs: {increase: false, backtrack: false}}, + // Text object motions + { keys: ['a', 'character'], type: 'motion', + motion: 'textObjectManipulation' }, + { keys: ['i', 'character'], type: 'motion', + motion: 'textObjectManipulation', + motionArgs: { textObjectInner: true }}, + // Search + { keys: ['/'], type: 'search', + searchArgs: { forward: true, querySrc: 'prompt', toJumplist: true }}, + { keys: ['?'], type: 'search', + searchArgs: { forward: false, querySrc: 'prompt', toJumplist: true }}, + { keys: ['*'], type: 'search', + searchArgs: { forward: true, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }}, + { keys: ['#'], type: 'search', + searchArgs: { forward: false, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }}, + { keys: ['g', '*'], type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', toJumplist: true }}, + { keys: ['g', '#'], type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', toJumplist: true }}, + // Ex command + { keys: [':'], type: 'ex' } + ]; + + var Pos = CodeMirror.Pos; + + var Vim = function() { + CodeMirror.defineOption('vimMode', false, function(cm, val) { + if (val) { + cm.setOption('keyMap', 'vim'); + cm.setOption('disableInput', true); + cm.setOption('showCursorWhenSelecting', false); + CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); + cm.on('cursorActivity', onCursorActivity); + maybeInitVimState(cm); + CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm)); + } else if (cm.state.vim) { + cm.setOption('keyMap', 'default'); + cm.setOption('disableInput', false); + cm.off('cursorActivity', onCursorActivity); + CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm)); + cm.state.vim = null; + } + }); + function getOnPasteFn(cm) { + var vim = cm.state.vim; + if (!vim.onPasteFn) { + vim.onPasteFn = function() { + if (!vim.insertMode) { + cm.setCursor(offsetCursor(cm.getCursor(), 0, 1)); + actions.enterInsertMode(cm, {}, vim); + } + }; + } + return vim.onPasteFn; + } + + var numberRegex = /[\d]/; + var wordRegexp = [(/\w/), (/[^\w\s]/)], bigWordRegexp = [(/\S/)]; + function makeKeyRange(start, size) { + var keys = []; + for (var i = start; i < start + size; i++) { + keys.push(String.fromCharCode(i)); + } + return keys; + } + var upperCaseAlphabet = makeKeyRange(65, 26); + var lowerCaseAlphabet = makeKeyRange(97, 26); + var numbers = makeKeyRange(48, 10); + var specialSymbols = '~`!@#$%^&*()_-+=[{}]\\|/?.,<>:;"\''.split(''); + var specialKeys = ['Left', 'Right', 'Up', 'Down', 'Space', 'Backspace', + 'Esc', 'Home', 'End', 'PageUp', 'PageDown', 'Enter']; + var validMarks = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['<', '>']); + var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"', '.', ':', '/']); + + function isLine(cm, line) { + return line >= cm.firstLine() && line <= cm.lastLine(); + } + function isLowerCase(k) { + return (/^[a-z]$/).test(k); + } + function isMatchableSymbol(k) { + return '()[]{}'.indexOf(k) != -1; + } + function isNumber(k) { + return numberRegex.test(k); + } + function isUpperCase(k) { + return (/^[A-Z]$/).test(k); + } + function isWhiteSpaceString(k) { + return (/^\s*$/).test(k); + } + function inArray(val, arr) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] == val) { + return true; + } + } + return false; + } + + var options = {}; + function defineOption(name, defaultValue, type) { + if (defaultValue === undefined) { throw Error('defaultValue is required'); } + if (!type) { type = 'string'; } + options[name] = { + type: type, + defaultValue: defaultValue + }; + setOption(name, defaultValue); + } + + function setOption(name, value) { + var option = options[name]; + if (!option) { + throw Error('Unknown option: ' + name); + } + if (option.type == 'boolean') { + if (value && value !== true) { + throw Error('Invalid argument: ' + name + '=' + value); + } else if (value !== false) { + // Boolean options are set to true if value is not defined. + value = true; + } + } + option.value = option.type == 'boolean' ? !!value : value; + } + + function getOption(name) { + var option = options[name]; + if (!option) { + throw Error('Unknown option: ' + name); + } + return option.value; + } + + var createCircularJumpList = function() { + var size = 100; + var pointer = -1; + var head = 0; + var tail = 0; + var buffer = new Array(size); + function add(cm, oldCur, newCur) { + var current = pointer % size; + var curMark = buffer[current]; + function useNextSlot(cursor) { + var next = ++pointer % size; + var trashMark = buffer[next]; + if (trashMark) { + trashMark.clear(); + } + buffer[next] = cm.setBookmark(cursor); + } + if (curMark) { + var markPos = curMark.find(); + // avoid recording redundant cursor position + if (markPos && !cursorEqual(markPos, oldCur)) { + useNextSlot(oldCur); + } + } else { + useNextSlot(oldCur); + } + useNextSlot(newCur); + head = pointer; + tail = pointer - size + 1; + if (tail < 0) { + tail = 0; + } + } + function move(cm, offset) { + pointer += offset; + if (pointer > head) { + pointer = head; + } else if (pointer < tail) { + pointer = tail; + } + var mark = buffer[(size + pointer) % size]; + // skip marks that are temporarily removed from text buffer + if (mark && !mark.find()) { + var inc = offset > 0 ? 1 : -1; + var newCur; + var oldCur = cm.getCursor(); + do { + pointer += inc; + mark = buffer[(size + pointer) % size]; + // skip marks that are the same as current position + if (mark && + (newCur = mark.find()) && + !cursorEqual(oldCur, newCur)) { + break; + } + } while (pointer < head && pointer > tail); + } + return mark; + } + return { + cachedCursor: undefined, //used for # and * jumps + add: add, + move: move + }; + }; + + // Returns an object to track the changes associated insert mode. It + // clones the object that is passed in, or creates an empty object one if + // none is provided. + var createInsertModeChanges = function(c) { + if (c) { + // Copy construction + return { + changes: c.changes, + expectCursorActivityForChange: c.expectCursorActivityForChange + }; + } + return { + // Change list + changes: [], + // Set to true on change, false on cursorActivity. + expectCursorActivityForChange: false + }; + }; + + function MacroModeState() { + this.latestRegister = undefined; + this.isPlaying = false; + this.isRecording = false; + this.replaySearchQueries = []; + this.onRecordingDone = undefined; + this.lastInsertModeChanges = createInsertModeChanges(); + } + MacroModeState.prototype = { + exitMacroRecordMode: function() { + var macroModeState = vimGlobalState.macroModeState; + macroModeState.onRecordingDone(); // close dialog + macroModeState.onRecordingDone = undefined; + macroModeState.isRecording = false; + }, + enterMacroRecordMode: function(cm, registerName) { + var register = + vimGlobalState.registerController.getRegister(registerName); + if (register) { + register.clear(); + this.latestRegister = registerName; + this.onRecordingDone = cm.openDialog( + '(recording)['+registerName+']', null, {bottom:true}); + this.isRecording = true; + } + } + }; + + function maybeInitVimState(cm) { + if (!cm.state.vim) { + // Store instance state in the CodeMirror object. + cm.state.vim = { + inputState: new InputState(), + // Vim's input state that triggered the last edit, used to repeat + // motions and operators with '.'. + lastEditInputState: undefined, + // Vim's action command before the last edit, used to repeat actions + // with '.' and insert mode repeat. + lastEditActionCommand: undefined, + // When using jk for navigation, if you move from a longer line to a + // shorter line, the cursor may clip to the end of the shorter line. + // If j is pressed again and cursor goes to the next line, the + // cursor should go back to its horizontal position on the longer + // line if it can. This is to keep track of the horizontal position. + lastHPos: -1, + // Doing the same with screen-position for gj/gk + lastHSPos: -1, + // The last motion command run. Cleared if a non-motion command gets + // executed in between. + lastMotion: null, + marks: {}, + // Mark for rendering fake cursor for visual mode. + fakeCursor: null, + insertMode: false, + // Repeat count for changes made in insert mode, triggered by key + // sequences like 3,i. Only exists when insertMode is true. + insertModeRepeat: undefined, + visualMode: false, + // If we are in visual line mode. No effect if visualMode is false. + visualLine: false, + lastSelection: null, + lastPastedText: null + }; + } + return cm.state.vim; + } + var vimGlobalState; + function resetVimGlobalState() { + vimGlobalState = { + // The current search query. + searchQuery: null, + // Whether we are searching backwards. + searchIsReversed: false, + // Replace part of the last substituted pattern + lastSubstituteReplacePart: undefined, + jumpList: createCircularJumpList(), + macroModeState: new MacroModeState, + // Recording latest f, t, F or T motion command. + lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''}, + registerController: new RegisterController({}), + // search history buffer + searchHistoryController: new HistoryController({}), + // ex Command history buffer + exCommandHistoryController : new HistoryController({}) + }; + for (var optionName in options) { + var option = options[optionName]; + option.value = option.defaultValue; + } + } + + var vimApi= { + buildKeyMap: function() { + // TODO: Convert keymap into dictionary format for fast lookup. + }, + // Testing hook, though it might be useful to expose the register + // controller anyways. + getRegisterController: function() { + return vimGlobalState.registerController; + }, + // Testing hook. + resetVimGlobalState_: resetVimGlobalState, + + // Testing hook. + getVimGlobalState_: function() { + return vimGlobalState; + }, + + // Testing hook. + maybeInitVimState_: maybeInitVimState, + + InsertModeKey: InsertModeKey, + map: function(lhs, rhs, ctx) { + // Add user defined key bindings. + exCommandDispatcher.map(lhs, rhs, ctx); + }, + setOption: setOption, + getOption: getOption, + defineOption: defineOption, + defineEx: function(name, prefix, func){ + if (name.indexOf(prefix) !== 0) { + throw new Error('(Vim.defineEx) "'+prefix+'" is not a prefix of "'+name+'", command not registered'); + } + exCommands[name]=func; + exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'}; + }, + // This is the outermost function called by CodeMirror, after keys have + // been mapped to their Vim equivalents. + handleKey: function(cm, key) { + var command; + var vim = maybeInitVimState(cm); + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isRecording) { + if (key == 'q') { + macroModeState.exitMacroRecordMode(); + clearInputState(cm); + return; + } + } + if (key == '') { + // Clear input state and get back to normal mode. + clearInputState(cm); + if (vim.visualMode) { + exitVisualMode(cm); + } + return; + } + // Enter visual mode when the mouse selects text. + if (!vim.visualMode && + !cursorEqual(cm.getCursor('head'), cm.getCursor('anchor'))) { + vim.visualMode = true; + vim.visualLine = false; + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual"}); + cm.on('mousedown', exitVisualMode); + } + if (key != '0' || (key == '0' && vim.inputState.getRepeat() === 0)) { + // Have to special case 0 since it's both a motion and a number. + command = commandDispatcher.matchCommand(key, defaultKeymap, vim); + } + if (!command) { + if (isNumber(key)) { + // Increment count unless count is 0 and key is 0. + vim.inputState.pushRepeatDigit(key); + } + if (macroModeState.isRecording) { + logKey(macroModeState, key); + } + return; + } + if (command.type == 'keyToKey') { + // TODO: prevent infinite recursion. + for (var i = 0; i < command.toKeys.length; i++) { + this.handleKey(cm, command.toKeys[i]); + } + } else { + if (macroModeState.isRecording) { + logKey(macroModeState, key); + } + commandDispatcher.processCommand(cm, vim, command); + } + }, + handleEx: function(cm, input) { + exCommandDispatcher.processCommand(cm, input); + } + }; + + // Represents the current input state. + function InputState() { + this.prefixRepeat = []; + this.motionRepeat = []; + + this.operator = null; + this.operatorArgs = null; + this.motion = null; + this.motionArgs = null; + this.keyBuffer = []; // For matching multi-key commands. + this.registerName = null; // Defaults to the unnamed register. + } + InputState.prototype.pushRepeatDigit = function(n) { + if (!this.operator) { + this.prefixRepeat = this.prefixRepeat.concat(n); + } else { + this.motionRepeat = this.motionRepeat.concat(n); + } + }; + InputState.prototype.getRepeat = function() { + var repeat = 0; + if (this.prefixRepeat.length > 0 || this.motionRepeat.length > 0) { + repeat = 1; + if (this.prefixRepeat.length > 0) { + repeat *= parseInt(this.prefixRepeat.join(''), 10); + } + if (this.motionRepeat.length > 0) { + repeat *= parseInt(this.motionRepeat.join(''), 10); + } + } + return repeat; + }; + + function clearInputState(cm, reason) { + cm.state.vim.inputState = new InputState(); + CodeMirror.signal(cm, 'vim-command-done', reason); + } + + /* + * Register stores information about copy and paste registers. Besides + * text, a register must store whether it is linewise (i.e., when it is + * pasted, should it insert itself into a new line, or should the text be + * inserted at the cursor position.) + */ + function Register(text, linewise) { + this.clear(); + this.keyBuffer = [text || '']; + this.insertModeChanges = []; + this.searchQueries = []; + this.linewise = !!linewise; + } + Register.prototype = { + setText: function(text, linewise) { + this.keyBuffer = [text || '']; + this.linewise = !!linewise; + }, + pushText: function(text, linewise) { + // if this register has ever been set to linewise, use linewise. + if (linewise) { + if (!this.linewise) { + this.keyBuffer.push('\n'); + } + this.linewise = true; + } + this.keyBuffer.push(text); + }, + pushInsertModeChanges: function(changes) { + this.insertModeChanges.push(createInsertModeChanges(changes)); + }, + pushSearchQuery: function(query) { + this.searchQueries.push(query); + }, + clear: function() { + this.keyBuffer = []; + this.insertModeChanges = []; + this.searchQueries = []; + this.linewise = false; + }, + toString: function() { + return this.keyBuffer.join(''); + } + }; + + /* + * vim registers allow you to keep many independent copy and paste buffers. + * See http://usevim.com/2012/04/13/registers/ for an introduction. + * + * RegisterController keeps the state of all the registers. An initial + * state may be passed in. The unnamed register '"' will always be + * overridden. + */ + function RegisterController(registers) { + this.registers = registers; + this.unnamedRegister = registers['"'] = new Register(); + registers['.'] = new Register(); + registers[':'] = new Register(); + registers['/'] = new Register(); + } + RegisterController.prototype = { + pushText: function(registerName, operator, text, linewise) { + if (linewise && text.charAt(0) == '\n') { + text = text.slice(1) + '\n'; + } + if (linewise && text.charAt(text.length - 1) !== '\n'){ + text += '\n'; + } + // Lowercase and uppercase registers refer to the same register. + // Uppercase just means append. + var register = this.isValidRegister(registerName) ? + this.getRegister(registerName) : null; + // if no register/an invalid register was specified, things go to the + // default registers + if (!register) { + switch (operator) { + case 'yank': + // The 0 register contains the text from the most recent yank. + this.registers['0'] = new Register(text, linewise); + break; + case 'delete': + case 'change': + if (text.indexOf('\n') == -1) { + // Delete less than 1 line. Update the small delete register. + this.registers['-'] = new Register(text, linewise); + } else { + // Shift down the contents of the numbered registers and put the + // deleted text into register 1. + this.shiftNumericRegisters_(); + this.registers['1'] = new Register(text, linewise); + } + break; + } + // Make sure the unnamed register is set to what just happened + this.unnamedRegister.setText(text, linewise); + return; + } + + // If we've gotten to this point, we've actually specified a register + var append = isUpperCase(registerName); + if (append) { + register.pushText(text, linewise); + } else { + register.setText(text, linewise); + } + // The unnamed register always has the same value as the last used + // register. + this.unnamedRegister.setText(register.toString(), linewise); + }, + // Gets the register named @name. If one of @name doesn't already exist, + // create it. If @name is invalid, return the unnamedRegister. + getRegister: function(name) { + if (!this.isValidRegister(name)) { + return this.unnamedRegister; + } + name = name.toLowerCase(); + if (!this.registers[name]) { + this.registers[name] = new Register(); + } + return this.registers[name]; + }, + isValidRegister: function(name) { + return name && inArray(name, validRegisters); + }, + shiftNumericRegisters_: function() { + for (var i = 9; i >= 2; i--) { + this.registers[i] = this.getRegister('' + (i - 1)); + } + } + }; + function HistoryController() { + this.historyBuffer = []; + this.iterator; + this.initialPrefix = null; + } + HistoryController.prototype = { + // the input argument here acts a user entered prefix for a small time + // until we start autocompletion in which case it is the autocompleted. + nextMatch: function (input, up) { + var historyBuffer = this.historyBuffer; + var dir = up ? -1 : 1; + if (this.initialPrefix === null) this.initialPrefix = input; + for (var i = this.iterator + dir; up ? i >= 0 : i < historyBuffer.length; i+= dir) { + var element = historyBuffer[i]; + for (var j = 0; j <= element.length; j++) { + if (this.initialPrefix == element.substring(0, j)) { + this.iterator = i; + return element; + } + } + } + // should return the user input in case we reach the end of buffer. + if (i >= historyBuffer.length) { + this.iterator = historyBuffer.length; + return this.initialPrefix; + } + // return the last autocompleted query or exCommand as it is. + if (i < 0 ) return input; + }, + pushInput: function(input) { + var index = this.historyBuffer.indexOf(input); + if (index > -1) this.historyBuffer.splice(index, 1); + if (input.length) this.historyBuffer.push(input); + }, + reset: function() { + this.initialPrefix = null; + this.iterator = this.historyBuffer.length; + } + }; + var commandDispatcher = { + matchCommand: function(key, keyMap, vim) { + var inputState = vim.inputState; + var keys = inputState.keyBuffer.concat(key); + var matchedCommands = []; + var selectedCharacter; + for (var i = 0; i < keyMap.length; i++) { + var command = keyMap[i]; + if (matchKeysPartial(keys, command.keys)) { + if (inputState.operator && command.type == 'action') { + // Ignore matched action commands after an operator. Operators + // only operate on motions. This check is really for text + // objects since aW, a[ etcs conflicts with a. + continue; + } + // Match commands that take as an argument. + if (command.keys[keys.length - 1] == 'character') { + selectedCharacter = keys[keys.length - 1]; + if (selectedCharacter.length>1){ + switch(selectedCharacter){ + case '': + selectedCharacter='\n'; + break; + case '': + selectedCharacter=' '; + break; + default: + continue; + } + } + } + // Add the command to the list of matched commands. Choose the best + // command later. + matchedCommands.push(command); + } + } + + // Returns the command if it is a full match, or null if not. + function getFullyMatchedCommandOrNull(command) { + if (keys.length < command.keys.length) { + // Matches part of a multi-key command. Buffer and wait for next + // stroke. + inputState.keyBuffer.push(key); + return null; + } else { + if (command.keys[keys.length - 1] == 'character') { + inputState.selectedCharacter = selectedCharacter; + } + // Clear the buffer since a full match was found. + inputState.keyBuffer = []; + return command; + } + } + + if (!matchedCommands.length) { + // Clear the buffer since there were no matches. + inputState.keyBuffer = []; + return null; + } else if (matchedCommands.length == 1) { + return getFullyMatchedCommandOrNull(matchedCommands[0]); + } else { + // Find the best match in the list of matchedCommands. + var context = vim.visualMode ? 'visual' : 'normal'; + var bestMatch; // Default to first in the list. + for (var i = 0; i < matchedCommands.length; i++) { + var current = matchedCommands[i]; + if (current.context == context) { + bestMatch = current; + break; + } else if (!bestMatch && !current.context) { + // Only set an imperfect match to best match if no best match is + // set and the imperfect match is not restricted to another + // context. + bestMatch = current; + } + } + return getFullyMatchedCommandOrNull(bestMatch); + } + }, + processCommand: function(cm, vim, command) { + vim.inputState.repeatOverride = command.repeatOverride; + switch (command.type) { + case 'motion': + this.processMotion(cm, vim, command); + break; + case 'operator': + this.processOperator(cm, vim, command); + break; + case 'operatorMotion': + this.processOperatorMotion(cm, vim, command); + break; + case 'action': + this.processAction(cm, vim, command); + break; + case 'search': + this.processSearch(cm, vim, command); + break; + case 'ex': + case 'keyToEx': + this.processEx(cm, vim, command); + break; + default: + break; + } + }, + processMotion: function(cm, vim, command) { + vim.inputState.motion = command.motion; + vim.inputState.motionArgs = copyArgs(command.motionArgs); + this.evalInput(cm, vim); + }, + processOperator: function(cm, vim, command) { + var inputState = vim.inputState; + if (inputState.operator) { + if (inputState.operator == command.operator) { + // Typing an operator twice like 'dd' makes the operator operate + // linewise + inputState.motion = 'expandToLine'; + inputState.motionArgs = { linewise: true }; + this.evalInput(cm, vim); + return; + } else { + // 2 different operators in a row doesn't make sense. + clearInputState(cm); + } + } + inputState.operator = command.operator; + inputState.operatorArgs = copyArgs(command.operatorArgs); + if (vim.visualMode) { + // Operating on a selection in visual mode. We don't need a motion. + this.evalInput(cm, vim); + } + }, + processOperatorMotion: function(cm, vim, command) { + var visualMode = vim.visualMode; + var operatorMotionArgs = copyArgs(command.operatorMotionArgs); + if (operatorMotionArgs) { + // Operator motions may have special behavior in visual mode. + if (visualMode && operatorMotionArgs.visualLine) { + vim.visualLine = true; + } + } + this.processOperator(cm, vim, command); + if (!visualMode) { + this.processMotion(cm, vim, command); + } + }, + processAction: function(cm, vim, command) { + var inputState = vim.inputState; + var repeat = inputState.getRepeat(); + var repeatIsExplicit = !!repeat; + var actionArgs = copyArgs(command.actionArgs) || {}; + if (inputState.selectedCharacter) { + actionArgs.selectedCharacter = inputState.selectedCharacter; + } + // Actions may or may not have motions and operators. Do these first. + if (command.operator) { + this.processOperator(cm, vim, command); + } + if (command.motion) { + this.processMotion(cm, vim, command); + } + if (command.motion || command.operator) { + this.evalInput(cm, vim); + } + actionArgs.repeat = repeat || 1; + actionArgs.repeatIsExplicit = repeatIsExplicit; + actionArgs.registerName = inputState.registerName; + clearInputState(cm); + vim.lastMotion = null; + if (command.isEdit) { + this.recordLastEdit(vim, inputState, command); + } + actions[command.action](cm, actionArgs, vim); + }, + processSearch: function(cm, vim, command) { + if (!cm.getSearchCursor) { + // Search depends on SearchCursor. + return; + } + var forward = command.searchArgs.forward; + var wholeWordOnly = command.searchArgs.wholeWordOnly; + getSearchState(cm).setReversed(!forward); + var promptPrefix = (forward) ? '/' : '?'; + var originalQuery = getSearchState(cm).getQuery(); + var originalScrollPos = cm.getScrollInfo(); + function handleQuery(query, ignoreCase, smartCase) { + vimGlobalState.searchHistoryController.pushInput(query); + vimGlobalState.searchHistoryController.reset(); + try { + updateSearchQuery(cm, query, ignoreCase, smartCase); + } catch (e) { + showConfirm(cm, 'Invalid regex: ' + query); + return; + } + commandDispatcher.processMotion(cm, vim, { + type: 'motion', + motion: 'findNext', + motionArgs: { forward: true, toJumplist: command.searchArgs.toJumplist } + }); + } + function onPromptClose(query) { + cm.scrollTo(originalScrollPos.left, originalScrollPos.top); + handleQuery(query, true /** ignoreCase */, true /** smartCase */); + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isRecording) { + logSearchQuery(macroModeState, query); + } + } + function onPromptKeyUp(e, query, close) { + var keyName = CodeMirror.keyName(e), up; + if (keyName == 'Up' || keyName == 'Down') { + up = keyName == 'Up' ? true : false; + query = vimGlobalState.searchHistoryController.nextMatch(query, up) || ''; + close(query); + } else { + if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift') + vimGlobalState.searchHistoryController.reset(); + } + var parsedQuery; + try { + parsedQuery = updateSearchQuery(cm, query, + true /** ignoreCase */, true /** smartCase */); + } catch (e) { + // Swallow bad regexes for incremental search. + } + if (parsedQuery) { + cm.scrollIntoView(findNext(cm, !forward, parsedQuery), 30); + } else { + clearSearchHighlight(cm); + cm.scrollTo(originalScrollPos.left, originalScrollPos.top); + } + } + function onPromptKeyDown(e, query, close) { + var keyName = CodeMirror.keyName(e); + if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') { + vimGlobalState.searchHistoryController.pushInput(query); + vimGlobalState.searchHistoryController.reset(); + updateSearchQuery(cm, originalQuery); + clearSearchHighlight(cm); + cm.scrollTo(originalScrollPos.left, originalScrollPos.top); + CodeMirror.e_stop(e); + close(); + cm.focus(); + } + } + switch (command.searchArgs.querySrc) { + case 'prompt': + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isPlaying) { + var query = macroModeState.replaySearchQueries.shift(); + handleQuery(query, true /** ignoreCase */, false /** smartCase */); + } else { + showPrompt(cm, { + onClose: onPromptClose, + prefix: promptPrefix, + desc: searchPromptDesc, + onKeyUp: onPromptKeyUp, + onKeyDown: onPromptKeyDown + }); + } + break; + case 'wordUnderCursor': + var word = expandWordUnderCursor(cm, false /** inclusive */, + true /** forward */, false /** bigWord */, + true /** noSymbol */); + var isKeyword = true; + if (!word) { + word = expandWordUnderCursor(cm, false /** inclusive */, + true /** forward */, false /** bigWord */, + false /** noSymbol */); + isKeyword = false; + } + if (!word) { + return; + } + var query = cm.getLine(word.start.line).substring(word.start.ch, + word.end.ch); + if (isKeyword && wholeWordOnly) { + query = '\\b' + query + '\\b'; + } else { + query = escapeRegex(query); + } + + // cachedCursor is used to save the old position of the cursor + // when * or # causes vim to seek for the nearest word and shift + // the cursor before entering the motion. + vimGlobalState.jumpList.cachedCursor = cm.getCursor(); + cm.setCursor(word.start); + + handleQuery(query, true /** ignoreCase */, false /** smartCase */); + break; + } + }, + processEx: function(cm, vim, command) { + function onPromptClose(input) { + // Give the prompt some time to close so that if processCommand shows + // an error, the elements don't overlap. + vimGlobalState.exCommandHistoryController.pushInput(input); + vimGlobalState.exCommandHistoryController.reset(); + exCommandDispatcher.processCommand(cm, input); + } + function onPromptKeyDown(e, input, close) { + var keyName = CodeMirror.keyName(e), up; + if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') { + vimGlobalState.exCommandHistoryController.pushInput(input); + vimGlobalState.exCommandHistoryController.reset(); + CodeMirror.e_stop(e); + close(); + cm.focus(); + } + if (keyName == 'Up' || keyName == 'Down') { + up = keyName == 'Up' ? true : false; + input = vimGlobalState.exCommandHistoryController.nextMatch(input, up) || ''; + close(input); + } else { + if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift') + vimGlobalState.exCommandHistoryController.reset(); + } + } + if (command.type == 'keyToEx') { + // Handle user defined Ex to Ex mappings + exCommandDispatcher.processCommand(cm, command.exArgs.input); + } else { + if (vim.visualMode) { + showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>', + onKeyDown: onPromptKeyDown}); + } else { + showPrompt(cm, { onClose: onPromptClose, prefix: ':', + onKeyDown: onPromptKeyDown}); + } + } + }, + evalInput: function(cm, vim) { + // If the motion comand is set, execute both the operator and motion. + // Otherwise return. + var inputState = vim.inputState; + var motion = inputState.motion; + var motionArgs = inputState.motionArgs || {}; + var operator = inputState.operator; + var operatorArgs = inputState.operatorArgs || {}; + var registerName = inputState.registerName; + var selectionEnd = copyCursor(cm.getCursor('head')); + var selectionStart = copyCursor(cm.getCursor('anchor')); + // The difference between cur and selection cursors are that cur is + // being operated on and ignores that there is a selection. + var curStart = copyCursor(selectionEnd); + var curOriginal = copyCursor(curStart); + var curEnd; + var repeat; + if (operator) { + this.recordLastEdit(vim, inputState); + } + if (inputState.repeatOverride !== undefined) { + // If repeatOverride is specified, that takes precedence over the + // input state's repeat. Used by Ex mode and can be user defined. + repeat = inputState.repeatOverride; + } else { + repeat = inputState.getRepeat(); + } + if (repeat > 0 && motionArgs.explicitRepeat) { + motionArgs.repeatIsExplicit = true; + } else if (motionArgs.noRepeat || + (!motionArgs.explicitRepeat && repeat === 0)) { + repeat = 1; + motionArgs.repeatIsExplicit = false; + } + if (inputState.selectedCharacter) { + // If there is a character input, stick it in all of the arg arrays. + motionArgs.selectedCharacter = operatorArgs.selectedCharacter = + inputState.selectedCharacter; + } + motionArgs.repeat = repeat; + clearInputState(cm); + if (motion) { + var motionResult = motions[motion](cm, motionArgs, vim); + vim.lastMotion = motions[motion]; + if (!motionResult) { + return; + } + if (motionArgs.toJumplist) { + var jumpList = vimGlobalState.jumpList; + // if the current motion is # or *, use cachedCursor + var cachedCursor = jumpList.cachedCursor; + if (cachedCursor) { + recordJumpPosition(cm, cachedCursor, motionResult); + delete jumpList.cachedCursor; + } else { + recordJumpPosition(cm, curOriginal, motionResult); + } + } + if (motionResult instanceof Array) { + curStart = motionResult[0]; + curEnd = motionResult[1]; + } else { + curEnd = motionResult; + } + // TODO: Handle null returns from motion commands better. + if (!curEnd) { + curEnd = Pos(curStart.line, curStart.ch); + } + if (vim.visualMode) { + // Check if the selection crossed over itself. Will need to shift + // the start point if that happened. + if (cursorIsBefore(selectionStart, selectionEnd) && + (cursorEqual(selectionStart, curEnd) || + cursorIsBefore(curEnd, selectionStart))) { + // The end of the selection has moved from after the start to + // before the start. We will shift the start right by 1. + selectionStart.ch += 1; + curEnd.ch -= 1; + } else if (cursorIsBefore(selectionEnd, selectionStart) && + (cursorEqual(selectionStart, curEnd) || + cursorIsBefore(selectionStart, curEnd))) { + // The opposite happened. We will shift the start left by 1. + selectionStart.ch -= 1; + curEnd.ch += 1; + } + if (vim.lastHPos != Infinity) { + vim.lastHPos = curEnd.ch; + } + selectionEnd = curEnd; + selectionStart = (motionResult instanceof Array) ? curStart : selectionStart; + if (vim.visualLine) { + if (cursorIsBefore(selectionStart, selectionEnd)) { + selectionStart.ch = 0; + + var lastLine = cm.lastLine(); + if (selectionEnd.line > lastLine) { + selectionEnd.line = lastLine; + } + selectionEnd.ch = lineLength(cm, selectionEnd.line); + } else { + selectionEnd.ch = 0; + selectionStart.ch = lineLength(cm, selectionStart.line); + } + } + cm.setSelection(selectionStart, selectionEnd); + updateMark(cm, vim, '<', + cursorIsBefore(selectionStart, selectionEnd) ? selectionStart + : selectionEnd); + updateMark(cm, vim, '>', + cursorIsBefore(selectionStart, selectionEnd) ? selectionEnd + : selectionStart); + } else if (!operator) { + curEnd = clipCursorToContent(cm, curEnd); + cm.setCursor(curEnd.line, curEnd.ch); + } + } + + if (operator) { + var inverted = false; + vim.lastMotion = null; + operatorArgs.repeat = repeat; // Indent in visual mode needs this. + if (vim.visualMode) { + curStart = selectionStart; + curEnd = selectionEnd; + motionArgs.inclusive = true; + } + // Swap start and end if motion was backward. + if (curEnd && cursorIsBefore(curEnd, curStart)) { + var tmp = curStart; + curStart = curEnd; + curEnd = tmp; + inverted = true; + } else if (!curEnd) { + curEnd = copyCursor(curStart); + } + if (motionArgs.inclusive && !vim.visualMode) { + // Move the selection end one to the right to include the last + // character. + curEnd.ch++; + } + if (operatorArgs.selOffset) { + // Replaying a visual mode operation + curEnd.line = curStart.line + operatorArgs.selOffset.line; + if (operatorArgs.selOffset.line) {curEnd.ch = operatorArgs.selOffset.ch; } + else { curEnd.ch = curStart.ch + operatorArgs.selOffset.ch; } + } else if (vim.visualMode) { + var selOffset = Pos(); + selOffset.line = curEnd.line - curStart.line; + if (selOffset.line) { selOffset.ch = curEnd.ch; } + else { selOffset.ch = curEnd.ch - curStart.ch; } + operatorArgs.selOffset = selOffset; + } + var linewise = motionArgs.linewise || + (vim.visualMode && vim.visualLine) || + operatorArgs.linewise; + if (linewise) { + // Expand selection to entire line. + expandSelectionToLine(cm, curStart, curEnd); + } else if (motionArgs.forward) { + // Clip to trailing newlines only if the motion goes forward. + clipToLine(cm, curStart, curEnd); + } + operatorArgs.registerName = registerName; + // Keep track of linewise as it affects how paste and change behave. + operatorArgs.linewise = linewise; + operators[operator](cm, operatorArgs, vim, curStart, + curEnd, curOriginal); + if (vim.visualMode) { + exitVisualMode(cm); + } + } + }, + recordLastEdit: function(vim, inputState, actionCommand) { + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isPlaying) { return; } + vim.lastEditInputState = inputState; + vim.lastEditActionCommand = actionCommand; + macroModeState.lastInsertModeChanges.changes = []; + macroModeState.lastInsertModeChanges.expectCursorActivityForChange = false; + } + }; + + /** + * typedef {Object{line:number,ch:number}} Cursor An object containing the + * position of the cursor. + */ + // All of the functions below return Cursor objects. + var motions = { + moveToTopLine: function(cm, motionArgs) { + var line = getUserVisibleLines(cm).top + motionArgs.repeat -1; + return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); + }, + moveToMiddleLine: function(cm) { + var range = getUserVisibleLines(cm); + var line = Math.floor((range.top + range.bottom) * 0.5); + return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); + }, + moveToBottomLine: function(cm, motionArgs) { + var line = getUserVisibleLines(cm).bottom - motionArgs.repeat +1; + return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); + }, + expandToLine: function(cm, motionArgs) { + // Expands forward to end of line, and then to next line if repeat is + // >1. Does not handle backward motion! + var cur = cm.getCursor(); + return Pos(cur.line + motionArgs.repeat - 1, Infinity); + }, + findNext: function(cm, motionArgs) { + var state = getSearchState(cm); + var query = state.getQuery(); + if (!query) { + return; + } + var prev = !motionArgs.forward; + // If search is initiated with ? instead of /, negate direction. + prev = (state.isReversed()) ? !prev : prev; + highlightSearchMatches(cm, query); + return findNext(cm, prev/** prev */, query, motionArgs.repeat); + }, + goToMark: function(cm, motionArgs, vim) { + var mark = vim.marks[motionArgs.selectedCharacter]; + if (mark) { + var pos = mark.find(); + return motionArgs.linewise ? { line: pos.line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(pos.line)) } : pos; + } + return null; + }, + moveToOtherHighlightedEnd: function(cm) { + var curEnd = copyCursor(cm.getCursor('head')); + var curStart = copyCursor(cm.getCursor('anchor')); + if (cursorIsBefore(curStart, curEnd)) { + curEnd.ch += 1; + } else if (cursorIsBefore(curEnd, curStart)) { + curStart.ch -= 1; + } + return ([curEnd,curStart]); + }, + jumpToMark: function(cm, motionArgs, vim) { + var best = cm.getCursor(); + for (var i = 0; i < motionArgs.repeat; i++) { + var cursor = best; + for (var key in vim.marks) { + if (!isLowerCase(key)) { + continue; + } + var mark = vim.marks[key].find(); + var isWrongDirection = (motionArgs.forward) ? + cursorIsBefore(mark, cursor) : cursorIsBefore(cursor, mark); + + if (isWrongDirection) { + continue; + } + if (motionArgs.linewise && (mark.line == cursor.line)) { + continue; + } + + var equal = cursorEqual(cursor, best); + var between = (motionArgs.forward) ? + cusrorIsBetween(cursor, mark, best) : + cusrorIsBetween(best, mark, cursor); + + if (equal || between) { + best = mark; + } + } + } + + if (motionArgs.linewise) { + // Vim places the cursor on the first non-whitespace character of + // the line if there is one, else it places the cursor at the end + // of the line, regardless of whether a mark was found. + best = Pos(best.line, findFirstNonWhiteSpaceCharacter(cm.getLine(best.line))); + } + return best; + }, + moveByCharacters: function(cm, motionArgs) { + var cur = cm.getCursor(); + var repeat = motionArgs.repeat; + var ch = motionArgs.forward ? cur.ch + repeat : cur.ch - repeat; + return Pos(cur.line, ch); + }, + moveByLines: function(cm, motionArgs, vim) { + var cur = cm.getCursor(); + var endCh = cur.ch; + // Depending what our last motion was, we may want to do different + // things. If our last motion was moving vertically, we want to + // preserve the HPos from our last horizontal move. If our last motion + // was going to the end of a line, moving vertically we should go to + // the end of the line, etc. + switch (vim.lastMotion) { + case this.moveByLines: + case this.moveByDisplayLines: + case this.moveByScroll: + case this.moveToColumn: + case this.moveToEol: + endCh = vim.lastHPos; + break; + default: + vim.lastHPos = endCh; + } + var repeat = motionArgs.repeat+(motionArgs.repeatOffset||0); + var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat; + var first = cm.firstLine(); + var last = cm.lastLine(); + // Vim cancels linewise motions that start on an edge and move beyond + // that edge. It does not cancel motions that do not start on an edge. + if ((line < first && cur.line == first) || + (line > last && cur.line == last)) { + return; + } + if (motionArgs.toFirstChar){ + endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line)); + vim.lastHPos = endCh; + } + vim.lastHSPos = cm.charCoords(Pos(line, endCh),'div').left; + return Pos(line, endCh); + }, + moveByDisplayLines: function(cm, motionArgs, vim) { + var cur = cm.getCursor(); + switch (vim.lastMotion) { + case this.moveByDisplayLines: + case this.moveByScroll: + case this.moveByLines: + case this.moveToColumn: + case this.moveToEol: + break; + default: + vim.lastHSPos = cm.charCoords(cur,'div').left; + } + var repeat = motionArgs.repeat; + var res=cm.findPosV(cur,(motionArgs.forward ? repeat : -repeat),'line',vim.lastHSPos); + if (res.hitSide) { + if (motionArgs.forward) { + var lastCharCoords = cm.charCoords(res, 'div'); + var goalCoords = { top: lastCharCoords.top + 8, left: vim.lastHSPos }; + var res = cm.coordsChar(goalCoords, 'div'); + } else { + var resCoords = cm.charCoords(Pos(cm.firstLine(), 0), 'div'); + resCoords.left = vim.lastHSPos; + res = cm.coordsChar(resCoords, 'div'); + } + } + vim.lastHPos = res.ch; + return res; + }, + moveByPage: function(cm, motionArgs) { + // CodeMirror only exposes functions that move the cursor page down, so + // doing this bad hack to move the cursor and move it back. evalInput + // will move the cursor to where it should be in the end. + var curStart = cm.getCursor(); + var repeat = motionArgs.repeat; + return cm.findPosV(curStart, (motionArgs.forward ? repeat : -repeat), 'page'); + }, + moveByParagraph: function(cm, motionArgs) { + var line = cm.getCursor().line; + var repeat = motionArgs.repeat; + var inc = motionArgs.forward ? 1 : -1; + for (var i = 0; i < repeat; i++) { + if ((!motionArgs.forward && line === cm.firstLine() ) || + (motionArgs.forward && line == cm.lastLine())) { + break; + } + line += inc; + while (line !== cm.firstLine() && line != cm.lastLine() && cm.getLine(line)) { + line += inc; + } + } + return Pos(line, 0); + }, + moveByScroll: function(cm, motionArgs, vim) { + var scrollbox = cm.getScrollInfo(); + var curEnd = null; + var repeat = motionArgs.repeat; + if (!repeat) { + repeat = scrollbox.clientHeight / (2 * cm.defaultTextHeight()); + } + var orig = cm.charCoords(cm.getCursor(), 'local'); + motionArgs.repeat = repeat; + var curEnd = motions.moveByDisplayLines(cm, motionArgs, vim); + if (!curEnd) { + return null; + } + var dest = cm.charCoords(curEnd, 'local'); + cm.scrollTo(null, scrollbox.top + dest.top - orig.top); + return curEnd; + }, + moveByWords: function(cm, motionArgs) { + return moveToWord(cm, motionArgs.repeat, !!motionArgs.forward, + !!motionArgs.wordEnd, !!motionArgs.bigWord); + }, + moveTillCharacter: function(cm, motionArgs) { + var repeat = motionArgs.repeat; + var curEnd = moveToCharacter(cm, repeat, motionArgs.forward, + motionArgs.selectedCharacter); + var increment = motionArgs.forward ? -1 : 1; + recordLastCharacterSearch(increment, motionArgs); + if (!curEnd) return null; + curEnd.ch += increment; + return curEnd; + }, + moveToCharacter: function(cm, motionArgs) { + var repeat = motionArgs.repeat; + recordLastCharacterSearch(0, motionArgs); + return moveToCharacter(cm, repeat, motionArgs.forward, + motionArgs.selectedCharacter) || cm.getCursor(); + }, + moveToSymbol: function(cm, motionArgs) { + var repeat = motionArgs.repeat; + return findSymbol(cm, repeat, motionArgs.forward, + motionArgs.selectedCharacter) || cm.getCursor(); + }, + moveToColumn: function(cm, motionArgs, vim) { + var repeat = motionArgs.repeat; + // repeat is equivalent to which column we want to move to! + vim.lastHPos = repeat - 1; + vim.lastHSPos = cm.charCoords(cm.getCursor(),'div').left; + return moveToColumn(cm, repeat); + }, + moveToEol: function(cm, motionArgs, vim) { + var cur = cm.getCursor(); + vim.lastHPos = Infinity; + var retval= Pos(cur.line + motionArgs.repeat - 1, Infinity); + var end=cm.clipPos(retval); + end.ch--; + vim.lastHSPos = cm.charCoords(end,'div').left; + return retval; + }, + moveToFirstNonWhiteSpaceCharacter: function(cm) { + // Go to the start of the line where the text begins, or the end for + // whitespace-only lines + var cursor = cm.getCursor(); + return Pos(cursor.line, + findFirstNonWhiteSpaceCharacter(cm.getLine(cursor.line))); + }, + moveToMatchedSymbol: function(cm) { + var cursor = cm.getCursor(); + var line = cursor.line; + var ch = cursor.ch; + var lineText = cm.getLine(line); + var symbol; + do { + symbol = lineText.charAt(ch++); + if (symbol && isMatchableSymbol(symbol)) { + var style = cm.getTokenTypeAt(Pos(line, ch)); + if (style !== "string" && style !== "comment") { + break; + } + } + } while (symbol); + if (symbol) { + var matched = cm.findMatchingBracket(Pos(line, ch)); + return matched.to; + } else { + return cursor; + } + }, + moveToStartOfLine: function(cm) { + var cursor = cm.getCursor(); + return Pos(cursor.line, 0); + }, + moveToLineOrEdgeOfDocument: function(cm, motionArgs) { + var lineNum = motionArgs.forward ? cm.lastLine() : cm.firstLine(); + if (motionArgs.repeatIsExplicit) { + lineNum = motionArgs.repeat - cm.getOption('firstLineNumber'); + } + return Pos(lineNum, + findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum))); + }, + textObjectManipulation: function(cm, motionArgs) { + // TODO: lots of possible exceptions that can be thrown here. Try da( + // outside of a () block. + + // TODO: adding <> >< to this map doesn't work, presumably because + // they're operators + var mirroredPairs = {'(': ')', ')': '(', + '{': '}', '}': '{', + '[': ']', ']': '['}; + var selfPaired = {'\'': true, '"': true}; + + var character = motionArgs.selectedCharacter; + // 'b' refers to '()' block. + // 'B' refers to '{}' block. + if (character == 'b') { + character = '('; + } else if (character == 'B') { + character = '{'; + } + + // Inclusive is the difference between a and i + // TODO: Instead of using the additional text object map to perform text + // object operations, merge the map into the defaultKeyMap and use + // motionArgs to define behavior. Define separate entries for 'aw', + // 'iw', 'a[', 'i[', etc. + var inclusive = !motionArgs.textObjectInner; + + var tmp; + if (mirroredPairs[character]) { + tmp = selectCompanionObject(cm, character, inclusive); + } else if (selfPaired[character]) { + tmp = findBeginningAndEnd(cm, character, inclusive); + } else if (character === 'W') { + tmp = expandWordUnderCursor(cm, inclusive, true /** forward */, + true /** bigWord */); + } else if (character === 'w') { + tmp = expandWordUnderCursor(cm, inclusive, true /** forward */, + false /** bigWord */); + } else { + // No text object defined for this, don't move. + return null; + } + + return [tmp.start, tmp.end]; + }, + + repeatLastCharacterSearch: function(cm, motionArgs) { + var lastSearch = vimGlobalState.lastChararacterSearch; + var repeat = motionArgs.repeat; + var forward = motionArgs.forward === lastSearch.forward; + var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1); + cm.moveH(-increment, 'char'); + motionArgs.inclusive = forward ? true : false; + var curEnd = moveToCharacter(cm, repeat, forward, lastSearch.selectedCharacter); + if (!curEnd) { + cm.moveH(increment, 'char'); + return cm.getCursor(); + } + curEnd.ch += increment; + return curEnd; + } + }; + + var operators = { + change: function(cm, operatorArgs, _vim, curStart, curEnd) { + vimGlobalState.registerController.pushText( + operatorArgs.registerName, 'change', cm.getRange(curStart, curEnd), + operatorArgs.linewise); + if (operatorArgs.linewise) { + // Push the next line back down, if there is a next line. + var replacement = curEnd.line > cm.lastLine() ? '' : '\n'; + cm.replaceRange(replacement, curStart, curEnd); + cm.indentLine(curStart.line, 'smart'); + // null ch so setCursor moves to end of line. + curStart.ch = null; + } else { + // Exclude trailing whitespace if the range is not all whitespace. + var text = cm.getRange(curStart, curEnd); + if (!isWhiteSpaceString(text)) { + var match = (/\s+$/).exec(text); + if (match) { + curEnd = offsetCursor(curEnd, 0, - match[0].length); + } + } + cm.replaceRange('', curStart, curEnd); + } + actions.enterInsertMode(cm, {}, cm.state.vim); + cm.setCursor(curStart); + }, + // delete is a javascript keyword. + 'delete': function(cm, operatorArgs, _vim, curStart, curEnd) { + // If the ending line is past the last line, inclusive, instead of + // including the trailing \n, include the \n before the starting line + if (operatorArgs.linewise && + curEnd.line > cm.lastLine() && curStart.line > cm.firstLine()) { + curStart.line--; + curStart.ch = lineLength(cm, curStart.line); + } + vimGlobalState.registerController.pushText( + operatorArgs.registerName, 'delete', cm.getRange(curStart, curEnd), + operatorArgs.linewise); + cm.replaceRange('', curStart, curEnd); + if (operatorArgs.linewise) { + cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm)); + } else { + cm.setCursor(curStart); + } + }, + indent: function(cm, operatorArgs, vim, curStart, curEnd) { + var startLine = curStart.line; + var endLine = curEnd.line; + // In visual mode, n> shifts the selection right n times, instead of + // shifting n lines right once. + var repeat = (vim.visualMode) ? operatorArgs.repeat : 1; + if (operatorArgs.linewise) { + // The only way to delete a newline is to delete until the start of + // the next line, so in linewise mode evalInput will include the next + // line. We don't want this in indent, so we go back a line. + endLine--; + } + for (var i = startLine; i <= endLine; i++) { + for (var j = 0; j < repeat; j++) { + cm.indentLine(i, operatorArgs.indentRight); + } + } + cm.setCursor(curStart); + cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm)); + }, + swapcase: function(cm, operatorArgs, _vim, curStart, curEnd, curOriginal) { + var toSwap = cm.getRange(curStart, curEnd); + var swapped = ''; + for (var i = 0; i < toSwap.length; i++) { + var character = toSwap.charAt(i); + swapped += isUpperCase(character) ? character.toLowerCase() : + character.toUpperCase(); + } + cm.replaceRange(swapped, curStart, curEnd); + if (!operatorArgs.shouldMoveCursor) { + cm.setCursor(curOriginal); + } + }, + yank: function(cm, operatorArgs, _vim, curStart, curEnd, curOriginal) { + vimGlobalState.registerController.pushText( + operatorArgs.registerName, 'yank', + cm.getRange(curStart, curEnd), operatorArgs.linewise); + cm.setCursor(curOriginal); + } + }; + + var actions = { + jumpListWalk: function(cm, actionArgs, vim) { + if (vim.visualMode) { + return; + } + var repeat = actionArgs.repeat; + var forward = actionArgs.forward; + var jumpList = vimGlobalState.jumpList; + + var mark = jumpList.move(cm, forward ? repeat : -repeat); + var markPos = mark ? mark.find() : undefined; + markPos = markPos ? markPos : cm.getCursor(); + cm.setCursor(markPos); + }, + scroll: function(cm, actionArgs, vim) { + if (vim.visualMode) { + return; + } + var repeat = actionArgs.repeat || 1; + var lineHeight = cm.defaultTextHeight(); + var top = cm.getScrollInfo().top; + var delta = lineHeight * repeat; + var newPos = actionArgs.forward ? top + delta : top - delta; + var cursor = copyCursor(cm.getCursor()); + var cursorCoords = cm.charCoords(cursor, 'local'); + if (actionArgs.forward) { + if (newPos > cursorCoords.top) { + cursor.line += (newPos - cursorCoords.top) / lineHeight; + cursor.line = Math.ceil(cursor.line); + cm.setCursor(cursor); + cursorCoords = cm.charCoords(cursor, 'local'); + cm.scrollTo(null, cursorCoords.top); + } else { + // Cursor stays within bounds. Just reposition the scroll window. + cm.scrollTo(null, newPos); + } + } else { + var newBottom = newPos + cm.getScrollInfo().clientHeight; + if (newBottom < cursorCoords.bottom) { + cursor.line -= (cursorCoords.bottom - newBottom) / lineHeight; + cursor.line = Math.floor(cursor.line); + cm.setCursor(cursor); + cursorCoords = cm.charCoords(cursor, 'local'); + cm.scrollTo( + null, cursorCoords.bottom - cm.getScrollInfo().clientHeight); + } else { + // Cursor stays within bounds. Just reposition the scroll window. + cm.scrollTo(null, newPos); + } + } + }, + scrollToCursor: function(cm, actionArgs) { + var lineNum = cm.getCursor().line; + var charCoords = cm.charCoords(Pos(lineNum, 0), 'local'); + var height = cm.getScrollInfo().clientHeight; + var y = charCoords.top; + var lineHeight = charCoords.bottom - y; + switch (actionArgs.position) { + case 'center': y = y - (height / 2) + lineHeight; + break; + case 'bottom': y = y - height + lineHeight*1.4; + break; + case 'top': y = y + lineHeight*0.4; + break; + } + cm.scrollTo(null, y); + }, + replayMacro: function(cm, actionArgs, vim) { + var registerName = actionArgs.selectedCharacter; + var repeat = actionArgs.repeat; + var macroModeState = vimGlobalState.macroModeState; + if (registerName == '@') { + registerName = macroModeState.latestRegister; + } + while(repeat--){ + executeMacroRegister(cm, vim, macroModeState, registerName); + } + }, + enterMacroRecordMode: function(cm, actionArgs) { + var macroModeState = vimGlobalState.macroModeState; + var registerName = actionArgs.selectedCharacter; + macroModeState.enterMacroRecordMode(cm, registerName); + }, + enterInsertMode: function(cm, actionArgs, vim) { + if (cm.getOption('readOnly')) { return; } + vim.insertMode = true; + vim.insertModeRepeat = actionArgs && actionArgs.repeat || 1; + var insertAt = (actionArgs) ? actionArgs.insertAt : null; + if (insertAt == 'eol') { + var cursor = cm.getCursor(); + cursor = Pos(cursor.line, lineLength(cm, cursor.line)); + cm.setCursor(cursor); + } else if (insertAt == 'charAfter') { + cm.setCursor(offsetCursor(cm.getCursor(), 0, 1)); + } else if (insertAt == 'firstNonBlank') { + cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm)); + } else if (insertAt == 'endOfSelectedArea') { + var selectionEnd = cm.getCursor('head'); + var selectionStart = cm.getCursor('anchor'); + if (selectionEnd.line < selectionStart.line) { + selectionEnd = Pos(selectionStart.line, 0); + } + cm.setCursor(selectionEnd); + exitVisualMode(cm); + } + cm.setOption('keyMap', 'vim-insert'); + cm.setOption('disableInput', false); + if (actionArgs && actionArgs.replace) { + // Handle Replace-mode as a special case of insert mode. + cm.toggleOverwrite(true); + cm.setOption('keyMap', 'vim-replace'); + CodeMirror.signal(cm, "vim-mode-change", {mode: "replace"}); + } else { + cm.setOption('keyMap', 'vim-insert'); + CodeMirror.signal(cm, "vim-mode-change", {mode: "insert"}); + } + if (!vimGlobalState.macroModeState.isPlaying) { + // Only record if not replaying. + cm.on('change', onChange); + CodeMirror.on(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown); + } + }, + toggleVisualMode: function(cm, actionArgs, vim) { + var repeat = actionArgs.repeat; + var curStart = cm.getCursor(); + var curEnd; + // TODO: The repeat should actually select number of characters/lines + // equal to the repeat times the size of the previous visual + // operation. + if (!vim.visualMode) { + cm.on('mousedown', exitVisualMode); + vim.visualMode = true; + vim.visualLine = !!actionArgs.linewise; + if (vim.visualLine) { + curStart.ch = 0; + curEnd = clipCursorToContent( + cm, Pos(curStart.line + repeat - 1, lineLength(cm, curStart.line)), + true /** includeLineBreak */); + } else { + curEnd = clipCursorToContent( + cm, Pos(curStart.line, curStart.ch + repeat), + true /** includeLineBreak */); + } + cm.setSelection(curStart, curEnd); + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: vim.visualLine ? "linewise" : ""}); + } else { + curStart = cm.getCursor('anchor'); + curEnd = cm.getCursor('head'); + if (!vim.visualLine && actionArgs.linewise) { + // Shift-V pressed in characterwise visual mode. Switch to linewise + // visual mode instead of exiting visual mode. + vim.visualLine = true; + curStart.ch = cursorIsBefore(curStart, curEnd) ? 0 : + lineLength(cm, curStart.line); + curEnd.ch = cursorIsBefore(curStart, curEnd) ? + lineLength(cm, curEnd.line) : 0; + cm.setSelection(curStart, curEnd); + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: "linewise"}); + } else if (vim.visualLine && !actionArgs.linewise) { + // v pressed in linewise visual mode. Switch to characterwise visual + // mode instead of exiting visual mode. + vim.visualLine = false; + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual"}); + } else { + exitVisualMode(cm); + } + } + updateMark(cm, vim, '<', cursorIsBefore(curStart, curEnd) ? curStart + : curEnd); + updateMark(cm, vim, '>', cursorIsBefore(curStart, curEnd) ? curEnd + : curStart); + }, + reselectLastSelection: function(cm, _actionArgs, vim) { + var lastSelection = vim.lastSelection; + if (lastSelection) { + var curStart = lastSelection.curStartMark.find(); + var curEnd = lastSelection.curEndMark.find(); + cm.setSelection(curStart, curEnd); + if (vim.visualMode) { + updateLastSelection(cm, vim); + var selectionStart = cm.getCursor('anchor'); + var selectionEnd = cm.getCursor('head'); + updateMark(cm, vim, '<', cursorIsBefore(selectionStart, selectionEnd) ? selectionStart + : selectionEnd); + updateMark(cm, vim, '>', cursorIsBefore(selectionStart, selectionEnd) ? selectionEnd + : selectionStart); + } + if (lastSelection.visualLine) { + vim.visualMode = true; + vim.visualLine = true; + } + else { + vim.visualMode = true; + vim.visualLine = false; + } + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: vim.visualLine ? "linewise" : ""}); + } + }, + joinLines: function(cm, actionArgs, vim) { + var curStart, curEnd; + if (vim.visualMode) { + curStart = cm.getCursor('anchor'); + curEnd = cm.getCursor('head'); + curEnd.ch = lineLength(cm, curEnd.line) - 1; + } else { + // Repeat is the number of lines to join. Minimum 2 lines. + var repeat = Math.max(actionArgs.repeat, 2); + curStart = cm.getCursor(); + curEnd = clipCursorToContent(cm, Pos(curStart.line + repeat - 1, + Infinity)); + } + var finalCh = 0; + cm.operation(function() { + for (var i = curStart.line; i < curEnd.line; i++) { + finalCh = lineLength(cm, curStart.line); + var tmp = Pos(curStart.line + 1, + lineLength(cm, curStart.line + 1)); + var text = cm.getRange(curStart, tmp); + text = text.replace(/\n\s*/g, ' '); + cm.replaceRange(text, curStart, tmp); + } + var curFinalPos = Pos(curStart.line, finalCh); + cm.setCursor(curFinalPos); + }); + }, + newLineAndEnterInsertMode: function(cm, actionArgs, vim) { + vim.insertMode = true; + var insertAt = copyCursor(cm.getCursor()); + if (insertAt.line === cm.firstLine() && !actionArgs.after) { + // Special case for inserting newline before start of document. + cm.replaceRange('\n', Pos(cm.firstLine(), 0)); + cm.setCursor(cm.firstLine(), 0); + } else { + insertAt.line = (actionArgs.after) ? insertAt.line : + insertAt.line - 1; + insertAt.ch = lineLength(cm, insertAt.line); + cm.setCursor(insertAt); + var newlineFn = CodeMirror.commands.newlineAndIndentContinueComment || + CodeMirror.commands.newlineAndIndent; + newlineFn(cm); + } + this.enterInsertMode(cm, { repeat: actionArgs.repeat }, vim); + }, + paste: function(cm, actionArgs, vim) { + var cur = copyCursor(cm.getCursor()); + var register = vimGlobalState.registerController.getRegister( + actionArgs.registerName); + var text = register.toString(); + if (!text) { + return; + } + if (actionArgs.matchIndent) { + // length that considers tabs and cm.options.tabSize + var whitespaceLength = function(str) { + var tabs = (str.split("\t").length - 1); + var spaces = (str.split(" ").length - 1); + return tabs * cm.options.tabSize + spaces * 1; + }; + var currentLine = cm.getLine(cm.getCursor().line); + var indent = whitespaceLength(currentLine.match(/^\s*/)[0]); + // chomp last newline b/c don't want it to match /^\s*/gm + var chompedText = text.replace(/\n$/, ''); + var wasChomped = text !== chompedText; + var firstIndent = whitespaceLength(text.match(/^\s*/)[0]); + var text = chompedText.replace(/^\s*/gm, function(wspace) { + var newIndent = indent + (whitespaceLength(wspace) - firstIndent); + if (newIndent < 0) { + return ""; + } + else if (cm.options.indentWithTabs) { + var quotient = Math.floor(newIndent / cm.options.tabSize); + return Array(quotient + 1).join('\t'); + } + else { + return Array(newIndent + 1).join(' '); + } + }); + text += wasChomped ? "\n" : ""; + } + if (actionArgs.repeat > 1) { + var text = Array(actionArgs.repeat + 1).join(text); + } + var linewise = register.linewise; + if (linewise) { + if(vim.visualMode) { + text = vim.visualLine ? text.slice(0, -1) : '\n' + text.slice(0, text.length - 1) + '\n'; + } else if (actionArgs.after) { + // Move the newline at the end to the start instead, and paste just + // before the newline character of the line we are on right now. + text = '\n' + text.slice(0, text.length - 1); + cur.ch = lineLength(cm, cur.line); + } else { + cur.ch = 0; + } + } else { + cur.ch += actionArgs.after ? 1 : 0; + } + var curPosFinal; + var idx; + if (vim.visualMode) { + // save the pasted text for reselection if the need arises + vim.lastPastedText = text; + var lastSelectionCurEnd; + var selectedArea = getSelectedAreaRange(cm, vim); + var selectionStart = selectedArea[0]; + var selectionEnd = selectedArea[1]; + // save the curEnd marker before it get cleared due to cm.replaceRange. + if (vim.lastSelection) lastSelectionCurEnd = vim.lastSelection.curEndMark.find(); + // push the previously selected text to unnamed register + vimGlobalState.registerController.unnamedRegister.setText(cm.getRange(selectionStart, selectionEnd)); + cm.replaceRange(text, selectionStart, selectionEnd); + // restore the the curEnd marker + if(lastSelectionCurEnd) vim.lastSelection.curEndMark = cm.setBookmark(lastSelectionCurEnd); + curPosFinal = cm.posFromIndex(cm.indexFromPos(selectionStart) + text.length - 1); + if(linewise)curPosFinal.ch=0; + } else { + cm.replaceRange(text, cur); + // Now fine tune the cursor to where we want it. + if (linewise && actionArgs.after) { + curPosFinal = Pos( + cur.line + 1, + findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line + 1))); + } else if (linewise && !actionArgs.after) { + curPosFinal = Pos( + cur.line, + findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line))); + } else if (!linewise && actionArgs.after) { + idx = cm.indexFromPos(cur); + curPosFinal = cm.posFromIndex(idx + text.length - 1); + } else { + idx = cm.indexFromPos(cur); + curPosFinal = cm.posFromIndex(idx + text.length); + } + } + cm.setCursor(curPosFinal); + }, + undo: function(cm, actionArgs) { + cm.operation(function() { + repeatFn(cm, CodeMirror.commands.undo, actionArgs.repeat)(); + cm.setCursor(cm.getCursor('anchor')); + }); + }, + redo: function(cm, actionArgs) { + repeatFn(cm, CodeMirror.commands.redo, actionArgs.repeat)(); + }, + setRegister: function(_cm, actionArgs, vim) { + vim.inputState.registerName = actionArgs.selectedCharacter; + }, + setMark: function(cm, actionArgs, vim) { + var markName = actionArgs.selectedCharacter; + updateMark(cm, vim, markName, cm.getCursor()); + }, + replace: function(cm, actionArgs, vim) { + var replaceWith = actionArgs.selectedCharacter; + var curStart = cm.getCursor(); + var replaceTo; + var curEnd; + if (vim.visualMode){ + curStart=cm.getCursor('start'); + curEnd=cm.getCursor('end'); + }else{ + var line = cm.getLine(curStart.line); + replaceTo = curStart.ch + actionArgs.repeat; + if (replaceTo > line.length) { + replaceTo=line.length; + } + curEnd = Pos(curStart.line, replaceTo); + } + if (replaceWith=='\n'){ + if (!vim.visualMode) cm.replaceRange('', curStart, curEnd); + // special case, where vim help says to replace by just one line-break + (CodeMirror.commands.newlineAndIndentContinueComment || CodeMirror.commands.newlineAndIndent)(cm); + }else { + var replaceWithStr=cm.getRange(curStart, curEnd); + //replace all characters in range by selected, but keep linebreaks + replaceWithStr=replaceWithStr.replace(/[^\n]/g,replaceWith); + cm.replaceRange(replaceWithStr, curStart, curEnd); + if (vim.visualMode){ + cm.setCursor(curStart); + exitVisualMode(cm); + }else{ + cm.setCursor(offsetCursor(curEnd, 0, -1)); + } + } + }, + incrementNumberToken: function(cm, actionArgs) { + var cur = cm.getCursor(); + var lineStr = cm.getLine(cur.line); + var re = /-?\d+/g; + var match; + var start; + var end; + var numberStr; + var token; + while ((match = re.exec(lineStr)) !== null) { + token = match[0]; + start = match.index; + end = start + token.length; + if (cur.ch < end)break; + } + if (!actionArgs.backtrack && (end <= cur.ch))return; + if (token) { + var increment = actionArgs.increase ? 1 : -1; + var number = parseInt(token) + (increment * actionArgs.repeat); + var from = Pos(cur.line, start); + var to = Pos(cur.line, end); + numberStr = number.toString(); + cm.replaceRange(numberStr, from, to); + } else { + return; + } + cm.setCursor(Pos(cur.line, start + numberStr.length - 1)); + }, + repeatLastEdit: function(cm, actionArgs, vim) { + var lastEditInputState = vim.lastEditInputState; + if (!lastEditInputState) { return; } + var repeat = actionArgs.repeat; + if (repeat && actionArgs.repeatIsExplicit) { + vim.lastEditInputState.repeatOverride = repeat; + } else { + repeat = vim.lastEditInputState.repeatOverride || repeat; + } + repeatLastEdit(cm, vim, repeat, false /** repeatForInsert */); + }, + changeCase: function(cm, actionArgs, vim) { + var selectedAreaRange = getSelectedAreaRange(cm, vim); + var selectionStart = selectedAreaRange[0]; + var selectionEnd = selectedAreaRange[1]; + // save the curEnd marker to avoid its removal due to cm.replaceRange + var lastSelectionCurEnd = vim.lastSelection.curEndMark.find(); + var toLower = actionArgs.toLower; + var text = cm.getRange(selectionStart, selectionEnd); + cm.replaceRange(toLower ? text.toLowerCase() : text.toUpperCase(), selectionStart, selectionEnd); + // restore the last selection curEnd marker + vim.lastSelection.curEndMark = cm.setBookmark(lastSelectionCurEnd); + cm.setCursor(selectionStart); + } + }; + + /* + * Below are miscellaneous utility functions used by vim.js + */ + + /** + * Clips cursor to ensure that line is within the buffer's range + * If includeLineBreak is true, then allow cur.ch == lineLength. + */ + function clipCursorToContent(cm, cur, includeLineBreak) { + var line = Math.min(Math.max(cm.firstLine(), cur.line), cm.lastLine() ); + var maxCh = lineLength(cm, line) - 1; + maxCh = (includeLineBreak) ? maxCh + 1 : maxCh; + var ch = Math.min(Math.max(0, cur.ch), maxCh); + return Pos(line, ch); + } + function copyArgs(args) { + var ret = {}; + for (var prop in args) { + if (args.hasOwnProperty(prop)) { + ret[prop] = args[prop]; + } + } + return ret; + } + function offsetCursor(cur, offsetLine, offsetCh) { + return Pos(cur.line + offsetLine, cur.ch + offsetCh); + } + function matchKeysPartial(pressed, mapped) { + for (var i = 0; i < pressed.length; i++) { + // 'character' means any character. For mark, register commads, etc. + if (pressed[i] != mapped[i] && mapped[i] != 'character') { + return false; + } + } + return true; + } + function repeatFn(cm, fn, repeat) { + return function() { + for (var i = 0; i < repeat; i++) { + fn(cm); + } + }; + } + function copyCursor(cur) { + return Pos(cur.line, cur.ch); + } + function cursorEqual(cur1, cur2) { + return cur1.ch == cur2.ch && cur1.line == cur2.line; + } + function cursorIsBefore(cur1, cur2) { + if (cur1.line < cur2.line) { + return true; + } + if (cur1.line == cur2.line && cur1.ch < cur2.ch) { + return true; + } + return false; + } + function cusrorIsBetween(cur1, cur2, cur3) { + // returns true if cur2 is between cur1 and cur3. + var cur1before2 = cursorIsBefore(cur1, cur2); + var cur2before3 = cursorIsBefore(cur2, cur3); + return cur1before2 && cur2before3; + } + function lineLength(cm, lineNum) { + return cm.getLine(lineNum).length; + } + function reverse(s){ + return s.split('').reverse().join(''); + } + function trim(s) { + if (s.trim) { + return s.trim(); + } + return s.replace(/^\s+|\s+$/g, ''); + } + function escapeRegex(s) { + return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, '\\$1'); + } + function getSelectedAreaRange(cm, vim) { + var selectionStart = cm.getCursor('anchor'); + var selectionEnd = cm.getCursor('head'); + var lastSelection = vim.lastSelection; + if (!vim.visualMode) { + var lastSelectionCurStart = vim.lastSelection.curStartMark.find(); + var lastSelectionCurEnd = vim.lastSelection.curEndMark.find(); + var line = lastSelectionCurEnd.line - lastSelectionCurStart.line; + var ch = line ? lastSelectionCurEnd.ch : lastSelectionCurEnd.ch - lastSelectionCurStart.ch; + selectionEnd = {line: selectionEnd.line + line, ch: line ? selectionEnd.ch : ch + selectionEnd.ch}; + if (lastSelection.visualLine) { + return [{line: selectionStart.line, ch: 0}, {line: selectionEnd.line, ch: lineLength(cm, selectionEnd.line)}]; + } + } else { + if (cursorIsBefore(selectionEnd, selectionStart)) { + var tmp = selectionStart; + selectionStart = selectionEnd; + selectionEnd = tmp; + } + exitVisualMode(cm); + } + return [selectionStart, selectionEnd]; + } + function updateLastSelection(cm, vim) { + // We need the vim mark '<' to get the selection in case of yank and put + var selectionStart = vim.marks['<'].find() || cm.getCursor('anchor'); + var selectionEnd = vim.marks['>'].find() ||cm.getCursor('head'); + // To accommodate the effect lastPastedText in the last selection + if (vim.lastPastedText) { + selectionEnd = cm.posFromIndex(cm.indexFromPos(selectionStart) + vim.lastPastedText.length-1); + vim.lastPastedText = null; + } + // can't use selection state here because yank has already reset its cursor + // Also, Bookmarks make the visual selections robust to edit operations + vim.lastSelection = {'curStartMark': cm.setBookmark(selectionStart), 'curEndMark': cm.setBookmark(selectionEnd), 'visualMode': vim.visualMode, 'visualLine': vim.visualLine}; + if (cursorIsBefore(selectionEnd, selectionStart)) { + vim.lastSelection.curStartMark = cm.setBookmark(selectionEnd); + vim.lastSelection.curEndMark = cm.setBookmark(selectionStart); + } + } + + function exitVisualMode(cm) { + cm.off('mousedown', exitVisualMode); + var vim = cm.state.vim; + var selectionStart = cm.getCursor('anchor'); + var selectionEnd = cm.getCursor('head'); + updateLastSelection(cm, vim); + vim.visualMode = false; + vim.visualLine = false; + if (!cursorEqual(selectionStart, selectionEnd)) { + // Clear the selection and set the cursor only if the selection has not + // already been cleared. Otherwise we risk moving the cursor somewhere + // it's not supposed to be. + cm.setCursor(clipCursorToContent(cm, selectionEnd)); + } + CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); + if (vim.fakeCursor) { + vim.fakeCursor.clear(); + } + } + + // Remove any trailing newlines from the selection. For + // example, with the caret at the start of the last word on the line, + // 'dw' should word, but not the newline, while 'w' should advance the + // caret to the first character of the next line. + function clipToLine(cm, curStart, curEnd) { + var selection = cm.getRange(curStart, curEnd); + // Only clip if the selection ends with trailing newline + whitespace + if (/\n\s*$/.test(selection)) { + var lines = selection.split('\n'); + // We know this is all whitepsace. + lines.pop(); + + // Cases: + // 1. Last word is an empty line - do not clip the trailing '\n' + // 2. Last word is not an empty line - clip the trailing '\n' + var line; + // Find the line containing the last word, and clip all whitespace up + // to it. + for (var line = lines.pop(); lines.length > 0 && line && isWhiteSpaceString(line); line = lines.pop()) { + curEnd.line--; + curEnd.ch = 0; + } + // If the last word is not an empty line, clip an additional newline + if (line) { + curEnd.line--; + curEnd.ch = lineLength(cm, curEnd.line); + } else { + curEnd.ch = 0; + } + } + } + + // Expand the selection to line ends. + function expandSelectionToLine(_cm, curStart, curEnd) { + curStart.ch = 0; + curEnd.ch = 0; + curEnd.line++; + } + + function findFirstNonWhiteSpaceCharacter(text) { + if (!text) { + return 0; + } + var firstNonWS = text.search(/\S/); + return firstNonWS == -1 ? text.length : firstNonWS; + } + + function expandWordUnderCursor(cm, inclusive, _forward, bigWord, noSymbol) { + var cur = cm.getCursor(); + var line = cm.getLine(cur.line); + var idx = cur.ch; + + // Seek to first word or non-whitespace character, depending on if + // noSymbol is true. + var textAfterIdx = line.substring(idx); + var firstMatchedChar; + if (noSymbol) { + firstMatchedChar = textAfterIdx.search(/\w/); + } else { + firstMatchedChar = textAfterIdx.search(/\S/); + } + if (firstMatchedChar == -1) { + return null; + } + idx += firstMatchedChar; + textAfterIdx = line.substring(idx); + var textBeforeIdx = line.substring(0, idx); + + var matchRegex; + // Greedy matchers for the "word" we are trying to expand. + if (bigWord) { + matchRegex = /^\S+/; + } else { + if ((/\w/).test(line.charAt(idx))) { + matchRegex = /^\w+/; + } else { + matchRegex = /^[^\w\s]+/; + } + } + + var wordAfterRegex = matchRegex.exec(textAfterIdx); + var wordStart = idx; + var wordEnd = idx + wordAfterRegex[0].length; + // TODO: Find a better way to do this. It will be slow on very long lines. + var revTextBeforeIdx = reverse(textBeforeIdx); + var wordBeforeRegex = matchRegex.exec(revTextBeforeIdx); + if (wordBeforeRegex) { + wordStart -= wordBeforeRegex[0].length; + } + + if (inclusive) { + // If present, trim all whitespace after word. + // Otherwise, trim all whitespace before word. + var textAfterWordEnd = line.substring(wordEnd); + var whitespacesAfterWord = textAfterWordEnd.match(/^\s*/)[0].length; + if (whitespacesAfterWord > 0) { + wordEnd += whitespacesAfterWord; + } else { + var revTrim = revTextBeforeIdx.length - wordStart; + var textBeforeWordStart = revTextBeforeIdx.substring(revTrim); + var whitespacesBeforeWord = textBeforeWordStart.match(/^\s*/)[0].length; + wordStart -= whitespacesBeforeWord; + } + } + + return { start: Pos(cur.line, wordStart), + end: Pos(cur.line, wordEnd) }; + } + + function recordJumpPosition(cm, oldCur, newCur) { + if (!cursorEqual(oldCur, newCur)) { + vimGlobalState.jumpList.add(cm, oldCur, newCur); + } + } + + function recordLastCharacterSearch(increment, args) { + vimGlobalState.lastChararacterSearch.increment = increment; + vimGlobalState.lastChararacterSearch.forward = args.forward; + vimGlobalState.lastChararacterSearch.selectedCharacter = args.selectedCharacter; + } + + var symbolToMode = { + '(': 'bracket', ')': 'bracket', '{': 'bracket', '}': 'bracket', + '[': 'section', ']': 'section', + '*': 'comment', '/': 'comment', + 'm': 'method', 'M': 'method', + '#': 'preprocess' + }; + var findSymbolModes = { + bracket: { + isComplete: function(state) { + if (state.nextCh === state.symb) { + state.depth++; + if (state.depth >= 1)return true; + } else if (state.nextCh === state.reverseSymb) { + state.depth--; + } + return false; + } + }, + section: { + init: function(state) { + state.curMoveThrough = true; + state.symb = (state.forward ? ']' : '[') === state.symb ? '{' : '}'; + }, + isComplete: function(state) { + return state.index === 0 && state.nextCh === state.symb; + } + }, + comment: { + isComplete: function(state) { + var found = state.lastCh === '*' && state.nextCh === '/'; + state.lastCh = state.nextCh; + return found; + } + }, + // TODO: The original Vim implementation only operates on level 1 and 2. + // The current implementation doesn't check for code block level and + // therefore it operates on any levels. + method: { + init: function(state) { + state.symb = (state.symb === 'm' ? '{' : '}'); + state.reverseSymb = state.symb === '{' ? '}' : '{'; + }, + isComplete: function(state) { + if (state.nextCh === state.symb)return true; + return false; + } + }, + preprocess: { + init: function(state) { + state.index = 0; + }, + isComplete: function(state) { + if (state.nextCh === '#') { + var token = state.lineText.match(/#(\w+)/)[1]; + if (token === 'endif') { + if (state.forward && state.depth === 0) { + return true; + } + state.depth++; + } else if (token === 'if') { + if (!state.forward && state.depth === 0) { + return true; + } + state.depth--; + } + if (token === 'else' && state.depth === 0)return true; + } + return false; + } + } + }; + function findSymbol(cm, repeat, forward, symb) { + var cur = copyCursor(cm.getCursor()); + var increment = forward ? 1 : -1; + var endLine = forward ? cm.lineCount() : -1; + var curCh = cur.ch; + var line = cur.line; + var lineText = cm.getLine(line); + var state = { + lineText: lineText, + nextCh: lineText.charAt(curCh), + lastCh: null, + index: curCh, + symb: symb, + reverseSymb: (forward ? { ')': '(', '}': '{' } : { '(': ')', '{': '}' })[symb], + forward: forward, + depth: 0, + curMoveThrough: false + }; + var mode = symbolToMode[symb]; + if (!mode)return cur; + var init = findSymbolModes[mode].init; + var isComplete = findSymbolModes[mode].isComplete; + if (init) { init(state); } + while (line !== endLine && repeat) { + state.index += increment; + state.nextCh = state.lineText.charAt(state.index); + if (!state.nextCh) { + line += increment; + state.lineText = cm.getLine(line) || ''; + if (increment > 0) { + state.index = 0; + } else { + var lineLen = state.lineText.length; + state.index = (lineLen > 0) ? (lineLen-1) : 0; + } + state.nextCh = state.lineText.charAt(state.index); + } + if (isComplete(state)) { + cur.line = line; + cur.ch = state.index; + repeat--; + } + } + if (state.nextCh || state.curMoveThrough) { + return Pos(line, state.index); + } + return cur; + } + + /* + * Returns the boundaries of the next word. If the cursor in the middle of + * the word, then returns the boundaries of the current word, starting at + * the cursor. If the cursor is at the start/end of a word, and we are going + * forward/backward, respectively, find the boundaries of the next word. + * + * @param {CodeMirror} cm CodeMirror object. + * @param {Cursor} cur The cursor position. + * @param {boolean} forward True to search forward. False to search + * backward. + * @param {boolean} bigWord True if punctuation count as part of the word. + * False if only [a-zA-Z0-9] characters count as part of the word. + * @param {boolean} emptyLineIsWord True if empty lines should be treated + * as words. + * @return {Object{from:number, to:number, line: number}} The boundaries of + * the word, or null if there are no more words. + */ + function findWord(cm, cur, forward, bigWord, emptyLineIsWord) { + var lineNum = cur.line; + var pos = cur.ch; + var line = cm.getLine(lineNum); + var dir = forward ? 1 : -1; + var regexps = bigWord ? bigWordRegexp : wordRegexp; + + if (emptyLineIsWord && line == '') { + lineNum += dir; + line = cm.getLine(lineNum); + if (!isLine(cm, lineNum)) { + return null; + } + pos = (forward) ? 0 : line.length; + } + + while (true) { + if (emptyLineIsWord && line == '') { + return { from: 0, to: 0, line: lineNum }; + } + var stop = (dir > 0) ? line.length : -1; + var wordStart = stop, wordEnd = stop; + // Find bounds of next word. + while (pos != stop) { + var foundWord = false; + for (var i = 0; i < regexps.length && !foundWord; ++i) { + if (regexps[i].test(line.charAt(pos))) { + wordStart = pos; + // Advance to end of word. + while (pos != stop && regexps[i].test(line.charAt(pos))) { + pos += dir; + } + wordEnd = pos; + foundWord = wordStart != wordEnd; + if (wordStart == cur.ch && lineNum == cur.line && + wordEnd == wordStart + dir) { + // We started at the end of a word. Find the next one. + continue; + } else { + return { + from: Math.min(wordStart, wordEnd + 1), + to: Math.max(wordStart, wordEnd), + line: lineNum }; + } + } + } + if (!foundWord) { + pos += dir; + } + } + // Advance to next/prev line. + lineNum += dir; + if (!isLine(cm, lineNum)) { + return null; + } + line = cm.getLine(lineNum); + pos = (dir > 0) ? 0 : line.length; + } + // Should never get here. + throw new Error('The impossible happened.'); + } + + /** + * @param {CodeMirror} cm CodeMirror object. + * @param {int} repeat Number of words to move past. + * @param {boolean} forward True to search forward. False to search + * backward. + * @param {boolean} wordEnd True to move to end of word. False to move to + * beginning of word. + * @param {boolean} bigWord True if punctuation count as part of the word. + * False if only alphabet characters count as part of the word. + * @return {Cursor} The position the cursor should move to. + */ + function moveToWord(cm, repeat, forward, wordEnd, bigWord) { + var cur = cm.getCursor(); + var curStart = copyCursor(cur); + var words = []; + if (forward && !wordEnd || !forward && wordEnd) { + repeat++; + } + // For 'e', empty lines are not considered words, go figure. + var emptyLineIsWord = !(forward && wordEnd); + for (var i = 0; i < repeat; i++) { + var word = findWord(cm, cur, forward, bigWord, emptyLineIsWord); + if (!word) { + var eodCh = lineLength(cm, cm.lastLine()); + words.push(forward + ? {line: cm.lastLine(), from: eodCh, to: eodCh} + : {line: 0, from: 0, to: 0}); + break; + } + words.push(word); + cur = Pos(word.line, forward ? (word.to - 1) : word.from); + } + var shortCircuit = words.length != repeat; + var firstWord = words[0]; + var lastWord = words.pop(); + if (forward && !wordEnd) { + // w + if (!shortCircuit && (firstWord.from != curStart.ch || firstWord.line != curStart.line)) { + // We did not start in the middle of a word. Discard the extra word at the end. + lastWord = words.pop(); + } + return Pos(lastWord.line, lastWord.from); + } else if (forward && wordEnd) { + return Pos(lastWord.line, lastWord.to - 1); + } else if (!forward && wordEnd) { + // ge + if (!shortCircuit && (firstWord.to != curStart.ch || firstWord.line != curStart.line)) { + // We did not start in the middle of a word. Discard the extra word at the end. + lastWord = words.pop(); + } + return Pos(lastWord.line, lastWord.to); + } else { + // b + return Pos(lastWord.line, lastWord.from); + } + } + + function moveToCharacter(cm, repeat, forward, character) { + var cur = cm.getCursor(); + var start = cur.ch; + var idx; + for (var i = 0; i < repeat; i ++) { + var line = cm.getLine(cur.line); + idx = charIdxInLine(start, line, character, forward, true); + if (idx == -1) { + return null; + } + start = idx; + } + return Pos(cm.getCursor().line, idx); + } + + function moveToColumn(cm, repeat) { + // repeat is always >= 1, so repeat - 1 always corresponds + // to the column we want to go to. + var line = cm.getCursor().line; + return clipCursorToContent(cm, Pos(line, repeat - 1)); + } + + function updateMark(cm, vim, markName, pos) { + if (!inArray(markName, validMarks)) { + return; + } + if (vim.marks[markName]) { + vim.marks[markName].clear(); + } + vim.marks[markName] = cm.setBookmark(pos); + } + + function charIdxInLine(start, line, character, forward, includeChar) { + // Search for char in line. + // motion_options: {forward, includeChar} + // If includeChar = true, include it too. + // If forward = true, search forward, else search backwards. + // If char is not found on this line, do nothing + var idx; + if (forward) { + idx = line.indexOf(character, start + 1); + if (idx != -1 && !includeChar) { + idx -= 1; + } + } else { + idx = line.lastIndexOf(character, start - 1); + if (idx != -1 && !includeChar) { + idx += 1; + } + } + return idx; + } + + // TODO: perhaps this finagling of start and end positions belonds + // in codmirror/replaceRange? + function selectCompanionObject(cm, symb, inclusive) { + var cur = cm.getCursor(), start, end; + + var bracketRegexp = ({ + '(': /[()]/, ')': /[()]/, + '[': /[[\]]/, ']': /[[\]]/, + '{': /[{}]/, '}': /[{}]/})[symb]; + var openSym = ({ + '(': '(', ')': '(', + '[': '[', ']': '[', + '{': '{', '}': '{'})[symb]; + var curChar = cm.getLine(cur.line).charAt(cur.ch); + // Due to the behavior of scanForBracket, we need to add an offset if the + // cursor is on a matching open bracket. + var offset = curChar === openSym ? 1 : 0; + + start = cm.scanForBracket(Pos(cur.line, cur.ch + offset), -1, null, {'bracketRegex': bracketRegexp}); + end = cm.scanForBracket(Pos(cur.line, cur.ch + offset), 1, null, {'bracketRegex': bracketRegexp}); + + if (!start || !end) { + return { start: cur, end: cur }; + } + + start = start.pos; + end = end.pos; + + if ((start.line == end.line && start.ch > end.ch) + || (start.line > end.line)) { + var tmp = start; + start = end; + end = tmp; + } + + if (inclusive) { + end.ch += 1; + } else { + start.ch += 1; + } + + return { start: start, end: end }; + } + + // Takes in a symbol and a cursor and tries to simulate text objects that + // have identical opening and closing symbols + // TODO support across multiple lines + function findBeginningAndEnd(cm, symb, inclusive) { + var cur = copyCursor(cm.getCursor()); + var line = cm.getLine(cur.line); + var chars = line.split(''); + var start, end, i, len; + var firstIndex = chars.indexOf(symb); + + // the decision tree is to always look backwards for the beginning first, + // but if the cursor is in front of the first instance of the symb, + // then move the cursor forward + if (cur.ch < firstIndex) { + cur.ch = firstIndex; + // Why is this line even here??? + // cm.setCursor(cur.line, firstIndex+1); + } + // otherwise if the cursor is currently on the closing symbol + else if (firstIndex < cur.ch && chars[cur.ch] == symb) { + end = cur.ch; // assign end to the current cursor + --cur.ch; // make sure to look backwards + } + + // if we're currently on the symbol, we've got a start + if (chars[cur.ch] == symb && !end) { + start = cur.ch + 1; // assign start to ahead of the cursor + } else { + // go backwards to find the start + for (i = cur.ch; i > -1 && !start; i--) { + if (chars[i] == symb) { + start = i + 1; + } + } + } + + // look forwards for the end symbol + if (start && !end) { + for (i = start, len = chars.length; i < len && !end; i++) { + if (chars[i] == symb) { + end = i; + } + } + } + + // nothing found + if (!start || !end) { + return { start: cur, end: cur }; + } + + // include the symbols + if (inclusive) { + --start; ++end; + } + + return { + start: Pos(cur.line, start), + end: Pos(cur.line, end) + }; + } + + // Search functions + defineOption('pcre', true, 'boolean'); + function SearchState() {} + SearchState.prototype = { + getQuery: function() { + return vimGlobalState.query; + }, + setQuery: function(query) { + vimGlobalState.query = query; + }, + getOverlay: function() { + return this.searchOverlay; + }, + setOverlay: function(overlay) { + this.searchOverlay = overlay; + }, + isReversed: function() { + return vimGlobalState.isReversed; + }, + setReversed: function(reversed) { + vimGlobalState.isReversed = reversed; + } + }; + function getSearchState(cm) { + var vim = cm.state.vim; + return vim.searchState_ || (vim.searchState_ = new SearchState()); + } + function dialog(cm, template, shortText, onClose, options) { + if (cm.openDialog) { + cm.openDialog(template, onClose, { bottom: true, value: options.value, + onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp }); + } + else { + onClose(prompt(shortText, '')); + } + } + function splitBySlash(argString) { + var slashes = findUnescapedSlashes(argString) || []; + if (!slashes.length) return []; + var tokens = []; + // in case of strings like foo/bar + if (slashes[0] !== 0) return; + for (var i = 0; i < slashes.length; i++) { + if (typeof slashes[i] == 'number') + tokens.push(argString.substring(slashes[i] + 1, slashes[i+1])); + } + return tokens; + } + + function findUnescapedSlashes(str) { + var escapeNextChar = false; + var slashes = []; + for (var i = 0; i < str.length; i++) { + var c = str.charAt(i); + if (!escapeNextChar && c == '/') { + slashes.push(i); + } + escapeNextChar = !escapeNextChar && (c == '\\'); + } + return slashes; + } + + // Translates a search string from ex (vim) syntax into javascript form. + function translateRegex(str) { + // When these match, add a '\' if unescaped or remove one if escaped. + var specials = '|(){'; + // Remove, but never add, a '\' for these. + var unescape = '}'; + var escapeNextChar = false; + var out = []; + for (var i = -1; i < str.length; i++) { + var c = str.charAt(i) || ''; + var n = str.charAt(i+1) || ''; + var specialComesNext = (n && specials.indexOf(n) != -1); + if (escapeNextChar) { + if (c !== '\\' || !specialComesNext) { + out.push(c); + } + escapeNextChar = false; + } else { + if (c === '\\') { + escapeNextChar = true; + // Treat the unescape list as special for removing, but not adding '\'. + if (n && unescape.indexOf(n) != -1) { + specialComesNext = true; + } + // Not passing this test means removing a '\'. + if (!specialComesNext || n === '\\') { + out.push(c); + } + } else { + out.push(c); + if (specialComesNext && n !== '\\') { + out.push('\\'); + } + } + } + } + return out.join(''); + } + + // Translates the replace part of a search and replace from ex (vim) syntax into + // javascript form. Similar to translateRegex, but additionally fixes back references + // (translates '\[0..9]' to '$[0..9]') and follows different rules for escaping '$'. + function translateRegexReplace(str) { + var escapeNextChar = false; + var out = []; + for (var i = -1; i < str.length; i++) { + var c = str.charAt(i) || ''; + var n = str.charAt(i+1) || ''; + if (escapeNextChar) { + // At any point in the loop, escapeNextChar is true if the previous + // character was a '\' and was not escaped. + out.push(c); + escapeNextChar = false; + } else { + if (c === '\\') { + escapeNextChar = true; + if ((isNumber(n) || n === '$')) { + out.push('$'); + } else if (n !== '/' && n !== '\\') { + out.push('\\'); + } + } else { + if (c === '$') { + out.push('$'); + } + out.push(c); + if (n === '/') { + out.push('\\'); + } + } + } + } + return out.join(''); + } + + // Unescape \ and / in the replace part, for PCRE mode. + function unescapeRegexReplace(str) { + var stream = new CodeMirror.StringStream(str); + var output = []; + while (!stream.eol()) { + // Search for \. + while (stream.peek() && stream.peek() != '\\') { + output.push(stream.next()); + } + if (stream.match('\\/', true)) { + // \/ => / + output.push('/'); + } else if (stream.match('\\\\', true)) { + // \\ => \ + output.push('\\'); + } else { + // Don't change anything + output.push(stream.next()); + } + } + return output.join(''); + } + + /** + * Extract the regular expression from the query and return a Regexp object. + * Returns null if the query is blank. + * If ignoreCase is passed in, the Regexp object will have the 'i' flag set. + * If smartCase is passed in, and the query contains upper case letters, + * then ignoreCase is overridden, and the 'i' flag will not be set. + * If the query contains the /i in the flag part of the regular expression, + * then both ignoreCase and smartCase are ignored, and 'i' will be passed + * through to the Regex object. + */ + function parseQuery(query, ignoreCase, smartCase) { + // First update the last search register + var lastSearchRegister = vimGlobalState.registerController.getRegister('/'); + lastSearchRegister.setText(query); + // Check if the query is already a regex. + if (query instanceof RegExp) { return query; } + // First try to extract regex + flags from the input. If no flags found, + // extract just the regex. IE does not accept flags directly defined in + // the regex string in the form /regex/flags + var slashes = findUnescapedSlashes(query); + var regexPart; + var forceIgnoreCase; + if (!slashes.length) { + // Query looks like 'regexp' + regexPart = query; + } else { + // Query looks like 'regexp/...' + regexPart = query.substring(0, slashes[0]); + var flagsPart = query.substring(slashes[0]); + forceIgnoreCase = (flagsPart.indexOf('i') != -1); + } + if (!regexPart) { + return null; + } + if (!getOption('pcre')) { + regexPart = translateRegex(regexPart); + } + if (smartCase) { + ignoreCase = (/^[^A-Z]*$/).test(regexPart); + } + var regexp = new RegExp(regexPart, + (ignoreCase || forceIgnoreCase) ? 'i' : undefined); + return regexp; + } + function showConfirm(cm, text) { + if (cm.openNotification) { + cm.openNotification('' + text + '', + {bottom: true, duration: 5000}); + } else { + alert(text); + } + } + function makePrompt(prefix, desc) { + var raw = ''; + if (prefix) { + raw += '' + prefix + ''; + } + raw += ' ' + + ''; + if (desc) { + raw += ''; + raw += desc; + raw += ''; + } + return raw; + } + var searchPromptDesc = '(Javascript regexp)'; + function showPrompt(cm, options) { + var shortText = (options.prefix || '') + ' ' + (options.desc || ''); + var prompt = makePrompt(options.prefix, options.desc); + dialog(cm, prompt, shortText, options.onClose, options); + } + function regexEqual(r1, r2) { + if (r1 instanceof RegExp && r2 instanceof RegExp) { + var props = ['global', 'multiline', 'ignoreCase', 'source']; + for (var i = 0; i < props.length; i++) { + var prop = props[i]; + if (r1[prop] !== r2[prop]) { + return false; + } + } + return true; + } + return false; + } + // Returns true if the query is valid. + function updateSearchQuery(cm, rawQuery, ignoreCase, smartCase) { + if (!rawQuery) { + return; + } + var state = getSearchState(cm); + var query = parseQuery(rawQuery, !!ignoreCase, !!smartCase); + if (!query) { + return; + } + highlightSearchMatches(cm, query); + if (regexEqual(query, state.getQuery())) { + return query; + } + state.setQuery(query); + return query; + } + function searchOverlay(query) { + if (query.source.charAt(0) == '^') { + var matchSol = true; + } + return { + token: function(stream) { + if (matchSol && !stream.sol()) { + stream.skipToEnd(); + return; + } + var match = stream.match(query, false); + if (match) { + if (match[0].length == 0) { + // Matched empty string, skip to next. + stream.next(); + return 'searching'; + } + if (!stream.sol()) { + // Backtrack 1 to match \b + stream.backUp(1); + if (!query.exec(stream.next() + match[0])) { + stream.next(); + return null; + } + } + stream.match(query); + return 'searching'; + } + while (!stream.eol()) { + stream.next(); + if (stream.match(query, false)) break; + } + }, + query: query + }; + } + function highlightSearchMatches(cm, query) { + var overlay = getSearchState(cm).getOverlay(); + if (!overlay || query != overlay.query) { + if (overlay) { + cm.removeOverlay(overlay); + } + overlay = searchOverlay(query); + cm.addOverlay(overlay); + getSearchState(cm).setOverlay(overlay); + } + } + function findNext(cm, prev, query, repeat) { + if (repeat === undefined) { repeat = 1; } + return cm.operation(function() { + var pos = cm.getCursor(); + var cursor = cm.getSearchCursor(query, pos); + for (var i = 0; i < repeat; i++) { + var found = cursor.find(prev); + if (i == 0 && found && cursorEqual(cursor.from(), pos)) { found = cursor.find(prev); } + if (!found) { + // SearchCursor may have returned null because it hit EOF, wrap + // around and try again. + cursor = cm.getSearchCursor(query, + (prev) ? Pos(cm.lastLine()) : Pos(cm.firstLine(), 0) ); + if (!cursor.find(prev)) { + return; + } + } + } + return cursor.from(); + }); + } + function clearSearchHighlight(cm) { + cm.removeOverlay(getSearchState(cm).getOverlay()); + getSearchState(cm).setOverlay(null); + } + /** + * Check if pos is in the specified range, INCLUSIVE. + * Range can be specified with 1 or 2 arguments. + * If the first range argument is an array, treat it as an array of line + * numbers. Match pos against any of the lines. + * If the first range argument is a number, + * if there is only 1 range argument, check if pos has the same line + * number + * if there are 2 range arguments, then check if pos is in between the two + * range arguments. + */ + function isInRange(pos, start, end) { + if (typeof pos != 'number') { + // Assume it is a cursor position. Get the line number. + pos = pos.line; + } + if (start instanceof Array) { + return inArray(pos, start); + } else { + if (end) { + return (pos >= start && pos <= end); + } else { + return pos == start; + } + } + } + function getUserVisibleLines(cm) { + var scrollInfo = cm.getScrollInfo(); + var occludeToleranceTop = 6; + var occludeToleranceBottom = 10; + var from = cm.coordsChar({left:0, top: occludeToleranceTop + scrollInfo.top}, 'local'); + var bottomY = scrollInfo.clientHeight - occludeToleranceBottom + scrollInfo.top; + var to = cm.coordsChar({left:0, top: bottomY}, 'local'); + return {top: from.line, bottom: to.line}; + } + + // Ex command handling + // Care must be taken when adding to the default Ex command map. For any + // pair of commands that have a shared prefix, at least one of their + // shortNames must not match the prefix of the other command. + var defaultExCommandMap = [ + { name: 'map' }, + { name: 'nmap', shortName: 'nm' }, + { name: 'vmap', shortName: 'vm' }, + { name: 'unmap' }, + { name: 'write', shortName: 'w' }, + { name: 'undo', shortName: 'u' }, + { name: 'redo', shortName: 'red' }, + { name: 'set', shortName: 'set' }, + { name: 'sort', shortName: 'sor' }, + { name: 'substitute', shortName: 's', possiblyAsync: true }, + { name: 'nohlsearch', shortName: 'noh' }, + { name: 'delmarks', shortName: 'delm' }, + { name: 'registers', shortName: 'reg', excludeFromCommandHistory: true }, + { name: 'global', shortName: 'g' } + ]; + Vim.ExCommandDispatcher = function() { + this.buildCommandMap_(); + }; + Vim.ExCommandDispatcher.prototype = { + processCommand: function(cm, input, opt_params) { + var vim = cm.state.vim; + var commandHistoryRegister = vimGlobalState.registerController.getRegister(':'); + var previousCommand = commandHistoryRegister.toString(); + if (vim.visualMode) { + exitVisualMode(cm); + } + var inputStream = new CodeMirror.StringStream(input); + // update ": with the latest command whether valid or invalid + commandHistoryRegister.setText(input); + var params = opt_params || {}; + params.input = input; + try { + this.parseInput_(cm, inputStream, params); + } catch(e) { + showConfirm(cm, e); + throw e; + } + var command; + var commandName; + if (!params.commandName) { + // If only a line range is defined, move to the line. + if (params.line !== undefined) { + commandName = 'move'; + } + } else { + command = this.matchCommand_(params.commandName); + if (command) { + commandName = command.name; + if (command.excludeFromCommandHistory) { + commandHistoryRegister.setText(previousCommand); + } + this.parseCommandArgs_(inputStream, params, command); + if (command.type == 'exToKey') { + // Handle Ex to Key mapping. + for (var i = 0; i < command.toKeys.length; i++) { + CodeMirror.Vim.handleKey(cm, command.toKeys[i]); + } + return; + } else if (command.type == 'exToEx') { + // Handle Ex to Ex mapping. + this.processCommand(cm, command.toInput); + return; + } + } + } + if (!commandName) { + showConfirm(cm, 'Not an editor command ":' + input + '"'); + return; + } + try { + exCommands[commandName](cm, params); + // Possibly asynchronous commands (e.g. substitute, which might have a + // user confirmation), are responsible for calling the callback when + // done. All others have it taken care of for them here. + if ((!command || !command.possiblyAsync) && params.callback) { + params.callback(); + } + } catch(e) { + showConfirm(cm, e); + throw e; + } + }, + parseInput_: function(cm, inputStream, result) { + inputStream.eatWhile(':'); + // Parse range. + if (inputStream.eat('%')) { + result.line = cm.firstLine(); + result.lineEnd = cm.lastLine(); + } else { + result.line = this.parseLineSpec_(cm, inputStream); + if (result.line !== undefined && inputStream.eat(',')) { + result.lineEnd = this.parseLineSpec_(cm, inputStream); + } + } + + // Parse command name. + var commandMatch = inputStream.match(/^(\w+)/); + if (commandMatch) { + result.commandName = commandMatch[1]; + } else { + result.commandName = inputStream.match(/.*/)[0]; + } + + return result; + }, + parseLineSpec_: function(cm, inputStream) { + var numberMatch = inputStream.match(/^(\d+)/); + if (numberMatch) { + return parseInt(numberMatch[1], 10) - 1; + } + switch (inputStream.next()) { + case '.': + return cm.getCursor().line; + case '$': + return cm.lastLine(); + case '\'': + var mark = cm.state.vim.marks[inputStream.next()]; + if (mark && mark.find()) { + return mark.find().line; + } + throw new Error('Mark not set'); + default: + inputStream.backUp(1); + return undefined; + } + }, + parseCommandArgs_: function(inputStream, params, command) { + if (inputStream.eol()) { + return; + } + params.argString = inputStream.match(/.*/)[0]; + // Parse command-line arguments + var delim = command.argDelimiter || /\s+/; + var args = trim(params.argString).split(delim); + if (args.length && args[0]) { + params.args = args; + } + }, + matchCommand_: function(commandName) { + // Return the command in the command map that matches the shortest + // prefix of the passed in command name. The match is guaranteed to be + // unambiguous if the defaultExCommandMap's shortNames are set up + // correctly. (see @code{defaultExCommandMap}). + for (var i = commandName.length; i > 0; i--) { + var prefix = commandName.substring(0, i); + if (this.commandMap_[prefix]) { + var command = this.commandMap_[prefix]; + if (command.name.indexOf(commandName) === 0) { + return command; + } + } + } + return null; + }, + buildCommandMap_: function() { + this.commandMap_ = {}; + for (var i = 0; i < defaultExCommandMap.length; i++) { + var command = defaultExCommandMap[i]; + var key = command.shortName || command.name; + this.commandMap_[key] = command; + } + }, + map: function(lhs, rhs, ctx) { + if (lhs != ':' && lhs.charAt(0) == ':') { + if (ctx) { throw Error('Mode not supported for ex mappings'); } + var commandName = lhs.substring(1); + if (rhs != ':' && rhs.charAt(0) == ':') { + // Ex to Ex mapping + this.commandMap_[commandName] = { + name: commandName, + type: 'exToEx', + toInput: rhs.substring(1), + user: true + }; + } else { + // Ex to key mapping + this.commandMap_[commandName] = { + name: commandName, + type: 'exToKey', + toKeys: parseKeyString(rhs), + user: true + }; + } + } else { + if (rhs != ':' && rhs.charAt(0) == ':') { + // Key to Ex mapping. + var mapping = { + keys: parseKeyString(lhs), + type: 'keyToEx', + exArgs: { input: rhs.substring(1) }, + user: true}; + if (ctx) { mapping.context = ctx; } + defaultKeymap.unshift(mapping); + } else { + // Key to key mapping + var mapping = { + keys: parseKeyString(lhs), + type: 'keyToKey', + toKeys: parseKeyString(rhs), + user: true + }; + if (ctx) { mapping.context = ctx; } + defaultKeymap.unshift(mapping); + } + } + }, + unmap: function(lhs, ctx) { + var arrayEquals = function(a, b) { + if (a === b) return true; + if (a == null || b == null) return true; + if (a.length != b.length) return false; + for (var i = 0; i < a.length; i++) { + if (a[i] !== b[i]) return false; + } + return true; + }; + if (lhs != ':' && lhs.charAt(0) == ':') { + // Ex to Ex or Ex to key mapping + if (ctx) { throw Error('Mode not supported for ex mappings'); } + var commandName = lhs.substring(1); + if (this.commandMap_[commandName] && this.commandMap_[commandName].user) { + delete this.commandMap_[commandName]; + return; + } + } else { + // Key to Ex or key to key mapping + var keys = parseKeyString(lhs); + for (var i = 0; i < defaultKeymap.length; i++) { + if (arrayEquals(keys, defaultKeymap[i].keys) + && defaultKeymap[i].context === ctx + && defaultKeymap[i].user) { + defaultKeymap.splice(i, 1); + return; + } + } + } + throw Error('No such mapping.'); + } + }; + + // Converts a key string sequence of the form abd into Vim's + // keymap representation. + function parseKeyString(str) { + var key, match; + var keys = []; + while (str) { + match = (/<\w+-.+?>|<\w+>|./).exec(str); + if (match === null)break; + key = match[0]; + str = str.substring(match.index + key.length); + keys.push(key); + } + return keys; + } + + var exCommands = { + map: function(cm, params, ctx) { + var mapArgs = params.args; + if (!mapArgs || mapArgs.length < 2) { + if (cm) { + showConfirm(cm, 'Invalid mapping: ' + params.input); + } + return; + } + exCommandDispatcher.map(mapArgs[0], mapArgs[1], ctx); + }, + nmap: function(cm, params) { this.map(cm, params, 'normal'); }, + vmap: function(cm, params) { this.map(cm, params, 'visual'); }, + unmap: function(cm, params, ctx) { + var mapArgs = params.args; + if (!mapArgs || mapArgs.length < 1) { + if (cm) { + showConfirm(cm, 'No such mapping: ' + params.input); + } + return; + } + exCommandDispatcher.unmap(mapArgs[0], ctx); + }, + move: function(cm, params) { + commandDispatcher.processCommand(cm, cm.state.vim, { + type: 'motion', + motion: 'moveToLineOrEdgeOfDocument', + motionArgs: { forward: false, explicitRepeat: true, + linewise: true }, + repeatOverride: params.line+1}); + }, + set: function(cm, params) { + var setArgs = params.args; + if (!setArgs || setArgs.length < 1) { + if (cm) { + showConfirm(cm, 'Invalid mapping: ' + params.input); + } + return; + } + var expr = setArgs[0].split('='); + var optionName = expr[0]; + var value = expr[1]; + var forceGet = false; + + if (optionName.charAt(optionName.length - 1) == '?') { + // If post-fixed with ?, then the set is actually a get. + if (value) { throw Error('Trailing characters: ' + params.argString); } + optionName = optionName.substring(0, optionName.length - 1); + forceGet = true; + } + if (value === undefined && optionName.substring(0, 2) == 'no') { + // To set boolean options to false, the option name is prefixed with + // 'no'. + optionName = optionName.substring(2); + value = false; + } + var optionIsBoolean = options[optionName] && options[optionName].type == 'boolean'; + if (optionIsBoolean && value == undefined) { + // Calling set with a boolean option sets it to true. + value = true; + } + if (!optionIsBoolean && !value || forceGet) { + var oldValue = getOption(optionName); + // If no value is provided, then we assume this is a get. + if (oldValue === true || oldValue === false) { + showConfirm(cm, ' ' + (oldValue ? '' : 'no') + optionName); + } else { + showConfirm(cm, ' ' + optionName + '=' + oldValue); + } + } else { + setOption(optionName, value); + } + }, + registers: function(cm,params) { + var regArgs = params.args; + var registers = vimGlobalState.registerController.registers; + var regInfo = '----------Registers----------

'; + if (!regArgs) { + for (var registerName in registers) { + var text = registers[registerName].toString(); + if (text.length) { + regInfo += '"' + registerName + ' ' + text + '
'; + } + } + } else { + var registerName; + regArgs = regArgs.join(''); + for (var i = 0; i < regArgs.length; i++) { + registerName = regArgs.charAt(i); + if (!vimGlobalState.registerController.isValidRegister(registerName)) { + continue; + } + var register = registers[registerName] || new Register(); + regInfo += '"' + registerName + ' ' + register.toString() + '
'; + } + } + showConfirm(cm, regInfo); + }, + sort: function(cm, params) { + var reverse, ignoreCase, unique, number; + function parseArgs() { + if (params.argString) { + var args = new CodeMirror.StringStream(params.argString); + if (args.eat('!')) { reverse = true; } + if (args.eol()) { return; } + if (!args.eatSpace()) { return 'Invalid arguments'; } + var opts = args.match(/[a-z]+/); + if (opts) { + opts = opts[0]; + ignoreCase = opts.indexOf('i') != -1; + unique = opts.indexOf('u') != -1; + var decimal = opts.indexOf('d') != -1 && 1; + var hex = opts.indexOf('x') != -1 && 1; + var octal = opts.indexOf('o') != -1 && 1; + if (decimal + hex + octal > 1) { return 'Invalid arguments'; } + number = decimal && 'decimal' || hex && 'hex' || octal && 'octal'; + } + if (args.eatSpace() && args.match(/\/.*\//)) { 'patterns not supported'; } + } + } + var err = parseArgs(); + if (err) { + showConfirm(cm, err + ': ' + params.argString); + return; + } + var lineStart = params.line || cm.firstLine(); + var lineEnd = params.lineEnd || params.line || cm.lastLine(); + if (lineStart == lineEnd) { return; } + var curStart = Pos(lineStart, 0); + var curEnd = Pos(lineEnd, lineLength(cm, lineEnd)); + var text = cm.getRange(curStart, curEnd).split('\n'); + var numberRegex = (number == 'decimal') ? /(-?)([\d]+)/ : + (number == 'hex') ? /(-?)(?:0x)?([0-9a-f]+)/i : + (number == 'octal') ? /([0-7]+)/ : null; + var radix = (number == 'decimal') ? 10 : (number == 'hex') ? 16 : (number == 'octal') ? 8 : null; + var numPart = [], textPart = []; + if (number) { + for (var i = 0; i < text.length; i++) { + if (numberRegex.exec(text[i])) { + numPart.push(text[i]); + } else { + textPart.push(text[i]); + } + } + } else { + textPart = text; + } + function compareFn(a, b) { + if (reverse) { var tmp; tmp = a; a = b; b = tmp; } + if (ignoreCase) { a = a.toLowerCase(); b = b.toLowerCase(); } + var anum = number && numberRegex.exec(a); + var bnum = number && numberRegex.exec(b); + if (!anum) { return a < b ? -1 : 1; } + anum = parseInt((anum[1] + anum[2]).toLowerCase(), radix); + bnum = parseInt((bnum[1] + bnum[2]).toLowerCase(), radix); + return anum - bnum; + } + numPart.sort(compareFn); + textPart.sort(compareFn); + text = (!reverse) ? textPart.concat(numPart) : numPart.concat(textPart); + if (unique) { // Remove duplicate lines + var textOld = text; + var lastLine; + text = []; + for (var i = 0; i < textOld.length; i++) { + if (textOld[i] != lastLine) { + text.push(textOld[i]); + } + lastLine = textOld[i]; + } + } + cm.replaceRange(text.join('\n'), curStart, curEnd); + }, + global: function(cm, params) { + // a global command is of the form + // :[range]g/pattern/[cmd] + // argString holds the string /pattern/[cmd] + var argString = params.argString; + if (!argString) { + showConfirm(cm, 'Regular Expression missing from global'); + return; + } + // range is specified here + var lineStart = (params.line !== undefined) ? params.line : cm.firstLine(); + var lineEnd = params.lineEnd || params.line || cm.lastLine(); + // get the tokens from argString + var tokens = splitBySlash(argString); + var regexPart = argString, cmd; + if (tokens.length) { + regexPart = tokens[0]; + cmd = tokens.slice(1, tokens.length).join('/'); + } + if (regexPart) { + // If regex part is empty, then use the previous query. Otherwise + // use the regex part as the new query. + try { + updateSearchQuery(cm, regexPart, true /** ignoreCase */, + true /** smartCase */); + } catch (e) { + showConfirm(cm, 'Invalid regex: ' + regexPart); + return; + } + } + // now that we have the regexPart, search for regex matches in the + // specified range of lines + var query = getSearchState(cm).getQuery(); + var matchedLines = [], content = ''; + for (var i = lineStart; i <= lineEnd; i++) { + var matched = query.test(cm.getLine(i)); + if (matched) { + matchedLines.push(i+1); + content+= cm.getLine(i) + '
'; + } + } + // if there is no [cmd], just display the list of matched lines + if (!cmd) { + showConfirm(cm, content); + return; + } + var index = 0; + var nextCommand = function() { + if (index < matchedLines.length) { + var command = matchedLines[index] + cmd; + exCommandDispatcher.processCommand(cm, command, { + callback: nextCommand + }); + } + index++; + }; + nextCommand(); + }, + substitute: function(cm, params) { + if (!cm.getSearchCursor) { + throw new Error('Search feature not available. Requires searchcursor.js or ' + + 'any other getSearchCursor implementation.'); + } + var argString = params.argString; + var tokens = argString ? splitBySlash(argString) : []; + var regexPart, replacePart = '', trailing, flagsPart, count; + var confirm = false; // Whether to confirm each replace. + var global = false; // True to replace all instances on a line, false to replace only 1. + if (tokens.length) { + regexPart = tokens[0]; + replacePart = tokens[1]; + if (replacePart !== undefined) { + if (getOption('pcre')) { + replacePart = unescapeRegexReplace(replacePart); + } else { + replacePart = translateRegexReplace(replacePart); + } + vimGlobalState.lastSubstituteReplacePart = replacePart; + } + trailing = tokens[2] ? tokens[2].split(' ') : []; + } else { + // either the argString is empty or its of the form ' hello/world' + // actually splitBySlash returns a list of tokens + // only if the string starts with a '/' + if (argString && argString.length) { + showConfirm(cm, 'Substitutions should be of the form ' + + ':s/pattern/replace/'); + return; + } + } + // After the 3rd slash, we can have flags followed by a space followed + // by count. + if (trailing) { + flagsPart = trailing[0]; + count = parseInt(trailing[1]); + if (flagsPart) { + if (flagsPart.indexOf('c') != -1) { + confirm = true; + flagsPart.replace('c', ''); + } + if (flagsPart.indexOf('g') != -1) { + global = true; + flagsPart.replace('g', ''); + } + regexPart = regexPart + '/' + flagsPart; + } + } + if (regexPart) { + // If regex part is empty, then use the previous query. Otherwise use + // the regex part as the new query. + try { + updateSearchQuery(cm, regexPart, true /** ignoreCase */, + true /** smartCase */); + } catch (e) { + showConfirm(cm, 'Invalid regex: ' + regexPart); + return; + } + } + replacePart = replacePart || vimGlobalState.lastSubstituteReplacePart; + if (replacePart === undefined) { + showConfirm(cm, 'No previous substitute regular expression'); + return; + } + var state = getSearchState(cm); + var query = state.getQuery(); + var lineStart = (params.line !== undefined) ? params.line : cm.getCursor().line; + var lineEnd = params.lineEnd || lineStart; + if (count) { + lineStart = lineEnd; + lineEnd = lineStart + count - 1; + } + var startPos = clipCursorToContent(cm, Pos(lineStart, 0)); + var cursor = cm.getSearchCursor(query, startPos); + doReplace(cm, confirm, global, lineStart, lineEnd, cursor, query, replacePart, params.callback); + }, + redo: CodeMirror.commands.redo, + undo: CodeMirror.commands.undo, + write: function(cm) { + if (CodeMirror.commands.save) { + // If a save command is defined, call it. + CodeMirror.commands.save(cm); + } else { + // Saves to text area if no save command is defined. + cm.save(); + } + }, + nohlsearch: function(cm) { + clearSearchHighlight(cm); + }, + delmarks: function(cm, params) { + if (!params.argString || !trim(params.argString)) { + showConfirm(cm, 'Argument required'); + return; + } + + var state = cm.state.vim; + var stream = new CodeMirror.StringStream(trim(params.argString)); + while (!stream.eol()) { + stream.eatSpace(); + + // Record the streams position at the beginning of the loop for use + // in error messages. + var count = stream.pos; + + if (!stream.match(/[a-zA-Z]/, false)) { + showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); + return; + } + + var sym = stream.next(); + // Check if this symbol is part of a range + if (stream.match('-', true)) { + // This symbol is part of a range. + + // The range must terminate at an alphabetic character. + if (!stream.match(/[a-zA-Z]/, false)) { + showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); + return; + } + + var startMark = sym; + var finishMark = stream.next(); + // The range must terminate at an alphabetic character which + // shares the same case as the start of the range. + if (isLowerCase(startMark) && isLowerCase(finishMark) || + isUpperCase(startMark) && isUpperCase(finishMark)) { + var start = startMark.charCodeAt(0); + var finish = finishMark.charCodeAt(0); + if (start >= finish) { + showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); + return; + } + + // Because marks are always ASCII values, and we have + // determined that they are the same case, we can use + // their char codes to iterate through the defined range. + for (var j = 0; j <= finish - start; j++) { + var mark = String.fromCharCode(start + j); + delete state.marks[mark]; + } + } else { + showConfirm(cm, 'Invalid argument: ' + startMark + '-'); + return; + } + } else { + // This symbol is a valid mark, and is not part of a range. + delete state.marks[sym]; + } + } + } + }; + + var exCommandDispatcher = new Vim.ExCommandDispatcher(); + + /** + * @param {CodeMirror} cm CodeMirror instance we are in. + * @param {boolean} confirm Whether to confirm each replace. + * @param {Cursor} lineStart Line to start replacing from. + * @param {Cursor} lineEnd Line to stop replacing at. + * @param {RegExp} query Query for performing matches with. + * @param {string} replaceWith Text to replace matches with. May contain $1, + * $2, etc for replacing captured groups using Javascript replace. + * @param {function()} callback A callback for when the replace is done. + */ + function doReplace(cm, confirm, global, lineStart, lineEnd, searchCursor, query, + replaceWith, callback) { + // Set up all the functions. + cm.state.vim.exMode = true; + var done = false; + var lastPos = searchCursor.from(); + function replaceAll() { + cm.operation(function() { + while (!done) { + replace(); + next(); + } + stop(); + }); + } + function replace() { + var text = cm.getRange(searchCursor.from(), searchCursor.to()); + var newText = text.replace(query, replaceWith); + searchCursor.replace(newText); + } + function next() { + var found; + // The below only loops to skip over multiple occurrences on the same + // line when 'global' is not true. + while(found = searchCursor.findNext() && + isInRange(searchCursor.from(), lineStart, lineEnd)) { + if (!global && lastPos && searchCursor.from().line == lastPos.line) { + continue; + } + cm.scrollIntoView(searchCursor.from(), 30); + cm.setSelection(searchCursor.from(), searchCursor.to()); + lastPos = searchCursor.from(); + done = false; + return; + } + done = true; + } + function stop(close) { + if (close) { close(); } + cm.focus(); + if (lastPos) { + cm.setCursor(lastPos); + var vim = cm.state.vim; + vim.exMode = false; + vim.lastHPos = vim.lastHSPos = lastPos.ch; + } + if (callback) { callback(); } + } + function onPromptKeyDown(e, _value, close) { + // Swallow all keys. + CodeMirror.e_stop(e); + var keyName = CodeMirror.keyName(e); + switch (keyName) { + case 'Y': + replace(); next(); break; + case 'N': + next(); break; + case 'A': + // replaceAll contains a call to close of its own. We don't want it + // to fire too early or multiple times. + var savedCallback = callback; + callback = undefined; + cm.operation(replaceAll); + callback = savedCallback; + break; + case 'L': + replace(); + // fall through and exit. + case 'Q': + case 'Esc': + case 'Ctrl-C': + case 'Ctrl-[': + stop(close); + break; + } + if (done) { stop(close); } + } + + // Actually do replace. + next(); + if (done) { + showConfirm(cm, 'No matches for ' + query.source); + return; + } + if (!confirm) { + replaceAll(); + if (callback) { callback(); }; + return; + } + showPrompt(cm, { + prefix: 'replace with ' + replaceWith + ' (y/n/a/q/l)', + onKeyDown: onPromptKeyDown + }); + } + + // Register Vim with CodeMirror + function buildVimKeyMap() { + /** + * Handle the raw key event from CodeMirror. Translate the + * Shift + key modifier to the resulting letter, while preserving other + * modifers. + */ + function cmKeyToVimKey(key, modifier) { + var vimKey = key; + if (isUpperCase(vimKey) && modifier == 'Ctrl') { + vimKey = vimKey.toLowerCase(); + } + if (modifier) { + // Vim will parse modifier+key combination as a single key. + vimKey = modifier.charAt(0) + '-' + vimKey; + } + var specialKey = ({Enter:'CR',Backspace:'BS',Delete:'Del'})[vimKey]; + vimKey = specialKey ? specialKey : vimKey; + vimKey = vimKey.length > 1 ? '<'+ vimKey + '>' : vimKey; + return vimKey; + } + + // Closure to bind CodeMirror, key, modifier. + function keyMapper(vimKey) { + return function(cm) { + CodeMirror.signal(cm, 'vim-keypress', vimKey); + CodeMirror.Vim.handleKey(cm, vimKey); + }; + } + + var cmToVimKeymap = { + 'nofallthrough': true, + 'style': 'fat-cursor' + }; + function bindKeys(keys, modifier) { + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + if (!modifier && key.length == 1) { + // Wrap all keys without modifiers with '' to identify them by their + // key characters instead of key identifiers. + key = "'" + key + "'"; + } + var vimKey = cmKeyToVimKey(keys[i], modifier); + var cmKey = modifier ? modifier + '-' + key : key; + cmToVimKeymap[cmKey] = keyMapper(vimKey); + } + } + bindKeys(upperCaseAlphabet); + bindKeys(lowerCaseAlphabet); + bindKeys(upperCaseAlphabet, 'Ctrl'); + bindKeys(specialSymbols); + bindKeys(specialSymbols, 'Ctrl'); + bindKeys(numbers); + bindKeys(numbers, 'Ctrl'); + bindKeys(specialKeys); + bindKeys(specialKeys, 'Ctrl'); + return cmToVimKeymap; + } + CodeMirror.keyMap.vim = buildVimKeyMap(); + + function exitInsertMode(cm) { + var vim = cm.state.vim; + var macroModeState = vimGlobalState.macroModeState; + var insertModeChangeRegister = vimGlobalState.registerController.getRegister('.'); + var isPlaying = macroModeState.isPlaying; + if (!isPlaying) { + cm.off('change', onChange); + CodeMirror.off(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown); + } + if (!isPlaying && vim.insertModeRepeat > 1) { + // Perform insert mode repeat for commands like 3,a and 3,o. + repeatLastEdit(cm, vim, vim.insertModeRepeat - 1, + true /** repeatForInsert */); + vim.lastEditInputState.repeatOverride = vim.insertModeRepeat; + } + delete vim.insertModeRepeat; + vim.insertMode = false; + cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1); + cm.setOption('keyMap', 'vim'); + cm.setOption('disableInput', true); + cm.toggleOverwrite(false); // exit replace mode if we were in it. + // update the ". register before exiting insert mode + insertModeChangeRegister.setText(macroModeState.lastInsertModeChanges.changes.join('')); + CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); + if (macroModeState.isRecording) { + logInsertModeChange(macroModeState); + } + } + + CodeMirror.keyMap['vim-insert'] = { + // TODO: override navigation keys so that Esc will cancel automatic + // indentation from o, O, i_ + 'Esc': exitInsertMode, + 'Ctrl-[': exitInsertMode, + 'Ctrl-C': exitInsertMode, + 'Ctrl-N': 'autocomplete', + 'Ctrl-P': 'autocomplete', + 'Enter': function(cm) { + var fn = CodeMirror.commands.newlineAndIndentContinueComment || + CodeMirror.commands.newlineAndIndent; + fn(cm); + }, + fallthrough: ['default'] + }; + + CodeMirror.keyMap['vim-replace'] = { + 'Backspace': 'goCharLeft', + fallthrough: ['vim-insert'] + }; + + function executeMacroRegister(cm, vim, macroModeState, registerName) { + var register = vimGlobalState.registerController.getRegister(registerName); + var keyBuffer = register.keyBuffer; + var imc = 0; + macroModeState.isPlaying = true; + macroModeState.replaySearchQueries = register.searchQueries.slice(0); + for (var i = 0; i < keyBuffer.length; i++) { + var text = keyBuffer[i]; + var match, key; + while (text) { + // Pull off one command key, which is either a single character + // or a special sequence wrapped in '<' and '>', e.g. ''. + match = (/<\w+-.+?>|<\w+>|./).exec(text); + key = match[0]; + text = text.substring(match.index + key.length); + CodeMirror.Vim.handleKey(cm, key); + if (vim.insertMode) { + var changes = register.insertModeChanges[imc++].changes; + vimGlobalState.macroModeState.lastInsertModeChanges.changes = + changes; + repeatInsertModeChanges(cm, changes, 1); + exitInsertMode(cm); + } + } + }; + macroModeState.isPlaying = false; + } + + function logKey(macroModeState, key) { + if (macroModeState.isPlaying) { return; } + var registerName = macroModeState.latestRegister; + var register = vimGlobalState.registerController.getRegister(registerName); + if (register) { + register.pushText(key); + } + } + + function logInsertModeChange(macroModeState) { + if (macroModeState.isPlaying) { return; } + var registerName = macroModeState.latestRegister; + var register = vimGlobalState.registerController.getRegister(registerName); + if (register) { + register.pushInsertModeChanges(macroModeState.lastInsertModeChanges); + } + } + + function logSearchQuery(macroModeState, query) { + if (macroModeState.isPlaying) { return; } + var registerName = macroModeState.latestRegister; + var register = vimGlobalState.registerController.getRegister(registerName); + if (register) { + register.pushSearchQuery(query); + } + } + + /** + * Listens for changes made in insert mode. + * Should only be active in insert mode. + */ + function onChange(_cm, changeObj) { + var macroModeState = vimGlobalState.macroModeState; + var lastChange = macroModeState.lastInsertModeChanges; + if (!macroModeState.isPlaying) { + while(changeObj) { + lastChange.expectCursorActivityForChange = true; + if (changeObj.origin == '+input' || changeObj.origin == 'paste' + || changeObj.origin === undefined /* only in testing */) { + var text = changeObj.text.join('\n'); + lastChange.changes.push(text); + } + // Change objects may be chained with next. + changeObj = changeObj.next; + } + } + } + + /** + * Listens for any kind of cursor activity on CodeMirror. + */ + function onCursorActivity(cm) { + var vim = cm.state.vim; + if (vim.insertMode) { + // Tracking cursor activity in insert mode (for macro support). + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isPlaying) { return; } + var lastChange = macroModeState.lastInsertModeChanges; + if (lastChange.expectCursorActivityForChange) { + lastChange.expectCursorActivityForChange = false; + } else { + // Cursor moved outside the context of an edit. Reset the change. + lastChange.changes = []; + } + } else if (cm.doc.history.lastSelOrigin == '*mouse') { + // Reset lastHPos if mouse click was done in normal mode. + vim.lastHPos = cm.doc.getCursor().ch; + if (cm.somethingSelected()) { + // If something is still selected, enter visual mode. + vim.visualMode = true; + } + } + if (vim.visualMode) { + var from, head; + from = head = cm.getCursor('head'); + var anchor = cm.getCursor('anchor'); + var to = Pos(head.line, from.ch + (cursorIsBefore(anchor, head) ? -1 : 1)); + if (cursorIsBefore(to, from)) { + var temp = from; + from = to; + to = temp; + } + if (vim.fakeCursor) { + vim.fakeCursor.clear(); + } + vim.fakeCursor = cm.markText(from, to, {className: 'cm-animate-fat-cursor'}); + } + } + + /** Wrapper for special keys pressed in insert mode */ + function InsertModeKey(keyName) { + this.keyName = keyName; + } + + /** + * Handles raw key down events from the text area. + * - Should only be active in insert mode. + * - For recording deletes in insert mode. + */ + function onKeyEventTargetKeyDown(e) { + var macroModeState = vimGlobalState.macroModeState; + var lastChange = macroModeState.lastInsertModeChanges; + var keyName = CodeMirror.keyName(e); + function onKeyFound() { + lastChange.changes.push(new InsertModeKey(keyName)); + return true; + } + if (keyName.indexOf('Delete') != -1 || keyName.indexOf('Backspace') != -1) { + CodeMirror.lookupKey(keyName, ['vim-insert'], onKeyFound); + } + } + + /** + * Repeats the last edit, which includes exactly 1 command and at most 1 + * insert. Operator and motion commands are read from lastEditInputState, + * while action commands are read from lastEditActionCommand. + * + * If repeatForInsert is true, then the function was called by + * exitInsertMode to repeat the insert mode changes the user just made. The + * corresponding enterInsertMode call was made with a count. + */ + function repeatLastEdit(cm, vim, repeat, repeatForInsert) { + var macroModeState = vimGlobalState.macroModeState; + macroModeState.isPlaying = true; + var isAction = !!vim.lastEditActionCommand; + var cachedInputState = vim.inputState; + function repeatCommand() { + if (isAction) { + commandDispatcher.processAction(cm, vim, vim.lastEditActionCommand); + } else { + commandDispatcher.evalInput(cm, vim); + } + } + function repeatInsert(repeat) { + if (macroModeState.lastInsertModeChanges.changes.length > 0) { + // For some reason, repeat cw in desktop VIM does not repeat + // insert mode changes. Will conform to that behavior. + repeat = !vim.lastEditActionCommand ? 1 : repeat; + var changeObject = macroModeState.lastInsertModeChanges; + // This isn't strictly necessary, but since lastInsertModeChanges is + // supposed to be immutable during replay, this helps catch bugs. + macroModeState.lastInsertModeChanges = {}; + repeatInsertModeChanges(cm, changeObject.changes, repeat); + macroModeState.lastInsertModeChanges = changeObject; + } + } + vim.inputState = vim.lastEditInputState; + if (isAction && vim.lastEditActionCommand.interlaceInsertRepeat) { + // o and O repeat have to be interlaced with insert repeats so that the + // insertions appear on separate lines instead of the last line. + for (var i = 0; i < repeat; i++) { + repeatCommand(); + repeatInsert(1); + } + } else { + if (!repeatForInsert) { + // Hack to get the cursor to end up at the right place. If I is + // repeated in insert mode repeat, cursor will be 1 insert + // change set left of where it should be. + repeatCommand(); + } + repeatInsert(repeat); + } + vim.inputState = cachedInputState; + if (vim.insertMode && !repeatForInsert) { + // Don't exit insert mode twice. If repeatForInsert is set, then we + // were called by an exitInsertMode call lower on the stack. + exitInsertMode(cm); + } + macroModeState.isPlaying = false; + }; + + function repeatInsertModeChanges(cm, changes, repeat) { + function keyHandler(binding) { + if (typeof binding == 'string') { + CodeMirror.commands[binding](cm); + } else { + binding(cm); + } + return true; + } + for (var i = 0; i < repeat; i++) { + for (var j = 0; j < changes.length; j++) { + var change = changes[j]; + if (change instanceof InsertModeKey) { + CodeMirror.lookupKey(change.keyName, ['vim-insert'], keyHandler); + } else { + var cur = cm.getCursor(); + cm.replaceRange(change, cur, cur); + } + } + } + } + + resetVimGlobalState(); + return vimApi; + }; + // Initialize Vim and make it available as an API. + CodeMirror.Vim = Vim(); +}); diff --git a/Upload/admin/jscripts/codemirror/lib/codemirror.css b/Upload/admin/jscripts/codemirror/lib/codemirror.css new file mode 100644 index 0000000..c089777 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/lib/codemirror.css @@ -0,0 +1,301 @@ +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; +} +.CodeMirror-scroll { + /* Set scrolling behaviour here */ + overflow: auto; +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre { + padding: 0 4px; /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} +.CodeMirror-linenumbers {} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +.CodeMirror-guttermarker { color: black; } +.CodeMirror-guttermarker-subtle { color: #999; } + +/* CURSOR */ + +.CodeMirror div.CodeMirror-cursor { + border-left: 1px solid black; +} +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} +.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor { + width: auto; + border: 0; + background: #7e7; +} +.cm-animate-fat-cursor { + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; +} +@-moz-keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} +@-webkit-keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} +@keyframes blink { + 0% { background: #7e7; } + 50% { background: none; } + 100% { background: #7e7; } +} + +/* Can style cursor different in overwrite (non-insert) mode */ +div.CodeMirror-overwrite div.CodeMirror-cursor {} + +.cm-tab { display: inline-block; } + +.CodeMirror-ruler { + border-left: 1px solid #ccc; + position: absolute; +} + +/* DEFAULT THEME */ + +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3 {color: #085;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} + +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} + +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} + +/* Default styles for common addons */ + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} +.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } +.CodeMirror-activeline-background {background: #e8f2ff;} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + line-height: 1; + position: relative; + overflow: hidden; + background: white; + color: black; +} + +.CodeMirror-scroll { + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actuall scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} +.CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; left: 0; top: 0; + padding-bottom: 30px; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + -moz-box-sizing: content-box; + box-sizing: content-box; + padding-bottom: 30px; + margin-bottom: -32px; + display: inline-block; + /* Hack to make IE7 behave */ + *zoom:1; + *display:inline; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; +} + +.CodeMirror-lines { + cursor: text; +} +.CodeMirror pre { + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; +} +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + overflow: auto; +} + +.CodeMirror-widget {} + +.CodeMirror-wrap .CodeMirror-scroll { + overflow-x: hidden; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} +.CodeMirror-measure pre { position: static; } + +.CodeMirror div.CodeMirror-cursor { + position: absolute; + border-right: none; + width: 0; +} + +div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 1; +} +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } +.CodeMirror-crosshair { cursor: crosshair; } + +.cm-searching { + background: #ffa; + background: rgba(255, 255, 0, .4); +} + +/* IE7 hack to prevent it from returning funny offsetTops on the spans */ +.CodeMirror span { *vertical-align: text-bottom; } + +/* Used to force a border model for a node */ +.cm-force-border { padding-right: .1px; } + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} diff --git a/Upload/admin/jscripts/codemirror/lib/codemirror.js b/Upload/admin/jscripts/codemirror/lib/codemirror.js new file mode 100644 index 0000000..bafc9fa --- /dev/null +++ b/Upload/admin/jscripts/codemirror/lib/codemirror.js @@ -0,0 +1,7638 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// This is CodeMirror (http://codemirror.net), a code editor +// implemented in JavaScript on top of the browser's DOM. +// +// You can find some technical background for some of the code below +// at http://marijnhaverbeke.nl/blog/#cm-internals . + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + module.exports = mod(); + else if (typeof define == "function" && define.amd) // AMD + return define([], mod); + else // Plain browser env + this.CodeMirror = mod(); +})(function() { + "use strict"; + + // BROWSER SNIFFING + + // Kludges for bugs and behavior differences that can't be feature + // detected are enabled based on userAgent etc sniffing. + + var gecko = /gecko\/\d/i.test(navigator.userAgent); + // ie_uptoN means Internet Explorer version N or lower + var ie_upto10 = /MSIE \d/.test(navigator.userAgent); + var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent); + var ie = ie_upto10 || ie_11up; + var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]); + var webkit = /WebKit\//.test(navigator.userAgent); + var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); + var chrome = /Chrome\//.test(navigator.userAgent); + var presto = /Opera\//.test(navigator.userAgent); + var safari = /Apple Computer/.test(navigator.vendor); + var khtml = /KHTML\//.test(navigator.userAgent); + var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent); + var phantom = /PhantomJS/.test(navigator.userAgent); + + var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent); + // This is woefully incomplete. Suggestions for alternative methods welcome. + var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent); + var mac = ios || /Mac/.test(navigator.platform); + var windows = /win/i.test(navigator.platform); + + var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/); + if (presto_version) presto_version = Number(presto_version[1]); + if (presto_version && presto_version >= 15) { presto = false; webkit = true; } + // Some browsers use the wrong event properties to signal cmd/ctrl on OS X + var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)); + var captureRightClick = gecko || (ie && ie_version >= 9); + + // Optimize some code when these features are not used. + var sawReadOnlySpans = false, sawCollapsedSpans = false; + + // EDITOR CONSTRUCTOR + + // A CodeMirror instance represents an editor. This is the object + // that user code is usually dealing with. + + function CodeMirror(place, options) { + if (!(this instanceof CodeMirror)) return new CodeMirror(place, options); + + this.options = options = options || {}; + // Determine effective options based on given values and defaults. + copyObj(defaults, options, false); + setGuttersForLineNumbers(options); + + var doc = options.value; + if (typeof doc == "string") doc = new Doc(doc, options.mode); + this.doc = doc; + + var display = this.display = new Display(place, doc); + display.wrapper.CodeMirror = this; + updateGutters(this); + themeChanged(this); + if (options.lineWrapping) + this.display.wrapper.className += " CodeMirror-wrap"; + if (options.autofocus && !mobile) focusInput(this); + + this.state = { + keyMaps: [], // stores maps added by addKeyMap + overlays: [], // highlighting overlays, as added by addOverlay + modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info + overwrite: false, focused: false, + suppressEdits: false, // used to disable editing during key handlers when in readOnly mode + pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in readInput + draggingText: false, + highlight: new Delayed() // stores highlight worker timeout + }; + + // Override magic textarea content restore that IE sometimes does + // on our hidden textarea on reload + if (ie && ie_version < 11) setTimeout(bind(resetInput, this, true), 20); + + registerEventHandlers(this); + ensureGlobalHandlers(); + + var cm = this; + runInOp(this, function() { + cm.curOp.forceUpdate = true; + attachDoc(cm, doc); + + if ((options.autofocus && !mobile) || activeElt() == display.input) + setTimeout(bind(onFocus, cm), 20); + else + onBlur(cm); + + for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) + optionHandlers[opt](cm, options[opt], Init); + for (var i = 0; i < initHooks.length; ++i) initHooks[i](cm); + }); + } + + // DISPLAY CONSTRUCTOR + + // The display handles the DOM integration, both for input reading + // and content drawing. It holds references to DOM nodes and + // display-related state. + + function Display(place, doc) { + var d = this; + + // The semihidden textarea that is focused when the editor is + // focused, and receives input. + var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none"); + // The textarea is kept positioned near the cursor to prevent the + // fact that it'll be scrolled into view on input from scrolling + // our fake cursor out of view. On webkit, when wrap=off, paste is + // very slow. So make the area wide instead. + if (webkit) input.style.width = "1000px"; + else input.setAttribute("wrap", "off"); + // If border: 0; -- iOS fails to open keyboard (issue #1287) + if (ios) input.style.border = "1px solid black"; + input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off"); input.setAttribute("spellcheck", "false"); + + // Wraps and hides input textarea + d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); + // The fake scrollbar elements. + d.scrollbarH = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); + d.scrollbarV = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); + // Covers bottom-right square when both scrollbars are present. + d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); + // Covers bottom of gutter when coverGutterNextToScrollbar is on + // and h scrollbar is present. + d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); + // Will contain the actual code, positioned to cover the viewport. + d.lineDiv = elt("div", null, "CodeMirror-code"); + // Elements are added to these to represent selection and cursors. + d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); + d.cursorDiv = elt("div", null, "CodeMirror-cursors"); + // A visibility: hidden element used to find the size of things. + d.measure = elt("div", null, "CodeMirror-measure"); + // When lines outside of the viewport are measured, they are drawn in this. + d.lineMeasure = elt("div", null, "CodeMirror-measure"); + // Wraps everything that needs to exist inside the vertically-padded coordinate system + d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], + null, "position: relative; outline: none"); + // Moved around its parent to cover visible view. + d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative"); + // Set to the height of the document, allowing scrolling. + d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); + // Behavior of elts with overflow: auto and padding is + // inconsistent across browsers. This is used to ensure the + // scrollable area is big enough. + d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerCutOff + "px; width: 1px;"); + // Will contain the gutters, if any. + d.gutters = elt("div", null, "CodeMirror-gutters"); + d.lineGutter = null; + // Actual scrollable element. + d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); + d.scroller.setAttribute("tabIndex", "-1"); + // The element in which the editor lives. + d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV, + d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); + + // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) + if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } + // Needed to hide big blue blinking cursor on Mobile Safari + if (ios) input.style.width = "0px"; + if (!webkit) d.scroller.draggable = true; + // Needed to handle Tab key in KHTML + if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "absolute"; } + // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). + if (ie && ie_version < 8) d.scrollbarH.style.minHeight = d.scrollbarV.style.minWidth = "18px"; + + if (place.appendChild) place.appendChild(d.wrapper); + else place(d.wrapper); + + // Current rendered range (may be bigger than the view window). + d.viewFrom = d.viewTo = doc.first; + // Information about the rendered lines. + d.view = []; + // Holds info about a single rendered line when it was rendered + // for measurement, while not in view. + d.externalMeasured = null; + // Empty space (in pixels) above the view + d.viewOffset = 0; + d.lastSizeC = 0; + d.updateLineNumbers = null; + + // Used to only resize the line number gutter when necessary (when + // the amount of lines crosses a boundary that makes its width change) + d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; + // See readInput and resetInput + d.prevInput = ""; + // Set to true when a non-horizontal-scrolling line widget is + // added. As an optimization, line widget aligning is skipped when + // this is false. + d.alignWidgets = false; + // Flag that indicates whether we expect input to appear real soon + // now (after some event like 'keypress' or 'input') and are + // polling intensively. + d.pollingFast = false; + // Self-resetting timeout for the poller + d.poll = new Delayed(); + + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + + // Tracks when resetInput has punted to just putting a short + // string into the textarea instead of the full selection. + d.inaccurateSelection = false; + + // Tracks the maximum line length so that the horizontal scrollbar + // can be kept static when scrolling. + d.maxLine = null; + d.maxLineLength = 0; + d.maxLineChanged = false; + + // Used for measuring wheel scrolling granularity + d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; + + // True when shift is held down. + d.shift = false; + + // Used to track whether anything happened since the context menu + // was opened. + d.selForContextMenu = null; + } + + // STATE UPDATES + + // Used to get the editor into a consistent state again when options change. + + function loadMode(cm) { + cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); + resetModeState(cm); + } + + function resetModeState(cm) { + cm.doc.iter(function(line) { + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + }); + cm.doc.frontier = cm.doc.first; + startWorker(cm, 100); + cm.state.modeGen++; + if (cm.curOp) regChange(cm); + } + + function wrappingChanged(cm) { + if (cm.options.lineWrapping) { + addClass(cm.display.wrapper, "CodeMirror-wrap"); + cm.display.sizer.style.minWidth = ""; + } else { + rmClass(cm.display.wrapper, "CodeMirror-wrap"); + findMaxLine(cm); + } + estimateLineHeights(cm); + regChange(cm); + clearCaches(cm); + setTimeout(function(){updateScrollbars(cm);}, 100); + } + + // Returns a function that estimates the height of a line, to use as + // first approximation until the line becomes visible (and is thus + // properly measurable). + function estimateHeight(cm) { + var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; + var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); + return function(line) { + if (lineIsHidden(cm.doc, line)) return 0; + + var widgetsHeight = 0; + if (line.widgets) for (var i = 0; i < line.widgets.length; i++) { + if (line.widgets[i].height) widgetsHeight += line.widgets[i].height; + } + + if (wrapping) + return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th; + else + return widgetsHeight + th; + }; + } + + function estimateLineHeights(cm) { + var doc = cm.doc, est = estimateHeight(cm); + doc.iter(function(line) { + var estHeight = est(line); + if (estHeight != line.height) updateLineHeight(line, estHeight); + }); + } + + function keyMapChanged(cm) { + var map = keyMap[cm.options.keyMap], style = map.style; + cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") + + (style ? " cm-keymap-" + style : ""); + } + + function themeChanged(cm) { + cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + + cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); + clearCaches(cm); + } + + function guttersChanged(cm) { + updateGutters(cm); + regChange(cm); + setTimeout(function(){alignHorizontally(cm);}, 20); + } + + // Rebuild the gutter elements, ensure the margin to the left of the + // code matches their width. + function updateGutters(cm) { + var gutters = cm.display.gutters, specs = cm.options.gutters; + removeChildren(gutters); + for (var i = 0; i < specs.length; ++i) { + var gutterClass = specs[i]; + var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)); + if (gutterClass == "CodeMirror-linenumbers") { + cm.display.lineGutter = gElt; + gElt.style.width = (cm.display.lineNumWidth || 1) + "px"; + } + } + gutters.style.display = i ? "" : "none"; + updateGutterSpace(cm); + } + + function updateGutterSpace(cm) { + var width = cm.display.gutters.offsetWidth; + cm.display.sizer.style.marginLeft = width + "px"; + cm.display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0; + } + + // Compute the character length of a line, taking into account + // collapsed ranges (see markText) that might hide parts, and join + // other lines onto it. + function lineLength(line) { + if (line.height == 0) return 0; + var len = line.text.length, merged, cur = line; + while (merged = collapsedSpanAtStart(cur)) { + var found = merged.find(0, true); + cur = found.from.line; + len += found.from.ch - found.to.ch; + } + cur = line; + while (merged = collapsedSpanAtEnd(cur)) { + var found = merged.find(0, true); + len -= cur.text.length - found.from.ch; + cur = found.to.line; + len += cur.text.length - found.to.ch; + } + return len; + } + + // Find the longest line in the document. + function findMaxLine(cm) { + var d = cm.display, doc = cm.doc; + d.maxLine = getLine(doc, doc.first); + d.maxLineLength = lineLength(d.maxLine); + d.maxLineChanged = true; + doc.iter(function(line) { + var len = lineLength(line); + if (len > d.maxLineLength) { + d.maxLineLength = len; + d.maxLine = line; + } + }); + } + + // Make sure the gutters options contains the element + // "CodeMirror-linenumbers" when the lineNumbers option is true. + function setGuttersForLineNumbers(options) { + var found = indexOf(options.gutters, "CodeMirror-linenumbers"); + if (found == -1 && options.lineNumbers) { + options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); + } else if (found > -1 && !options.lineNumbers) { + options.gutters = options.gutters.slice(0); + options.gutters.splice(found, 1); + } + } + + // SCROLLBARS + + function hScrollbarTakesSpace(cm) { + return cm.display.scroller.clientHeight - cm.display.wrapper.clientHeight < scrollerCutOff - 3; + } + + // Prepare DOM reads needed to update the scrollbars. Done in one + // shot to minimize update/measure roundtrips. + function measureForScrollbars(cm) { + var scroll = cm.display.scroller; + return { + clientHeight: scroll.clientHeight, + barHeight: cm.display.scrollbarV.clientHeight, + scrollWidth: scroll.scrollWidth, clientWidth: scroll.clientWidth, + hScrollbarTakesSpace: hScrollbarTakesSpace(cm), + barWidth: cm.display.scrollbarH.clientWidth, + docHeight: Math.round(cm.doc.height + paddingVert(cm.display)) + }; + } + + // Re-synchronize the fake scrollbars with the actual size of the + // content. + function updateScrollbars(cm, measure) { + if (!measure) measure = measureForScrollbars(cm); + var d = cm.display, sWidth = scrollbarWidth(d.measure); + var scrollHeight = measure.docHeight + scrollerCutOff; + var needsH = measure.scrollWidth > measure.clientWidth; + if (needsH && measure.scrollWidth <= measure.clientWidth + 1 && + sWidth > 0 && !measure.hScrollbarTakesSpace) + needsH = false; // (Issue #2562) + var needsV = scrollHeight > measure.clientHeight; + + if (needsV) { + d.scrollbarV.style.display = "block"; + d.scrollbarV.style.bottom = needsH ? sWidth + "px" : "0"; + // A bug in IE8 can cause this value to be negative, so guard it. + d.scrollbarV.firstChild.style.height = + Math.max(0, scrollHeight - measure.clientHeight + (measure.barHeight || d.scrollbarV.clientHeight)) + "px"; + } else { + d.scrollbarV.style.display = ""; + d.scrollbarV.firstChild.style.height = "0"; + } + if (needsH) { + d.scrollbarH.style.display = "block"; + d.scrollbarH.style.right = needsV ? sWidth + "px" : "0"; + d.scrollbarH.firstChild.style.width = + (measure.scrollWidth - measure.clientWidth + (measure.barWidth || d.scrollbarH.clientWidth)) + "px"; + } else { + d.scrollbarH.style.display = ""; + d.scrollbarH.firstChild.style.width = "0"; + } + if (needsH && needsV) { + d.scrollbarFiller.style.display = "block"; + d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = sWidth + "px"; + } else d.scrollbarFiller.style.display = ""; + if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { + d.gutterFiller.style.display = "block"; + d.gutterFiller.style.height = sWidth + "px"; + d.gutterFiller.style.width = d.gutters.offsetWidth + "px"; + } else d.gutterFiller.style.display = ""; + + if (!cm.state.checkedOverlayScrollbar && measure.clientHeight > 0) { + if (sWidth === 0) { + var w = mac && !mac_geMountainLion ? "12px" : "18px"; + d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = w; + var barMouseDown = function(e) { + if (e_target(e) != d.scrollbarV && e_target(e) != d.scrollbarH) + operation(cm, onMouseDown)(e); + }; + on(d.scrollbarV, "mousedown", barMouseDown); + on(d.scrollbarH, "mousedown", barMouseDown); + } + cm.state.checkedOverlayScrollbar = true; + } + } + + // Compute the lines that are visible in a given viewport (defaults + // the the current scroll position). viewPort may contain top, + // height, and ensure (see op.scrollToPos) properties. + function visibleLines(display, doc, viewPort) { + var top = viewPort && viewPort.top != null ? Math.max(0, viewPort.top) : display.scroller.scrollTop; + top = Math.floor(top - paddingTop(display)); + var bottom = viewPort && viewPort.bottom != null ? viewPort.bottom : top + display.wrapper.clientHeight; + + var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); + // Ensure is a {from: {line, ch}, to: {line, ch}} object, and + // forces those lines into the viewport (if possible). + if (viewPort && viewPort.ensure) { + var ensureFrom = viewPort.ensure.from.line, ensureTo = viewPort.ensure.to.line; + if (ensureFrom < from) + return {from: ensureFrom, + to: lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight)}; + if (Math.min(ensureTo, doc.lastLine()) >= to) + return {from: lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight), + to: ensureTo}; + } + return {from: from, to: Math.max(to, from + 1)}; + } + + // LINE NUMBERS + + // Re-align line numbers and gutter marks to compensate for + // horizontal scrolling. + function alignHorizontally(cm) { + var display = cm.display, view = display.view; + if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; + var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; + var gutterW = display.gutters.offsetWidth, left = comp + "px"; + for (var i = 0; i < view.length; i++) if (!view[i].hidden) { + if (cm.options.fixedGutter && view[i].gutter) + view[i].gutter.style.left = left; + var align = view[i].alignable; + if (align) for (var j = 0; j < align.length; j++) + align[j].style.left = left; + } + if (cm.options.fixedGutter) + display.gutters.style.left = (comp + gutterW) + "px"; + } + + // Used to ensure that the line number gutter is still the right + // size for the current document size. Returns true when an update + // is needed. + function maybeUpdateLineNumberWidth(cm) { + if (!cm.options.lineNumbers) return false; + var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; + if (last.length != display.lineNumChars) { + var test = display.measure.appendChild(elt("div", [elt("div", last)], + "CodeMirror-linenumber CodeMirror-gutter-elt")); + var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; + display.lineGutter.style.width = ""; + display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding); + display.lineNumWidth = display.lineNumInnerWidth + padding; + display.lineNumChars = display.lineNumInnerWidth ? last.length : -1; + display.lineGutter.style.width = display.lineNumWidth + "px"; + updateGutterSpace(cm); + return true; + } + return false; + } + + function lineNumberFor(options, i) { + return String(options.lineNumberFormatter(i + options.firstLineNumber)); + } + + // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, + // but using getBoundingClientRect to get a sub-pixel-accurate + // result. + function compensateForHScroll(display) { + return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left; + } + + // DISPLAY DRAWING + + // Updates the display, selection, and scrollbars, using the + // information in display.view to find out which nodes are no longer + // up-to-date. Tries to bail out early when no changes are needed, + // unless forced is true. + // Returns true if an actual update happened, false otherwise. + function updateDisplay(cm, viewPort, forced) { + var oldFrom = cm.display.viewFrom, oldTo = cm.display.viewTo, updated; + var visible = visibleLines(cm.display, cm.doc, viewPort); + for (var first = true;; first = false) { + var oldWidth = cm.display.scroller.clientWidth; + if (!updateDisplayInner(cm, visible, forced)) break; + updated = true; + + // If the max line changed since it was last measured, measure it, + // and ensure the document's width matches it. + if (cm.display.maxLineChanged && !cm.options.lineWrapping) + adjustContentWidth(cm); + + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + setDocumentHeight(cm, barMeasure); + updateScrollbars(cm, barMeasure); + if (webkit && cm.options.lineWrapping) + checkForWebkitWidthBug(cm, barMeasure); // (Issue #2420) + if (webkit && barMeasure.scrollWidth > barMeasure.clientWidth && + barMeasure.scrollWidth < barMeasure.clientWidth + 1 && + !hScrollbarTakesSpace(cm)) + updateScrollbars(cm); // (Issue #2562) + if (first && cm.options.lineWrapping && oldWidth != cm.display.scroller.clientWidth) { + forced = true; + continue; + } + forced = false; + + // Clip forced viewport to actual scrollable area. + if (viewPort && viewPort.top != null) + viewPort = {top: Math.min(barMeasure.docHeight - scrollerCutOff - barMeasure.clientHeight, viewPort.top)}; + // Updated line heights might result in the drawn area not + // actually covering the viewport. Keep looping until it does. + visible = visibleLines(cm.display, cm.doc, viewPort); + if (visible.from >= cm.display.viewFrom && visible.to <= cm.display.viewTo) + break; + } + + cm.display.updateLineNumbers = null; + if (updated) { + signalLater(cm, "update", cm); + if (cm.display.viewFrom != oldFrom || cm.display.viewTo != oldTo) + signalLater(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); + } + return updated; + } + + // Does the actual updating of the line display. Bails out + // (returning false) when there is nothing to be done and forced is + // false. + function updateDisplayInner(cm, visible, forced) { + var display = cm.display, doc = cm.doc; + if (!display.wrapper.offsetWidth) { + resetView(cm); + return; + } + + // Bail out if the visible area is already rendered and nothing changed. + if (!forced && visible.from >= display.viewFrom && visible.to <= display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && + countDirtyView(cm) == 0) + return; + + if (maybeUpdateLineNumberWidth(cm)) + resetView(cm); + var dims = getDimensions(cm); + + // Compute a suitable new viewport (from & to) + var end = doc.first + doc.size; + var from = Math.max(visible.from - cm.options.viewportMargin, doc.first); + var to = Math.min(end, visible.to + cm.options.viewportMargin); + if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom); + if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo); + if (sawCollapsedSpans) { + from = visualLineNo(cm.doc, from); + to = visualLineEndNo(cm.doc, to); + } + + var different = from != display.viewFrom || to != display.viewTo || + display.lastSizeC != display.wrapper.clientHeight; + adjustView(cm, from, to); + + display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); + // Position the mover div to align with the current scroll position + cm.display.mover.style.top = display.viewOffset + "px"; + + var toUpdate = countDirtyView(cm); + if (!different && toUpdate == 0 && !forced) return; + + // For big changes, we hide the enclosing element during the + // update, since that speeds up the operations on most browsers. + var focused = activeElt(); + if (toUpdate > 4) display.lineDiv.style.display = "none"; + patchDisplay(cm, display.updateLineNumbers, dims); + if (toUpdate > 4) display.lineDiv.style.display = ""; + // There might have been a widget with a focused element that got + // hidden or updated, if so re-focus it. + if (focused && activeElt() != focused && focused.offsetHeight) focused.focus(); + + // Prevent selection and cursors from interfering with the scroll + // width. + removeChildren(display.cursorDiv); + removeChildren(display.selectionDiv); + + if (different) { + display.lastSizeC = display.wrapper.clientHeight; + startWorker(cm, 400); + } + + updateHeightsInViewport(cm); + + return true; + } + + function adjustContentWidth(cm) { + var display = cm.display; + var width = measureChar(cm, display.maxLine, display.maxLine.text.length).left; + display.maxLineChanged = false; + var minWidth = Math.max(0, width + 3); + var maxScrollLeft = Math.max(0, display.sizer.offsetLeft + minWidth + scrollerCutOff - display.scroller.clientWidth); + display.sizer.style.minWidth = minWidth + "px"; + if (maxScrollLeft < cm.doc.scrollLeft) + setScrollLeft(cm, Math.min(display.scroller.scrollLeft, maxScrollLeft), true); + } + + function setDocumentHeight(cm, measure) { + cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = measure.docHeight + "px"; + cm.display.gutters.style.height = Math.max(measure.docHeight, measure.clientHeight - scrollerCutOff) + "px"; + } + + function checkForWebkitWidthBug(cm, measure) { + // Work around Webkit bug where it sometimes reserves space for a + // non-existing phantom scrollbar in the scroller (Issue #2420) + if (cm.display.sizer.offsetWidth + cm.display.gutters.offsetWidth < cm.display.scroller.clientWidth - 1) { + cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = "0px"; + cm.display.gutters.style.height = measure.docHeight + "px"; + } + } + + // Read the actual heights of the rendered lines, and update their + // stored heights to match. + function updateHeightsInViewport(cm) { + var display = cm.display; + var prevBottom = display.lineDiv.offsetTop; + for (var i = 0; i < display.view.length; i++) { + var cur = display.view[i], height; + if (cur.hidden) continue; + if (ie && ie_version < 8) { + var bot = cur.node.offsetTop + cur.node.offsetHeight; + height = bot - prevBottom; + prevBottom = bot; + } else { + var box = cur.node.getBoundingClientRect(); + height = box.bottom - box.top; + } + var diff = cur.line.height - height; + if (height < 2) height = textHeight(display); + if (diff > .001 || diff < -.001) { + updateLineHeight(cur.line, height); + updateWidgetHeight(cur.line); + if (cur.rest) for (var j = 0; j < cur.rest.length; j++) + updateWidgetHeight(cur.rest[j]); + } + } + } + + // Read and store the height of line widgets associated with the + // given line. + function updateWidgetHeight(line) { + if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) + line.widgets[i].height = line.widgets[i].node.offsetHeight; + } + + // Do a bulk-read of the DOM positions and sizes needed to draw the + // view, so that we don't interleave reading and writing to the DOM. + function getDimensions(cm) { + var d = cm.display, left = {}, width = {}; + for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { + left[cm.options.gutters[i]] = n.offsetLeft; + width[cm.options.gutters[i]] = n.offsetWidth; + } + return {fixedPos: compensateForHScroll(d), + gutterTotalWidth: d.gutters.offsetWidth, + gutterLeft: left, + gutterWidth: width, + wrapperWidth: d.wrapper.clientWidth}; + } + + // Sync the actual display DOM structure with display.view, removing + // nodes for lines that are no longer in view, and creating the ones + // that are not there yet, and updating the ones that are out of + // date. + function patchDisplay(cm, updateNumbersFrom, dims) { + var display = cm.display, lineNumbers = cm.options.lineNumbers; + var container = display.lineDiv, cur = container.firstChild; + + function rm(node) { + var next = node.nextSibling; + // Works around a throw-scroll bug in OS X Webkit + if (webkit && mac && cm.display.currentWheelTarget == node) + node.style.display = "none"; + else + node.parentNode.removeChild(node); + return next; + } + + var view = display.view, lineN = display.viewFrom; + // Loop over the elements in the view, syncing cur (the DOM nodes + // in display.lineDiv) with the view as we go. + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (lineView.hidden) { + } else if (!lineView.node) { // Not drawn yet + var node = buildLineElement(cm, lineView, lineN, dims); + container.insertBefore(node, cur); + } else { // Already drawn + while (cur != lineView.node) cur = rm(cur); + var updateNumber = lineNumbers && updateNumbersFrom != null && + updateNumbersFrom <= lineN && lineView.lineNumber; + if (lineView.changes) { + if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false; + updateLineForChanges(cm, lineView, lineN, dims); + } + if (updateNumber) { + removeChildren(lineView.lineNumber); + lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))); + } + cur = lineView.node.nextSibling; + } + lineN += lineView.size; + } + while (cur) cur = rm(cur); + } + + // When an aspect of a line changes, a string is added to + // lineView.changes. This updates the relevant part of the line's + // DOM structure. + function updateLineForChanges(cm, lineView, lineN, dims) { + for (var j = 0; j < lineView.changes.length; j++) { + var type = lineView.changes[j]; + if (type == "text") updateLineText(cm, lineView); + else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims); + else if (type == "class") updateLineClasses(lineView); + else if (type == "widget") updateLineWidgets(lineView, dims); + } + lineView.changes = null; + } + + // Lines with gutter elements, widgets or a background class need to + // be wrapped, and have the extra elements added to the wrapper div + function ensureLineWrapped(lineView) { + if (lineView.node == lineView.text) { + lineView.node = elt("div", null, null, "position: relative"); + if (lineView.text.parentNode) + lineView.text.parentNode.replaceChild(lineView.node, lineView.text); + lineView.node.appendChild(lineView.text); + if (ie && ie_version < 8) lineView.node.style.zIndex = 2; + } + return lineView.node; + } + + function updateLineBackground(lineView) { + var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; + if (cls) cls += " CodeMirror-linebackground"; + if (lineView.background) { + if (cls) lineView.background.className = cls; + else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; } + } else if (cls) { + var wrap = ensureLineWrapped(lineView); + lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild); + } + } + + // Wrapper around buildLineContent which will reuse the structure + // in display.externalMeasured when possible. + function getLineContent(cm, lineView) { + var ext = cm.display.externalMeasured; + if (ext && ext.line == lineView.line) { + cm.display.externalMeasured = null; + lineView.measure = ext.measure; + return ext.built; + } + return buildLineContent(cm, lineView); + } + + // Redraw the line's text. Interacts with the background and text + // classes because the mode may output tokens that influence these + // classes. + function updateLineText(cm, lineView) { + var cls = lineView.text.className; + var built = getLineContent(cm, lineView); + if (lineView.text == lineView.node) lineView.node = built.pre; + lineView.text.parentNode.replaceChild(built.pre, lineView.text); + lineView.text = built.pre; + if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { + lineView.bgClass = built.bgClass; + lineView.textClass = built.textClass; + updateLineClasses(lineView); + } else if (cls) { + lineView.text.className = cls; + } + } + + function updateLineClasses(lineView) { + updateLineBackground(lineView); + if (lineView.line.wrapClass) + ensureLineWrapped(lineView).className = lineView.line.wrapClass; + else if (lineView.node != lineView.text) + lineView.node.className = ""; + var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass; + lineView.text.className = textClass || ""; + } + + function updateLineGutter(cm, lineView, lineN, dims) { + if (lineView.gutter) { + lineView.node.removeChild(lineView.gutter); + lineView.gutter = null; + } + var markers = lineView.line.gutterMarkers; + if (cm.options.lineNumbers || markers) { + var wrap = ensureLineWrapped(lineView); + var gutterWrap = lineView.gutter = + wrap.insertBefore(elt("div", null, "CodeMirror-gutter-wrapper", "position: absolute; left: " + + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"), + lineView.text); + if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) + lineView.lineNumber = gutterWrap.appendChild( + elt("div", lineNumberFor(cm.options, lineN), + "CodeMirror-linenumber CodeMirror-gutter-elt", + "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " + + cm.display.lineNumInnerWidth + "px")); + if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) { + var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]; + if (found) + gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + + dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px")); + } + } + } + + function updateLineWidgets(lineView, dims) { + if (lineView.alignable) lineView.alignable = null; + for (var node = lineView.node.firstChild, next; node; node = next) { + var next = node.nextSibling; + if (node.className == "CodeMirror-linewidget") + lineView.node.removeChild(node); + } + insertLineWidgets(lineView, dims); + } + + // Build a line's DOM representation from scratch + function buildLineElement(cm, lineView, lineN, dims) { + var built = getLineContent(cm, lineView); + lineView.text = lineView.node = built.pre; + if (built.bgClass) lineView.bgClass = built.bgClass; + if (built.textClass) lineView.textClass = built.textClass; + + updateLineClasses(lineView); + updateLineGutter(cm, lineView, lineN, dims); + insertLineWidgets(lineView, dims); + return lineView.node; + } + + // A lineView may contain multiple logical lines (when merged by + // collapsed spans). The widgets for all of them need to be drawn. + function insertLineWidgets(lineView, dims) { + insertLineWidgetsFor(lineView.line, lineView, dims, true); + if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + insertLineWidgetsFor(lineView.rest[i], lineView, dims, false); + } + + function insertLineWidgetsFor(line, lineView, dims, allowAbove) { + if (!line.widgets) return; + var wrap = ensureLineWrapped(lineView); + for (var i = 0, ws = line.widgets; i < ws.length; ++i) { + var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); + if (!widget.handleMouseEvents) node.ignoreEvents = true; + positionLineWidget(widget, node, lineView, dims); + if (allowAbove && widget.above) + wrap.insertBefore(node, lineView.gutter || lineView.text); + else + wrap.appendChild(node); + signalLater(widget, "redraw"); + } + } + + function positionLineWidget(widget, node, lineView, dims) { + if (widget.noHScroll) { + (lineView.alignable || (lineView.alignable = [])).push(node); + var width = dims.wrapperWidth; + node.style.left = dims.fixedPos + "px"; + if (!widget.coverGutter) { + width -= dims.gutterTotalWidth; + node.style.paddingLeft = dims.gutterTotalWidth + "px"; + } + node.style.width = width + "px"; + } + if (widget.coverGutter) { + node.style.zIndex = 5; + node.style.position = "relative"; + if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px"; + } + } + + // POSITION OBJECT + + // A Pos instance represents a position within the text. + var Pos = CodeMirror.Pos = function(line, ch) { + if (!(this instanceof Pos)) return new Pos(line, ch); + this.line = line; this.ch = ch; + }; + + // Compare two positions, return 0 if they are the same, a negative + // number when a is less, and a positive number otherwise. + var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; }; + + function copyPos(x) {return Pos(x.line, x.ch);} + function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; } + function minPos(a, b) { return cmp(a, b) < 0 ? a : b; } + + // SELECTION / CURSOR + + // Selection objects are immutable. A new one is created every time + // the selection changes. A selection is one or more non-overlapping + // (and non-touching) ranges, sorted, and an integer that indicates + // which one is the primary selection (the one that's scrolled into + // view, that getCursor returns, etc). + function Selection(ranges, primIndex) { + this.ranges = ranges; + this.primIndex = primIndex; + } + + Selection.prototype = { + primary: function() { return this.ranges[this.primIndex]; }, + equals: function(other) { + if (other == this) return true; + if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false; + for (var i = 0; i < this.ranges.length; i++) { + var here = this.ranges[i], there = other.ranges[i]; + if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false; + } + return true; + }, + deepCopy: function() { + for (var out = [], i = 0; i < this.ranges.length; i++) + out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); + return new Selection(out, this.primIndex); + }, + somethingSelected: function() { + for (var i = 0; i < this.ranges.length; i++) + if (!this.ranges[i].empty()) return true; + return false; + }, + contains: function(pos, end) { + if (!end) end = pos; + for (var i = 0; i < this.ranges.length; i++) { + var range = this.ranges[i]; + if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) + return i; + } + return -1; + } + }; + + function Range(anchor, head) { + this.anchor = anchor; this.head = head; + } + + Range.prototype = { + from: function() { return minPos(this.anchor, this.head); }, + to: function() { return maxPos(this.anchor, this.head); }, + empty: function() { + return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch; + } + }; + + // Take an unsorted, potentially overlapping set of ranges, and + // build a selection out of it. 'Consumes' ranges array (modifying + // it). + function normalizeSelection(ranges, primIndex) { + var prim = ranges[primIndex]; + ranges.sort(function(a, b) { return cmp(a.from(), b.from()); }); + primIndex = indexOf(ranges, prim); + for (var i = 1; i < ranges.length; i++) { + var cur = ranges[i], prev = ranges[i - 1]; + if (cmp(prev.to(), cur.from()) >= 0) { + var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()); + var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head; + if (i <= primIndex) --primIndex; + ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)); + } + } + return new Selection(ranges, primIndex); + } + + function simpleSelection(anchor, head) { + return new Selection([new Range(anchor, head || anchor)], 0); + } + + // Most of the external API clips given positions to make sure they + // actually exist within the document. + function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));} + function clipPos(doc, pos) { + if (pos.line < doc.first) return Pos(doc.first, 0); + var last = doc.first + doc.size - 1; + if (pos.line > last) return Pos(last, getLine(doc, last).text.length); + return clipToLen(pos, getLine(doc, pos.line).text.length); + } + function clipToLen(pos, linelen) { + var ch = pos.ch; + if (ch == null || ch > linelen) return Pos(pos.line, linelen); + else if (ch < 0) return Pos(pos.line, 0); + else return pos; + } + function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;} + function clipPosArray(doc, array) { + for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]); + return out; + } + + // SELECTION UPDATES + + // The 'scroll' parameter given to many of these indicated whether + // the new cursor position should be scrolled into view after + // modifying the selection. + + // If shift is held or the extend flag is set, extends a range to + // include a given position (and optionally a second position). + // Otherwise, simply returns the range between the given positions. + // Used for cursor motion and such. + function extendRange(doc, range, head, other) { + if (doc.cm && doc.cm.display.shift || doc.extend) { + var anchor = range.anchor; + if (other) { + var posBefore = cmp(head, anchor) < 0; + if (posBefore != (cmp(other, anchor) < 0)) { + anchor = head; + head = other; + } else if (posBefore != (cmp(head, other) < 0)) { + head = other; + } + } + return new Range(anchor, head); + } else { + return new Range(other || head, head); + } + } + + // Extend the primary selection range, discard the rest. + function extendSelection(doc, head, other, options) { + setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options); + } + + // Extend all selections (pos is an array of selections with length + // equal the number of selections) + function extendSelections(doc, heads, options) { + for (var out = [], i = 0; i < doc.sel.ranges.length; i++) + out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null); + var newSel = normalizeSelection(out, doc.sel.primIndex); + setSelection(doc, newSel, options); + } + + // Updates a single range in the selection. + function replaceOneSelection(doc, i, range, options) { + var ranges = doc.sel.ranges.slice(0); + ranges[i] = range; + setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options); + } + + // Reset the selection to a single range. + function setSimpleSelection(doc, anchor, head, options) { + setSelection(doc, simpleSelection(anchor, head), options); + } + + // Give beforeSelectionChange handlers a change to influence a + // selection update. + function filterSelectionChange(doc, sel) { + var obj = { + ranges: sel.ranges, + update: function(ranges) { + this.ranges = []; + for (var i = 0; i < ranges.length; i++) + this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), + clipPos(doc, ranges[i].head)); + } + }; + signal(doc, "beforeSelectionChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); + if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1); + else return sel; + } + + function setSelectionReplaceHistory(doc, sel, options) { + var done = doc.history.done, last = lst(done); + if (last && last.ranges) { + done[done.length - 1] = sel; + setSelectionNoUndo(doc, sel, options); + } else { + setSelection(doc, sel, options); + } + } + + // Set a new selection. + function setSelection(doc, sel, options) { + setSelectionNoUndo(doc, sel, options); + addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options); + } + + function setSelectionNoUndo(doc, sel, options) { + if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) + sel = filterSelectionChange(doc, sel); + + var bias = options && options.bias || + (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); + setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); + + if (!(options && options.scroll === false) && doc.cm) + ensureCursorVisible(doc.cm); + } + + function setSelectionInner(doc, sel) { + if (sel.equals(doc.sel)) return; + + doc.sel = sel; + + if (doc.cm) { + doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true; + signalCursorActivity(doc.cm); + } + signalLater(doc, "cursorActivity", doc); + } + + // Verify that the selection does not partially select any atomic + // marked ranges. + function reCheckSelection(doc) { + setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll); + } + + // Return a selection that does not partially select any atomic + // ranges. + function skipAtomicInSelection(doc, sel, bias, mayClear) { + var out; + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i]; + var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear); + var newHead = skipAtomic(doc, range.head, bias, mayClear); + if (out || newAnchor != range.anchor || newHead != range.head) { + if (!out) out = sel.ranges.slice(0, i); + out[i] = new Range(newAnchor, newHead); + } + } + return out ? normalizeSelection(out, sel.primIndex) : sel; + } + + // Ensure a given position is not inside an atomic range. + function skipAtomic(doc, pos, bias, mayClear) { + var flipped = false, curPos = pos; + var dir = bias || 1; + doc.cantEdit = false; + search: for (;;) { + var line = getLine(doc, curPos.line); + if (line.markedSpans) { + for (var i = 0; i < line.markedSpans.length; ++i) { + var sp = line.markedSpans[i], m = sp.marker; + if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) && + (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) { + if (mayClear) { + signal(m, "beforeCursorEnter"); + if (m.explicitlyCleared) { + if (!line.markedSpans) break; + else {--i; continue;} + } + } + if (!m.atomic) continue; + var newPos = m.find(dir < 0 ? -1 : 1); + if (cmp(newPos, curPos) == 0) { + newPos.ch += dir; + if (newPos.ch < 0) { + if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1)); + else newPos = null; + } else if (newPos.ch > line.text.length) { + if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0); + else newPos = null; + } + if (!newPos) { + if (flipped) { + // Driven in a corner -- no valid cursor position found at all + // -- try again *with* clearing, if we didn't already + if (!mayClear) return skipAtomic(doc, pos, bias, true); + // Otherwise, turn off editing until further notice, and return the start of the doc + doc.cantEdit = true; + return Pos(doc.first, 0); + } + flipped = true; newPos = pos; dir = -dir; + } + } + curPos = newPos; + continue search; + } + } + } + return curPos; + } + } + + // SELECTION DRAWING + + // Redraw the selection and/or cursor + function updateSelection(cm) { + var display = cm.display, doc = cm.doc; + var curFragment = document.createDocumentFragment(); + var selFragment = document.createDocumentFragment(); + + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + var collapsed = range.empty(); + if (collapsed || cm.options.showCursorWhenSelecting) + drawSelectionCursor(cm, range, curFragment); + if (!collapsed) + drawSelectionRange(cm, range, selFragment); + } + + // Move the hidden textarea near the cursor to prevent scrolling artifacts + if (cm.options.moveInputWithCursor) { + var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); + var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); + var top = Math.max(0, Math.min(display.wrapper.clientHeight - 10, + headPos.top + lineOff.top - wrapOff.top)); + var left = Math.max(0, Math.min(display.wrapper.clientWidth - 10, + headPos.left + lineOff.left - wrapOff.left)); + display.inputDiv.style.top = top + "px"; + display.inputDiv.style.left = left + "px"; + } + + removeChildrenAndAdd(display.cursorDiv, curFragment); + removeChildrenAndAdd(display.selectionDiv, selFragment); + } + + // Draws a cursor for the given range + function drawSelectionCursor(cm, range, output) { + var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine); + + var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); + cursor.style.left = pos.left + "px"; + cursor.style.top = pos.top + "px"; + cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; + + if (pos.other) { + // Secondary cursor, shown when on a 'jump' in bi-directional text + var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); + otherCursor.style.display = ""; + otherCursor.style.left = pos.other.left + "px"; + otherCursor.style.top = pos.other.top + "px"; + otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"; + } + } + + // Draws the given range as a highlighted selection + function drawSelectionRange(cm, range, output) { + var display = cm.display, doc = cm.doc; + var fragment = document.createDocumentFragment(); + var padding = paddingH(cm.display), leftSide = padding.left, rightSide = display.lineSpace.offsetWidth - padding.right; + + function add(left, top, width, bottom) { + if (top < 0) top = 0; + top = Math.round(top); + bottom = Math.round(bottom); + fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left + + "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) + + "px; height: " + (bottom - top) + "px")); + } + + function drawForLine(line, fromArg, toArg) { + var lineObj = getLine(doc, line); + var lineLen = lineObj.text.length; + var start, end; + function coords(ch, bias) { + return charCoords(cm, Pos(line, ch), "div", lineObj, bias); + } + + iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { + var leftPos = coords(from, "left"), rightPos, left, right; + if (from == to) { + rightPos = leftPos; + left = right = leftPos.left; + } else { + rightPos = coords(to - 1, "right"); + if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } + left = leftPos.left; + right = rightPos.right; + } + if (fromArg == null && from == 0) left = leftSide; + if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part + add(left, leftPos.top, null, leftPos.bottom); + left = leftSide; + if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top); + } + if (toArg == null && to == lineLen) right = rightSide; + if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) + start = leftPos; + if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) + end = rightPos; + if (left < leftSide + 1) left = leftSide; + add(left, rightPos.top, right - left, rightPos.bottom); + }); + return {start: start, end: end}; + } + + var sFrom = range.from(), sTo = range.to(); + if (sFrom.line == sTo.line) { + drawForLine(sFrom.line, sFrom.ch, sTo.ch); + } else { + var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line); + var singleVLine = visualLine(fromLine) == visualLine(toLine); + var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end; + var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start; + if (singleVLine) { + if (leftEnd.top < rightStart.top - 2) { + add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); + add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); + } else { + add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); + } + } + if (leftEnd.bottom < rightStart.top) + add(leftSide, leftEnd.bottom, null, rightStart.top); + } + + output.appendChild(fragment); + } + + // Cursor-blinking + function restartBlink(cm) { + if (!cm.state.focused) return; + var display = cm.display; + clearInterval(display.blinker); + var on = true; + display.cursorDiv.style.visibility = ""; + if (cm.options.cursorBlinkRate > 0) + display.blinker = setInterval(function() { + display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; + }, cm.options.cursorBlinkRate); + else if (cm.options.cursorBlinkRate < 0) + display.cursorDiv.style.visibility = "hidden"; + } + + // HIGHLIGHT WORKER + + function startWorker(cm, time) { + if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo) + cm.state.highlight.set(time, bind(highlightWorker, cm)); + } + + function highlightWorker(cm) { + var doc = cm.doc; + if (doc.frontier < doc.first) doc.frontier = doc.first; + if (doc.frontier >= cm.display.viewTo) return; + var end = +new Date + cm.options.workTime; + var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); + + runInOp(cm, function() { + doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) { + if (doc.frontier >= cm.display.viewFrom) { // Visible + var oldStyles = line.styles; + var highlighted = highlightLine(cm, line, state, true); + line.styles = highlighted.styles; + var oldCls = line.styleClasses, newCls = highlighted.classes; + if (newCls) line.styleClasses = newCls; + else if (oldCls) line.styleClasses = null; + var ischange = !oldStyles || oldStyles.length != line.styles.length || + oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); + for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; + if (ischange) regLineChange(cm, doc.frontier, "text"); + line.stateAfter = copyState(doc.mode, state); + } else { + processLine(cm, line.text, state); + line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; + } + ++doc.frontier; + if (+new Date > end) { + startWorker(cm, cm.options.workDelay); + return true; + } + }); + }); + } + + // Finds the line to start with when starting a parse. Tries to + // find a line with a stateAfter, so that it can start with a + // valid state. If that fails, it returns the line with the + // smallest indentation, which tends to need the least context to + // parse correctly. + function findStartLine(cm, n, precise) { + var minindent, minline, doc = cm.doc; + var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100); + for (var search = n; search > lim; --search) { + if (search <= doc.first) return doc.first; + var line = getLine(doc, search - 1); + if (line.stateAfter && (!precise || search <= doc.frontier)) return search; + var indented = countColumn(line.text, null, cm.options.tabSize); + if (minline == null || minindent > indented) { + minline = search - 1; + minindent = indented; + } + } + return minline; + } + + function getStateBefore(cm, n, precise) { + var doc = cm.doc, display = cm.display; + if (!doc.mode.startState) return true; + var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter; + if (!state) state = startState(doc.mode); + else state = copyState(doc.mode, state); + doc.iter(pos, n, function(line) { + processLine(cm, line.text, state); + var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo; + line.stateAfter = save ? copyState(doc.mode, state) : null; + ++pos; + }); + if (precise) doc.frontier = pos; + return state; + } + + // POSITION MEASUREMENT + + function paddingTop(display) {return display.lineSpace.offsetTop;} + function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;} + function paddingH(display) { + if (display.cachedPaddingH) return display.cachedPaddingH; + var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); + var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; + var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}; + if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data; + return data; + } + + // Ensure the lineView.wrapping.heights array is populated. This is + // an array of bottom offsets for the lines that make up a drawn + // line. When lineWrapping is on, there might be more than one + // height. + function ensureLineHeights(cm, lineView, rect) { + var wrapping = cm.options.lineWrapping; + var curWidth = wrapping && cm.display.scroller.clientWidth; + if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { + var heights = lineView.measure.heights = []; + if (wrapping) { + lineView.measure.width = curWidth; + var rects = lineView.text.firstChild.getClientRects(); + for (var i = 0; i < rects.length - 1; i++) { + var cur = rects[i], next = rects[i + 1]; + if (Math.abs(cur.bottom - next.bottom) > 2) + heights.push((cur.bottom + next.top) / 2 - rect.top); + } + } + heights.push(rect.bottom - rect.top); + } + } + + // Find a line map (mapping character offsets to text nodes) and a + // measurement cache for the given line number. (A line view might + // contain multiple lines when collapsed ranges are present.) + function mapFromLineView(lineView, line, lineN) { + if (lineView.line == line) + return {map: lineView.measure.map, cache: lineView.measure.cache}; + for (var i = 0; i < lineView.rest.length; i++) + if (lineView.rest[i] == line) + return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]}; + for (var i = 0; i < lineView.rest.length; i++) + if (lineNo(lineView.rest[i]) > lineN) + return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true}; + } + + // Render a line into the hidden node display.externalMeasured. Used + // when measurement is needed for a line that's not in the viewport. + function updateExternalMeasurement(cm, line) { + line = visualLine(line); + var lineN = lineNo(line); + var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN); + view.lineN = lineN; + var built = view.built = buildLineContent(cm, view); + view.text = built.pre; + removeChildrenAndAdd(cm.display.lineMeasure, built.pre); + return view; + } + + // Get a {top, bottom, left, right} box (in line-local coordinates) + // for a given character. + function measureChar(cm, line, ch, bias) { + return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias); + } + + // Find a line view that corresponds to the given line number. + function findViewForLine(cm, lineN) { + if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) + return cm.display.view[findViewIndex(cm, lineN)]; + var ext = cm.display.externalMeasured; + if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) + return ext; + } + + // Measurement can be split in two steps, the set-up work that + // applies to the whole line, and the measurement of the actual + // character. Functions like coordsChar, that need to do a lot of + // measurements in a row, can thus ensure that the set-up work is + // only done once. + function prepareMeasureForLine(cm, line) { + var lineN = lineNo(line); + var view = findViewForLine(cm, lineN); + if (view && !view.text) + view = null; + else if (view && view.changes) + updateLineForChanges(cm, view, lineN, getDimensions(cm)); + if (!view) + view = updateExternalMeasurement(cm, line); + + var info = mapFromLineView(view, line, lineN); + return { + line: line, view: view, rect: null, + map: info.map, cache: info.cache, before: info.before, + hasHeights: false + }; + } + + // Given a prepared measurement object, measures the position of an + // actual character (or fetches it from the cache). + function measureCharPrepared(cm, prepared, ch, bias, varHeight) { + if (prepared.before) ch = -1; + var key = ch + (bias || ""), found; + if (prepared.cache.hasOwnProperty(key)) { + found = prepared.cache[key]; + } else { + if (!prepared.rect) + prepared.rect = prepared.view.text.getBoundingClientRect(); + if (!prepared.hasHeights) { + ensureLineHeights(cm, prepared.view, prepared.rect); + prepared.hasHeights = true; + } + found = measureCharInner(cm, prepared, ch, bias); + if (!found.bogus) prepared.cache[key] = found; + } + return {left: found.left, right: found.right, + top: varHeight ? found.rtop : found.top, + bottom: varHeight ? found.rbottom : found.bottom}; + } + + var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; + + function measureCharInner(cm, prepared, ch, bias) { + var map = prepared.map; + + var node, start, end, collapse; + // First, search the line map for the text node corresponding to, + // or closest to, the target character. + for (var i = 0; i < map.length; i += 3) { + var mStart = map[i], mEnd = map[i + 1]; + if (ch < mStart) { + start = 0; end = 1; + collapse = "left"; + } else if (ch < mEnd) { + start = ch - mStart; + end = start + 1; + } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { + end = mEnd - mStart; + start = end - 1; + if (ch >= mEnd) collapse = "right"; + } + if (start != null) { + node = map[i + 2]; + if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) + collapse = bias; + if (bias == "left" && start == 0) + while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { + node = map[(i -= 3) + 2]; + collapse = "left"; + } + if (bias == "right" && start == mEnd - mStart) + while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { + node = map[(i += 3) + 2]; + collapse = "right"; + } + break; + } + } + + var rect; + if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. + while (start && isExtendingChar(prepared.line.text.charAt(mStart + start))) --start; + while (mStart + end < mEnd && isExtendingChar(prepared.line.text.charAt(mStart + end))) ++end; + if (ie && ie_version < 9 && start == 0 && end == mEnd - mStart) { + rect = node.parentNode.getBoundingClientRect(); + } else if (ie && cm.options.lineWrapping) { + var rects = range(node, start, end).getClientRects(); + if (rects.length) + rect = rects[bias == "right" ? rects.length - 1 : 0]; + else + rect = nullRect; + } else { + rect = range(node, start, end).getBoundingClientRect() || nullRect; + } + } else { // If it is a widget, simply get the box for the whole widget. + if (start > 0) collapse = bias = "right"; + var rects; + if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) + rect = rects[bias == "right" ? rects.length - 1 : 0]; + else + rect = node.getBoundingClientRect(); + } + if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { + var rSpan = node.parentNode.getClientRects()[0]; + if (rSpan) + rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; + else + rect = nullRect; + } + + var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; + var mid = (rtop + rbot) / 2; + var heights = prepared.view.measure.heights; + for (var i = 0; i < heights.length - 1; i++) + if (mid < heights[i]) break; + var top = i ? heights[i - 1] : 0, bot = heights[i]; + var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, + right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, + top: top, bottom: bot}; + if (!rect.left && !rect.right) result.bogus = true; + if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } + return result; + } + + function clearLineMeasurementCacheFor(lineView) { + if (lineView.measure) { + lineView.measure.cache = {}; + lineView.measure.heights = null; + if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + lineView.measure.caches[i] = {}; + } + } + + function clearLineMeasurementCache(cm) { + cm.display.externalMeasure = null; + removeChildren(cm.display.lineMeasure); + for (var i = 0; i < cm.display.view.length; i++) + clearLineMeasurementCacheFor(cm.display.view[i]); + } + + function clearCaches(cm) { + clearLineMeasurementCache(cm); + cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; + if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; + cm.display.lineNumChars = null; + } + + function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; } + function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; } + + // Converts a {top, bottom, left, right} box from line-local + // coordinates into another coordinate system. Context may be one of + // "line", "div" (display.lineDiv), "local"/null (editor), or "page". + function intoCoordSystem(cm, lineObj, rect, context) { + if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { + var size = widgetHeight(lineObj.widgets[i]); + rect.top += size; rect.bottom += size; + } + if (context == "line") return rect; + if (!context) context = "local"; + var yOff = heightAtLine(lineObj); + if (context == "local") yOff += paddingTop(cm.display); + else yOff -= cm.display.viewOffset; + if (context == "page" || context == "window") { + var lOff = cm.display.lineSpace.getBoundingClientRect(); + yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); + var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); + rect.left += xOff; rect.right += xOff; + } + rect.top += yOff; rect.bottom += yOff; + return rect; + } + + // Coverts a box from "div" coords to another coordinate system. + // Context may be "window", "page", "div", or "local"/null. + function fromCoordSystem(cm, coords, context) { + if (context == "div") return coords; + var left = coords.left, top = coords.top; + // First move into "page" coordinate system + if (context == "page") { + left -= pageScrollX(); + top -= pageScrollY(); + } else if (context == "local" || !context) { + var localBox = cm.display.sizer.getBoundingClientRect(); + left += localBox.left; + top += localBox.top; + } + + var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect(); + return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}; + } + + function charCoords(cm, pos, context, lineObj, bias) { + if (!lineObj) lineObj = getLine(cm.doc, pos.line); + return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context); + } + + // Returns a box for a given cursor position, which may have an + // 'other' property containing the position of the secondary cursor + // on a bidi boundary. + function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { + lineObj = lineObj || getLine(cm.doc, pos.line); + if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj); + function get(ch, right) { + var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight); + if (right) m.left = m.right; else m.right = m.left; + return intoCoordSystem(cm, lineObj, m, context); + } + function getBidi(ch, partPos) { + var part = order[partPos], right = part.level % 2; + if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { + part = order[--partPos]; + ch = bidiRight(part) - (part.level % 2 ? 0 : 1); + right = true; + } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) { + part = order[++partPos]; + ch = bidiLeft(part) - part.level % 2; + right = false; + } + if (right && ch == part.to && ch > part.from) return get(ch - 1); + return get(ch, right); + } + var order = getOrder(lineObj), ch = pos.ch; + if (!order) return get(ch); + var partPos = getBidiPartAt(order, ch); + var val = getBidi(ch, partPos); + if (bidiOther != null) val.other = getBidi(ch, bidiOther); + return val; + } + + // Used to cheaply estimate the coordinates for a position. Used for + // intermediate scroll updates. + function estimateCoords(cm, pos) { + var left = 0, pos = clipPos(cm.doc, pos); + if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch; + var lineObj = getLine(cm.doc, pos.line); + var top = heightAtLine(lineObj) + paddingTop(cm.display); + return {left: left, right: left, top: top, bottom: top + lineObj.height}; + } + + // Positions returned by coordsChar contain some extra information. + // xRel is the relative x position of the input coordinates compared + // to the found position (so xRel > 0 means the coordinates are to + // the right of the character position, for example). When outside + // is true, that means the coordinates lie outside the line's + // vertical range. + function PosWithInfo(line, ch, outside, xRel) { + var pos = Pos(line, ch); + pos.xRel = xRel; + if (outside) pos.outside = true; + return pos; + } + + // Compute the character position closest to the given coordinates. + // Input must be lineSpace-local ("div" coordinate system). + function coordsChar(cm, x, y) { + var doc = cm.doc; + y += cm.display.viewOffset; + if (y < 0) return PosWithInfo(doc.first, 0, true, -1); + var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; + if (lineN > last) + return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1); + if (x < 0) x = 0; + + var lineObj = getLine(doc, lineN); + for (;;) { + var found = coordsCharInner(cm, lineObj, lineN, x, y); + var merged = collapsedSpanAtEnd(lineObj); + var mergedPos = merged && merged.find(0, true); + if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) + lineN = lineNo(lineObj = mergedPos.to.line); + else + return found; + } + } + + function coordsCharInner(cm, lineObj, lineNo, x, y) { + var innerOff = y - heightAtLine(lineObj); + var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth; + var preparedMeasure = prepareMeasureForLine(cm, lineObj); + + function getX(ch) { + var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure); + wrongLine = true; + if (innerOff > sp.bottom) return sp.left - adjust; + else if (innerOff < sp.top) return sp.left + adjust; + else wrongLine = false; + return sp.left; + } + + var bidi = getOrder(lineObj), dist = lineObj.text.length; + var from = lineLeft(lineObj), to = lineRight(lineObj); + var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine; + + if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1); + // Do a binary search between these bounds. + for (;;) { + if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { + var ch = x < fromX || x - fromX <= toX - x ? from : to; + var xDiff = x - (ch == from ? fromX : toX); + while (isExtendingChar(lineObj.text.charAt(ch))) ++ch; + var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside, + xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0); + return pos; + } + var step = Math.ceil(dist / 2), middle = from + step; + if (bidi) { + middle = from; + for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1); + } + var middleX = getX(middle); + if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;} + else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;} + } + } + + var measureText; + // Compute the default text height. + function textHeight(display) { + if (display.cachedTextHeight != null) return display.cachedTextHeight; + if (measureText == null) { + measureText = elt("pre"); + // Measure a bunch of lines, for browsers that compute + // fractional heights. + for (var i = 0; i < 49; ++i) { + measureText.appendChild(document.createTextNode("x")); + measureText.appendChild(elt("br")); + } + measureText.appendChild(document.createTextNode("x")); + } + removeChildrenAndAdd(display.measure, measureText); + var height = measureText.offsetHeight / 50; + if (height > 3) display.cachedTextHeight = height; + removeChildren(display.measure); + return height || 1; + } + + // Compute the default character width. + function charWidth(display) { + if (display.cachedCharWidth != null) return display.cachedCharWidth; + var anchor = elt("span", "xxxxxxxxxx"); + var pre = elt("pre", [anchor]); + removeChildrenAndAdd(display.measure, pre); + var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; + if (width > 2) display.cachedCharWidth = width; + return width || 10; + } + + // OPERATIONS + + // Operations are used to wrap a series of changes to the editor + // state in such a way that each change won't have to update the + // cursor and display (which would be awkward, slow, and + // error-prone). Instead, display updates are batched and then all + // combined and executed at once. + + var nextOpId = 0; + // Start a new operation. + function startOperation(cm) { + cm.curOp = { + viewChanged: false, // Flag that indicates that lines might need to be redrawn + startHeight: cm.doc.height, // Used to detect need to update scrollbar + forceUpdate: false, // Used to force a redraw + updateInput: null, // Whether to reset the input textarea + typing: false, // Whether this reset should be careful to leave existing text (for compositing) + changeObjs: null, // Accumulated changes, for firing change events + cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on + selectionChanged: false, // Whether the selection needs to be redrawn + updateMaxLine: false, // Set when the widest line needs to be determined anew + scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet + scrollToPos: null, // Used to scroll to a specific position + id: ++nextOpId // Unique ID + }; + if (!delayedCallbackDepth++) delayedCallbacks = []; + } + + // Finish an operation, updating the display and signalling delayed events + function endOperation(cm) { + var op = cm.curOp, doc = cm.doc, display = cm.display; + cm.curOp = null; + + if (op.updateMaxLine) findMaxLine(cm); + + // If it looks like an update might be needed, call updateDisplay + if (op.viewChanged || op.forceUpdate || op.scrollTop != null || + op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || + op.scrollToPos.to.line >= display.viewTo) || + display.maxLineChanged && cm.options.lineWrapping) { + var updated = updateDisplay(cm, {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate); + if (cm.display.scroller.offsetHeight) cm.doc.scrollTop = cm.display.scroller.scrollTop; + } + // If no update was run, but the selection changed, redraw that. + if (!updated && op.selectionChanged) updateSelection(cm); + if (!updated && op.startHeight != cm.doc.height) updateScrollbars(cm); + + // Abort mouse wheel delta measurement, when scrolling explicitly + if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) + display.wheelStartX = display.wheelStartY = null; + + // Propagate the scroll position to the actual DOM scroller + if (op.scrollTop != null && display.scroller.scrollTop != op.scrollTop) { + var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)); + display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top; + } + if (op.scrollLeft != null && display.scroller.scrollLeft != op.scrollLeft) { + var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft)); + display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left; + alignHorizontally(cm); + } + // If we need to scroll a specific position into view, do so. + if (op.scrollToPos) { + var coords = scrollPosIntoView(cm, clipPos(cm.doc, op.scrollToPos.from), + clipPos(cm.doc, op.scrollToPos.to), op.scrollToPos.margin); + if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords); + } + + if (op.selectionChanged) restartBlink(cm); + + if (cm.state.focused && op.updateInput) + resetInput(cm, op.typing); + + // Fire events for markers that are hidden/unidden by editing or + // undoing + var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; + if (hidden) for (var i = 0; i < hidden.length; ++i) + if (!hidden[i].lines.length) signal(hidden[i], "hide"); + if (unhidden) for (var i = 0; i < unhidden.length; ++i) + if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); + + var delayed; + if (!--delayedCallbackDepth) { + delayed = delayedCallbacks; + delayedCallbacks = null; + } + // Fire change events, and delayed event handlers + if (op.changeObjs) + signal(cm, "changes", cm, op.changeObjs); + if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i](); + if (op.cursorActivityHandlers) + for (var i = 0; i < op.cursorActivityHandlers.length; i++) + op.cursorActivityHandlers[i](cm); + } + + // Run the given function in an operation + function runInOp(cm, f) { + if (cm.curOp) return f(); + startOperation(cm); + try { return f(); } + finally { endOperation(cm); } + } + // Wraps a function in an operation. Returns the wrapped function. + function operation(cm, f) { + return function() { + if (cm.curOp) return f.apply(cm, arguments); + startOperation(cm); + try { return f.apply(cm, arguments); } + finally { endOperation(cm); } + }; + } + // Used to add methods to editor and doc instances, wrapping them in + // operations. + function methodOp(f) { + return function() { + if (this.curOp) return f.apply(this, arguments); + startOperation(this); + try { return f.apply(this, arguments); } + finally { endOperation(this); } + }; + } + function docMethodOp(f) { + return function() { + var cm = this.cm; + if (!cm || cm.curOp) return f.apply(this, arguments); + startOperation(cm); + try { return f.apply(this, arguments); } + finally { endOperation(cm); } + }; + } + + // VIEW TRACKING + + // These objects are used to represent the visible (currently drawn) + // part of the document. A LineView may correspond to multiple + // logical lines, if those are connected by collapsed ranges. + function LineView(doc, line, lineN) { + // The starting line + this.line = line; + // Continuing lines, if any + this.rest = visualLineContinued(line); + // Number of logical lines in this visual line + this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1; + this.node = this.text = null; + this.hidden = lineIsHidden(doc, line); + } + + // Create a range of LineView objects for the given lines. + function buildViewArray(cm, from, to) { + var array = [], nextPos; + for (var pos = from; pos < to; pos = nextPos) { + var view = new LineView(cm.doc, getLine(cm.doc, pos), pos); + nextPos = pos + view.size; + array.push(view); + } + return array; + } + + // Updates the display.view data structure for a given change to the + // document. From and to are in pre-change coordinates. Lendiff is + // the amount of lines added or subtracted by the change. This is + // used for changes that span multiple lines, or change the way + // lines are divided into visual lines. regLineChange (below) + // registers single-line changes. + function regChange(cm, from, to, lendiff) { + if (from == null) from = cm.doc.first; + if (to == null) to = cm.doc.first + cm.doc.size; + if (!lendiff) lendiff = 0; + + var display = cm.display; + if (lendiff && to < display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers > from)) + display.updateLineNumbers = from; + + cm.curOp.viewChanged = true; + + if (from >= display.viewTo) { // Change after + if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) + resetView(cm); + } else if (to <= display.viewFrom) { // Change before + if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { + resetView(cm); + } else { + display.viewFrom += lendiff; + display.viewTo += lendiff; + } + } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap + resetView(cm); + } else if (from <= display.viewFrom) { // Top overlap + var cut = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cut) { + display.view = display.view.slice(cut.index); + display.viewFrom = cut.lineN; + display.viewTo += lendiff; + } else { + resetView(cm); + } + } else if (to >= display.viewTo) { // Bottom overlap + var cut = viewCuttingPoint(cm, from, from, -1); + if (cut) { + display.view = display.view.slice(0, cut.index); + display.viewTo = cut.lineN; + } else { + resetView(cm); + } + } else { // Gap in the middle + var cutTop = viewCuttingPoint(cm, from, from, -1); + var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cutTop && cutBot) { + display.view = display.view.slice(0, cutTop.index) + .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) + .concat(display.view.slice(cutBot.index)); + display.viewTo += lendiff; + } else { + resetView(cm); + } + } + + var ext = display.externalMeasured; + if (ext) { + if (to < ext.lineN) + ext.lineN += lendiff; + else if (from < ext.lineN + ext.size) + display.externalMeasured = null; + } + } + + // Register a change to a single line. Type must be one of "text", + // "gutter", "class", "widget" + function regLineChange(cm, line, type) { + cm.curOp.viewChanged = true; + var display = cm.display, ext = cm.display.externalMeasured; + if (ext && line >= ext.lineN && line < ext.lineN + ext.size) + display.externalMeasured = null; + + if (line < display.viewFrom || line >= display.viewTo) return; + var lineView = display.view[findViewIndex(cm, line)]; + if (lineView.node == null) return; + var arr = lineView.changes || (lineView.changes = []); + if (indexOf(arr, type) == -1) arr.push(type); + } + + // Clear the view. + function resetView(cm) { + cm.display.viewFrom = cm.display.viewTo = cm.doc.first; + cm.display.view = []; + cm.display.viewOffset = 0; + } + + // Find the view element corresponding to a given line. Return null + // when the line isn't visible. + function findViewIndex(cm, n) { + if (n >= cm.display.viewTo) return null; + n -= cm.display.viewFrom; + if (n < 0) return null; + var view = cm.display.view; + for (var i = 0; i < view.length; i++) { + n -= view[i].size; + if (n < 0) return i; + } + } + + function viewCuttingPoint(cm, oldN, newN, dir) { + var index = findViewIndex(cm, oldN), diff, view = cm.display.view; + if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) + return {index: index, lineN: newN}; + for (var i = 0, n = cm.display.viewFrom; i < index; i++) + n += view[i].size; + if (n != oldN) { + if (dir > 0) { + if (index == view.length - 1) return null; + diff = (n + view[index].size) - oldN; + index++; + } else { + diff = n - oldN; + } + oldN += diff; newN += diff; + } + while (visualLineNo(cm.doc, newN) != newN) { + if (index == (dir < 0 ? 0 : view.length - 1)) return null; + newN += dir * view[index - (dir < 0 ? 1 : 0)].size; + index += dir; + } + return {index: index, lineN: newN}; + } + + // Force the view to cover a given range, adding empty view element + // or clipping off existing ones as needed. + function adjustView(cm, from, to) { + var display = cm.display, view = display.view; + if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { + display.view = buildViewArray(cm, from, to); + display.viewFrom = from; + } else { + if (display.viewFrom > from) + display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); + else if (display.viewFrom < from) + display.view = display.view.slice(findViewIndex(cm, from)); + display.viewFrom = from; + if (display.viewTo < to) + display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); + else if (display.viewTo > to) + display.view = display.view.slice(0, findViewIndex(cm, to)); + } + display.viewTo = to; + } + + // Count the number of lines in the view whose DOM representation is + // out of date (or nonexistent). + function countDirtyView(cm) { + var view = cm.display.view, dirty = 0; + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty; + } + return dirty; + } + + // INPUT HANDLING + + // Poll for input changes, using the normal rate of polling. This + // runs as long as the editor is focused. + function slowPoll(cm) { + if (cm.display.pollingFast) return; + cm.display.poll.set(cm.options.pollInterval, function() { + readInput(cm); + if (cm.state.focused) slowPoll(cm); + }); + } + + // When an event has just come in that is likely to add or change + // something in the input textarea, we poll faster, to ensure that + // the change appears on the screen quickly. + function fastPoll(cm) { + var missed = false; + cm.display.pollingFast = true; + function p() { + var changed = readInput(cm); + if (!changed && !missed) {missed = true; cm.display.poll.set(60, p);} + else {cm.display.pollingFast = false; slowPoll(cm);} + } + cm.display.poll.set(20, p); + } + + // Read input from the textarea, and update the document to match. + // When something is selected, it is present in the textarea, and + // selected (unless it is huge, in which case a placeholder is + // used). When nothing is selected, the cursor sits after previously + // seen text (can be empty), which is stored in prevInput (we must + // not reset the textarea when typing, because that breaks IME). + function readInput(cm) { + var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc; + // Since this is called a *lot*, try to bail out as cheaply as + // possible when it is clear that nothing happened. hasSelection + // will be the case when there is a lot of text in the textarea, + // in which case reading its value would be expensive. + if (!cm.state.focused || (hasSelection(input) && !prevInput) || isReadOnly(cm) || cm.options.disableInput) + return false; + // See paste handler for more on the fakedLastChar kludge + if (cm.state.pasteIncoming && cm.state.fakedLastChar) { + input.value = input.value.substring(0, input.value.length - 1); + cm.state.fakedLastChar = false; + } + var text = input.value; + // If nothing changed, bail. + if (text == prevInput && !cm.somethingSelected()) return false; + // Work around nonsensical selection resetting in IE9/10 + if (ie && ie_version >= 9 && cm.display.inputHasSelection === text) { + resetInput(cm); + return false; + } + + var withOp = !cm.curOp; + if (withOp) startOperation(cm); + cm.display.shift = false; + + if (text.charCodeAt(0) == 0x200b && doc.sel == cm.display.selForContextMenu && !prevInput) + prevInput = "\u200b"; + // Find the part of the input that is actually new + var same = 0, l = Math.min(prevInput.length, text.length); + while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; + var inserted = text.slice(same), textLines = splitLines(inserted); + + // When pasing N lines into N selections, insert one line per selection + var multiPaste = cm.state.pasteIncoming && textLines.length > 1 && doc.sel.ranges.length == textLines.length; + + // Normal behavior is to insert the new text into every selection + for (var i = doc.sel.ranges.length - 1; i >= 0; i--) { + var range = doc.sel.ranges[i]; + var from = range.from(), to = range.to(); + // Handle deletion + if (same < prevInput.length) + from = Pos(from.line, from.ch - (prevInput.length - same)); + // Handle overwrite + else if (cm.state.overwrite && range.empty() && !cm.state.pasteIncoming) + to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); + var updateInput = cm.curOp.updateInput; + var changeEvent = {from: from, to: to, text: multiPaste ? [textLines[i]] : textLines, + origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"}; + makeChange(cm.doc, changeEvent); + signalLater(cm, "inputRead", cm, changeEvent); + // When an 'electric' character is inserted, immediately trigger a reindent + if (inserted && !cm.state.pasteIncoming && cm.options.electricChars && + cm.options.smartIndent && range.head.ch < 100 && + (!i || doc.sel.ranges[i - 1].head.line != range.head.line)) { + var mode = cm.getModeAt(range.head); + if (mode.electricChars) { + for (var j = 0; j < mode.electricChars.length; j++) + if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { + indentLine(cm, range.head.line, "smart"); + break; + } + } else if (mode.electricInput) { + var end = changeEnd(changeEvent); + if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch))) + indentLine(cm, range.head.line, "smart"); + } + } + } + ensureCursorVisible(cm); + cm.curOp.updateInput = updateInput; + cm.curOp.typing = true; + + // Don't leave long text in the textarea, since it makes further polling slow + if (text.length > 1000 || text.indexOf("\n") > -1) input.value = cm.display.prevInput = ""; + else cm.display.prevInput = text; + if (withOp) endOperation(cm); + cm.state.pasteIncoming = cm.state.cutIncoming = false; + return true; + } + + // Reset the input to correspond to the selection (or to be empty, + // when not typing and nothing is selected) + function resetInput(cm, typing) { + var minimal, selected, doc = cm.doc; + if (cm.somethingSelected()) { + cm.display.prevInput = ""; + var range = doc.sel.primary(); + minimal = hasCopyEvent && + (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000); + var content = minimal ? "-" : selected || cm.getSelection(); + cm.display.input.value = content; + if (cm.state.focused) selectInput(cm.display.input); + if (ie && ie_version >= 9) cm.display.inputHasSelection = content; + } else if (!typing) { + cm.display.prevInput = cm.display.input.value = ""; + if (ie && ie_version >= 9) cm.display.inputHasSelection = null; + } + cm.display.inaccurateSelection = minimal; + } + + function focusInput(cm) { + if (cm.options.readOnly != "nocursor" && (!mobile || activeElt() != cm.display.input)) + cm.display.input.focus(); + } + + function ensureFocus(cm) { + if (!cm.state.focused) { focusInput(cm); onFocus(cm); } + } + + function isReadOnly(cm) { + return cm.options.readOnly || cm.doc.cantEdit; + } + + // EVENT HANDLERS + + // Attach the necessary event handlers when initializing the editor + function registerEventHandlers(cm) { + var d = cm.display; + on(d.scroller, "mousedown", operation(cm, onMouseDown)); + // Older IE's will not fire a second mousedown for a double click + if (ie && ie_version < 11) + on(d.scroller, "dblclick", operation(cm, function(e) { + if (signalDOMEvent(cm, e)) return; + var pos = posFromMouse(cm, e); + if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; + e_preventDefault(e); + var word = findWordAt(cm, pos); + extendSelection(cm.doc, word.anchor, word.head); + })); + else + on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); }); + // Prevent normal selection in the editor (we handle our own) + on(d.lineSpace, "selectstart", function(e) { + if (!eventInWidget(d, e)) e_preventDefault(e); + }); + // Some browsers fire contextmenu *after* opening the menu, at + // which point we can't mess with it anymore. Context menu is + // handled in onMouseDown for these browsers. + if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); + + // Sync scrolling between fake scrollbars and real scrollable + // area, ensure viewport is updated when scrolling. + on(d.scroller, "scroll", function() { + if (d.scroller.clientHeight) { + setScrollTop(cm, d.scroller.scrollTop); + setScrollLeft(cm, d.scroller.scrollLeft, true); + signal(cm, "scroll", cm); + } + }); + on(d.scrollbarV, "scroll", function() { + if (d.scroller.clientHeight) setScrollTop(cm, d.scrollbarV.scrollTop); + }); + on(d.scrollbarH, "scroll", function() { + if (d.scroller.clientHeight) setScrollLeft(cm, d.scrollbarH.scrollLeft); + }); + + // Listen to wheel events in order to try and update the viewport on time. + on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); + on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); + + // Prevent clicks in the scrollbars from killing focus + function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); } + on(d.scrollbarH, "mousedown", reFocus); + on(d.scrollbarV, "mousedown", reFocus); + // Prevent wrapper from ever scrolling + on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); + + on(d.input, "keyup", operation(cm, onKeyUp)); + on(d.input, "input", function() { + if (ie && ie_version >= 9 && cm.display.inputHasSelection) cm.display.inputHasSelection = null; + fastPoll(cm); + }); + on(d.input, "keydown", operation(cm, onKeyDown)); + on(d.input, "keypress", operation(cm, onKeyPress)); + on(d.input, "focus", bind(onFocus, cm)); + on(d.input, "blur", bind(onBlur, cm)); + + function drag_(e) { + if (!signalDOMEvent(cm, e)) e_stop(e); + } + if (cm.options.dragDrop) { + on(d.scroller, "dragstart", function(e){onDragStart(cm, e);}); + on(d.scroller, "dragenter", drag_); + on(d.scroller, "dragover", drag_); + on(d.scroller, "drop", operation(cm, onDrop)); + } + on(d.scroller, "paste", function(e) { + if (eventInWidget(d, e)) return; + cm.state.pasteIncoming = true; + focusInput(cm); + fastPoll(cm); + }); + on(d.input, "paste", function() { + // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206 + // Add a char to the end of textarea before paste occur so that + // selection doesn't span to the end of textarea. + if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) { + var start = d.input.selectionStart, end = d.input.selectionEnd; + d.input.value += "$"; + // The selection end needs to be set before the start, otherwise there + // can be an intermediate non-empty selection between the two, which + // can override the middle-click paste buffer on linux and cause the + // wrong thing to get pasted. + d.input.selectionEnd = end; + d.input.selectionStart = start; + cm.state.fakedLastChar = true; + } + cm.state.pasteIncoming = true; + fastPoll(cm); + }); + + function prepareCopyCut(e) { + if (cm.somethingSelected()) { + if (d.inaccurateSelection) { + d.prevInput = ""; + d.inaccurateSelection = false; + d.input.value = cm.getSelection(); + selectInput(d.input); + } + } else { + var text = "", ranges = []; + for (var i = 0; i < cm.doc.sel.ranges.length; i++) { + var line = cm.doc.sel.ranges[i].head.line; + var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)}; + ranges.push(lineRange); + text += cm.getRange(lineRange.anchor, lineRange.head); + } + if (e.type == "cut") { + cm.setSelections(ranges, null, sel_dontScroll); + } else { + d.prevInput = ""; + d.input.value = text; + selectInput(d.input); + } + } + if (e.type == "cut") cm.state.cutIncoming = true; + } + on(d.input, "cut", prepareCopyCut); + on(d.input, "copy", prepareCopyCut); + + // Needed to handle Tab key in KHTML + if (khtml) on(d.sizer, "mouseup", function() { + if (activeElt() == d.input) d.input.blur(); + focusInput(cm); + }); + } + + // Called when the window resizes + function onResize(cm) { + // Might be a text scaling operation, clear size caches. + var d = cm.display; + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + cm.setSize(); + } + + // MOUSE EVENTS + + // Return true when the given mouse event happened in a widget + function eventInWidget(display, e) { + for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { + if (!n || n.ignoreEvents || n.parentNode == display.sizer && n != display.mover) return true; + } + } + + // Given a mouse event, find the corresponding position. If liberal + // is false, it checks whether a gutter or scrollbar was clicked, + // and returns null if it was. forRect is used by rectangular + // selections, and tries to estimate a character position even for + // coordinates beyond the right of the text. + function posFromMouse(cm, e, liberal, forRect) { + var display = cm.display; + if (!liberal) { + var target = e_target(e); + if (target == display.scrollbarH || target == display.scrollbarV || + target == display.scrollbarFiller || target == display.gutterFiller) return null; + } + var x, y, space = display.lineSpace.getBoundingClientRect(); + // Fails unpredictably on IE[67] when mouse is dragged around quickly. + try { x = e.clientX - space.left; y = e.clientY - space.top; } + catch (e) { return null; } + var coords = coordsChar(cm, x, y), line; + if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { + var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; + coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); + } + return coords; + } + + // A mouse down can be a single click, double click, triple click, + // start of selection drag, start of text drag, new cursor + // (ctrl-click), rectangle drag (alt-drag), or xwin + // middle-click-paste. Or it might be a click on something we should + // not interfere with, such as a scrollbar or widget. + function onMouseDown(e) { + if (signalDOMEvent(this, e)) return; + var cm = this, display = cm.display; + display.shift = e.shiftKey; + + if (eventInWidget(display, e)) { + if (!webkit) { + // Briefly turn off draggability, to allow widgets to do + // normal dragging things. + display.scroller.draggable = false; + setTimeout(function(){display.scroller.draggable = true;}, 100); + } + return; + } + if (clickInGutter(cm, e)) return; + var start = posFromMouse(cm, e); + window.focus(); + + switch (e_button(e)) { + case 1: + if (start) + leftButtonDown(cm, e, start); + else if (e_target(e) == display.scroller) + e_preventDefault(e); + break; + case 2: + if (webkit) cm.state.lastMiddleDown = +new Date; + if (start) extendSelection(cm.doc, start); + setTimeout(bind(focusInput, cm), 20); + e_preventDefault(e); + break; + case 3: + if (captureRightClick) onContextMenu(cm, e); + break; + } + } + + var lastClick, lastDoubleClick; + function leftButtonDown(cm, e, start) { + setTimeout(bind(ensureFocus, cm), 0); + + var now = +new Date, type; + if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { + type = "triple"; + } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) { + type = "double"; + lastDoubleClick = {time: now, pos: start}; + } else { + type = "single"; + lastClick = {time: now, pos: start}; + } + + var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey; + if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) && + type == "single" && sel.contains(start) > -1 && sel.somethingSelected()) + leftButtonStartDrag(cm, e, start, modifier); + else + leftButtonSelect(cm, e, start, type, modifier); + } + + // Start a text drag. When it ends, see if any dragging actually + // happen, and treat as a click if it didn't. + function leftButtonStartDrag(cm, e, start, modifier) { + var display = cm.display; + var dragEnd = operation(cm, function(e2) { + if (webkit) display.scroller.draggable = false; + cm.state.draggingText = false; + off(document, "mouseup", dragEnd); + off(display.scroller, "drop", dragEnd); + if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { + e_preventDefault(e2); + if (!modifier) + extendSelection(cm.doc, start); + focusInput(cm); + // Work around unexplainable focus problem in IE9 (#2127) + if (ie && ie_version == 9) + setTimeout(function() {document.body.focus(); focusInput(cm);}, 20); + } + }); + // Let the drag handler handle this. + if (webkit) display.scroller.draggable = true; + cm.state.draggingText = dragEnd; + // IE's approach to draggable + if (display.scroller.dragDrop) display.scroller.dragDrop(); + on(document, "mouseup", dragEnd); + on(display.scroller, "drop", dragEnd); + } + + // Normal selection, as opposed to text dragging. + function leftButtonSelect(cm, e, start, type, addNew) { + var display = cm.display, doc = cm.doc; + e_preventDefault(e); + + var ourRange, ourIndex, startSel = doc.sel; + if (addNew && !e.shiftKey) { + ourIndex = doc.sel.contains(start); + if (ourIndex > -1) + ourRange = doc.sel.ranges[ourIndex]; + else + ourRange = new Range(start, start); + } else { + ourRange = doc.sel.primary(); + } + + if (e.altKey) { + type = "rect"; + if (!addNew) ourRange = new Range(start, start); + start = posFromMouse(cm, e, true, true); + ourIndex = -1; + } else if (type == "double") { + var word = findWordAt(cm, start); + if (cm.display.shift || doc.extend) + ourRange = extendRange(doc, ourRange, word.anchor, word.head); + else + ourRange = word; + } else if (type == "triple") { + var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))); + if (cm.display.shift || doc.extend) + ourRange = extendRange(doc, ourRange, line.anchor, line.head); + else + ourRange = line; + } else { + ourRange = extendRange(doc, ourRange, start); + } + + if (!addNew) { + ourIndex = 0; + setSelection(doc, new Selection([ourRange], 0), sel_mouse); + startSel = doc.sel; + } else if (ourIndex > -1) { + replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); + } else { + ourIndex = doc.sel.ranges.length; + setSelection(doc, normalizeSelection(doc.sel.ranges.concat([ourRange]), ourIndex), + {scroll: false, origin: "*mouse"}); + } + + var lastPos = start; + function extendTo(pos) { + if (cmp(lastPos, pos) == 0) return; + lastPos = pos; + + if (type == "rect") { + var ranges = [], tabSize = cm.options.tabSize; + var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); + var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); + var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); + for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); + line <= end; line++) { + var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); + if (left == right) + ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); + else if (text.length > leftPos) + ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); + } + if (!ranges.length) ranges.push(new Range(start, start)); + setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), + {origin: "*mouse", scroll: false}); + cm.scrollIntoView(pos); + } else { + var oldRange = ourRange; + var anchor = oldRange.anchor, head = pos; + if (type != "single") { + if (type == "double") + var range = findWordAt(cm, pos); + else + var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))); + if (cmp(range.anchor, anchor) > 0) { + head = range.head; + anchor = minPos(oldRange.from(), range.anchor); + } else { + head = range.anchor; + anchor = maxPos(oldRange.to(), range.head); + } + } + var ranges = startSel.ranges.slice(0); + ranges[ourIndex] = new Range(clipPos(doc, anchor), head); + setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse); + } + } + + var editorSize = display.wrapper.getBoundingClientRect(); + // Used to ensure timeout re-tries don't fire when another extend + // happened in the meantime (clearTimeout isn't reliable -- at + // least on Chrome, the timeouts still happen even when cleared, + // if the clear happens after their scheduled firing time). + var counter = 0; + + function extend(e) { + var curCount = ++counter; + var cur = posFromMouse(cm, e, true, type == "rect"); + if (!cur) return; + if (cmp(cur, lastPos) != 0) { + ensureFocus(cm); + extendTo(cur); + var visible = visibleLines(display, doc); + if (cur.line >= visible.to || cur.line < visible.from) + setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150); + } else { + var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; + if (outside) setTimeout(operation(cm, function() { + if (counter != curCount) return; + display.scroller.scrollTop += outside; + extend(e); + }), 50); + } + } + + function done(e) { + counter = Infinity; + e_preventDefault(e); + focusInput(cm); + off(document, "mousemove", move); + off(document, "mouseup", up); + doc.history.lastSelOrigin = null; + } + + var move = operation(cm, function(e) { + if (!e_button(e)) done(e); + else extend(e); + }); + var up = operation(cm, done); + on(document, "mousemove", move); + on(document, "mouseup", up); + } + + // Determines whether an event happened in the gutter, and fires the + // handlers for the corresponding event. + function gutterEvent(cm, e, type, prevent, signalfn) { + try { var mX = e.clientX, mY = e.clientY; } + catch(e) { return false; } + if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false; + if (prevent) e_preventDefault(e); + + var display = cm.display; + var lineBox = display.lineDiv.getBoundingClientRect(); + + if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e); + mY -= lineBox.top - display.viewOffset; + + for (var i = 0; i < cm.options.gutters.length; ++i) { + var g = display.gutters.childNodes[i]; + if (g && g.getBoundingClientRect().right >= mX) { + var line = lineAtHeight(cm.doc, mY); + var gutter = cm.options.gutters[i]; + signalfn(cm, type, cm, line, gutter, e); + return e_defaultPrevented(e); + } + } + } + + function clickInGutter(cm, e) { + return gutterEvent(cm, e, "gutterClick", true, signalLater); + } + + // Kludge to work around strange IE behavior where it'll sometimes + // re-fire a series of drag-related events right after the drop (#1551) + var lastDrop = 0; + + function onDrop(e) { + var cm = this; + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) + return; + e_preventDefault(e); + if (ie) lastDrop = +new Date; + var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; + if (!pos || isReadOnly(cm)) return; + // Might be a file drop, in which case we simply extract the text + // and insert it. + if (files && files.length && window.FileReader && window.File) { + var n = files.length, text = Array(n), read = 0; + var loadFile = function(file, i) { + var reader = new FileReader; + reader.onload = operation(cm, function() { + text[i] = reader.result; + if (++read == n) { + pos = clipPos(cm.doc, pos); + var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"}; + makeChange(cm.doc, change); + setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); + } + }); + reader.readAsText(file); + }; + for (var i = 0; i < n; ++i) loadFile(files[i], i); + } else { // Normal drop + // Don't do a replace if the drop happened inside of the selected text. + if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { + cm.state.draggingText(e); + // Ensure the editor is re-focused + setTimeout(bind(focusInput, cm), 20); + return; + } + try { + var text = e.dataTransfer.getData("Text"); + if (text) { + if (cm.state.draggingText && !(mac ? e.metaKey : e.ctrlKey)) + var selected = cm.listSelections(); + setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); + if (selected) for (var i = 0; i < selected.length; ++i) + replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag"); + cm.replaceSelection(text, "around", "paste"); + focusInput(cm); + } + } + catch(e){} + } + } + + function onDragStart(cm, e) { + if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; } + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; + + e.dataTransfer.setData("Text", cm.getSelection()); + + // Use dummy image instead of default browsers image. + // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. + if (e.dataTransfer.setDragImage && !safari) { + var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); + img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; + if (presto) { + img.width = img.height = 1; + cm.display.wrapper.appendChild(img); + // Force a relayout, or Opera won't use our image for some obscure reason + img._top = img.offsetTop; + } + e.dataTransfer.setDragImage(img, 0, 0); + if (presto) img.parentNode.removeChild(img); + } + } + + // SCROLL EVENTS + + // Sync the scrollable area and scrollbars, ensure the viewport + // covers the visible area. + function setScrollTop(cm, val) { + if (Math.abs(cm.doc.scrollTop - val) < 2) return; + cm.doc.scrollTop = val; + if (!gecko) updateDisplay(cm, {top: val}); + if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; + if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val; + if (gecko) updateDisplay(cm); + startWorker(cm, 100); + } + // Sync scroller and scrollbar, ensure the gutter elements are + // aligned. + function setScrollLeft(cm, val, isScroller) { + if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return; + val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); + cm.doc.scrollLeft = val; + alignHorizontally(cm); + if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val; + if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val; + } + + // Since the delta values reported on mouse wheel events are + // unstandardized between browsers and even browser versions, and + // generally horribly unpredictable, this code starts by measuring + // the scroll effect that the first few mouse wheel events have, + // and, from that, detects the way it can convert deltas to pixel + // offsets afterwards. + // + // The reason we want to know the amount a wheel event will scroll + // is that it gives us a chance to update the display before the + // actual scrolling happens, reducing flickering. + + var wheelSamples = 0, wheelPixelsPerUnit = null; + // Fill in a browser-detected starting value on browsers where we + // know one. These don't have to be accurate -- the result of them + // being wrong would just be a slight flicker on the first wheel + // scroll (if it is large enough). + if (ie) wheelPixelsPerUnit = -.53; + else if (gecko) wheelPixelsPerUnit = 15; + else if (chrome) wheelPixelsPerUnit = -.7; + else if (safari) wheelPixelsPerUnit = -1/3; + + function onScrollWheel(cm, e) { + var dx = e.wheelDeltaX, dy = e.wheelDeltaY; + if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail; + if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail; + else if (dy == null) dy = e.wheelDelta; + + var display = cm.display, scroll = display.scroller; + // Quit if there's nothing to scroll here + if (!(dx && scroll.scrollWidth > scroll.clientWidth || + dy && scroll.scrollHeight > scroll.clientHeight)) return; + + // Webkit browsers on OS X abort momentum scrolls when the target + // of the scroll event is removed from the scrollable element. + // This hack (see related code in patchDisplay) makes sure the + // element is kept around. + if (dy && mac && webkit) { + outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { + for (var i = 0; i < view.length; i++) { + if (view[i].node == cur) { + cm.display.currentWheelTarget = cur; + break outer; + } + } + } + } + + // On some browsers, horizontal scrolling will cause redraws to + // happen before the gutter has been realigned, causing it to + // wriggle around in a most unseemly way. When we have an + // estimated pixels/delta value, we just handle horizontal + // scrolling entirely here. It'll be slightly off from native, but + // better than glitching out. + if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { + if (dy) + setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); + setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); + e_preventDefault(e); + display.wheelStartX = null; // Abort measurement, if in progress + return; + } + + // 'Project' the visible viewport to cover the area that is being + // scrolled into view (if we know enough to estimate it). + if (dy && wheelPixelsPerUnit != null) { + var pixels = dy * wheelPixelsPerUnit; + var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; + if (pixels < 0) top = Math.max(0, top + pixels - 50); + else bot = Math.min(cm.doc.height, bot + pixels + 50); + updateDisplay(cm, {top: top, bottom: bot}); + } + + if (wheelSamples < 20) { + if (display.wheelStartX == null) { + display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; + display.wheelDX = dx; display.wheelDY = dy; + setTimeout(function() { + if (display.wheelStartX == null) return; + var movedX = scroll.scrollLeft - display.wheelStartX; + var movedY = scroll.scrollTop - display.wheelStartY; + var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || + (movedX && display.wheelDX && movedX / display.wheelDX); + display.wheelStartX = display.wheelStartY = null; + if (!sample) return; + wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); + ++wheelSamples; + }, 200); + } else { + display.wheelDX += dx; display.wheelDY += dy; + } + } + } + + // KEY EVENTS + + // Run a handler that was bound to a key. + function doHandleBinding(cm, bound, dropShift) { + if (typeof bound == "string") { + bound = commands[bound]; + if (!bound) return false; + } + // Ensure previous input has been read, so that the handler sees a + // consistent view of the document + if (cm.display.pollingFast && readInput(cm)) cm.display.pollingFast = false; + var prevShift = cm.display.shift, done = false; + try { + if (isReadOnly(cm)) cm.state.suppressEdits = true; + if (dropShift) cm.display.shift = false; + done = bound(cm) != Pass; + } finally { + cm.display.shift = prevShift; + cm.state.suppressEdits = false; + } + return done; + } + + // Collect the currently active keymaps. + function allKeyMaps(cm) { + var maps = cm.state.keyMaps.slice(0); + if (cm.options.extraKeys) maps.push(cm.options.extraKeys); + maps.push(cm.options.keyMap); + return maps; + } + + var maybeTransition; + // Handle a key from the keydown event. + function handleKeyBinding(cm, e) { + // Handle automatic keymap transitions + var startMap = getKeyMap(cm.options.keyMap), next = startMap.auto; + clearTimeout(maybeTransition); + if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() { + if (getKeyMap(cm.options.keyMap) == startMap) { + cm.options.keyMap = (next.call ? next.call(null, cm) : next); + keyMapChanged(cm); + } + }, 50); + + var name = keyName(e, true), handled = false; + if (!name) return false; + var keymaps = allKeyMaps(cm); + + if (e.shiftKey) { + // First try to resolve full name (including 'Shift-'). Failing + // that, see if there is a cursor-motion command (starting with + // 'go') bound to the keyname without 'Shift-'. + handled = lookupKey("Shift-" + name, keymaps, function(b) {return doHandleBinding(cm, b, true);}) + || lookupKey(name, keymaps, function(b) { + if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) + return doHandleBinding(cm, b); + }); + } else { + handled = lookupKey(name, keymaps, function(b) { return doHandleBinding(cm, b); }); + } + + if (handled) { + e_preventDefault(e); + restartBlink(cm); + signalLater(cm, "keyHandled", cm, name, e); + } + return handled; + } + + // Handle a key from the keypress event + function handleCharBinding(cm, e, ch) { + var handled = lookupKey("'" + ch + "'", allKeyMaps(cm), + function(b) { return doHandleBinding(cm, b, true); }); + if (handled) { + e_preventDefault(e); + restartBlink(cm); + signalLater(cm, "keyHandled", cm, "'" + ch + "'", e); + } + return handled; + } + + var lastStoppedKey = null; + function onKeyDown(e) { + var cm = this; + ensureFocus(cm); + if (signalDOMEvent(cm, e)) return; + // IE does strange things with escape. + if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false; + var code = e.keyCode; + cm.display.shift = code == 16 || e.shiftKey; + var handled = handleKeyBinding(cm, e); + if (presto) { + lastStoppedKey = handled ? code : null; + // Opera has no cut event... we try to at least catch the key combo + if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) + cm.replaceSelection("", null, "cut"); + } + + // Turn mouse into crosshair when Alt is held on Mac. + if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) + showCrossHair(cm); + } + + function showCrossHair(cm) { + var lineDiv = cm.display.lineDiv; + addClass(lineDiv, "CodeMirror-crosshair"); + + function up(e) { + if (e.keyCode == 18 || !e.altKey) { + rmClass(lineDiv, "CodeMirror-crosshair"); + off(document, "keyup", up); + off(document, "mouseover", up); + } + } + on(document, "keyup", up); + on(document, "mouseover", up); + } + + function onKeyUp(e) { + if (signalDOMEvent(this, e)) return; + if (e.keyCode == 16) this.doc.sel.shift = false; + } + + function onKeyPress(e) { + var cm = this; + if (signalDOMEvent(cm, e) || e.ctrlKey || mac && e.metaKey) return; + var keyCode = e.keyCode, charCode = e.charCode; + if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} + if (((presto && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return; + var ch = String.fromCharCode(charCode == null ? keyCode : charCode); + if (handleCharBinding(cm, e, ch)) return; + if (ie && ie_version >= 9) cm.display.inputHasSelection = null; + fastPoll(cm); + } + + // FOCUS/BLUR EVENTS + + function onFocus(cm) { + if (cm.options.readOnly == "nocursor") return; + if (!cm.state.focused) { + signal(cm, "focus", cm); + cm.state.focused = true; + addClass(cm.display.wrapper, "CodeMirror-focused"); + // The prevInput test prevents this from firing when a context + // menu is closed (since the resetInput would kill the + // select-all detection hack) + if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { + resetInput(cm); + if (webkit) setTimeout(bind(resetInput, cm, true), 0); // Issue #1730 + } + } + slowPoll(cm); + restartBlink(cm); + } + function onBlur(cm) { + if (cm.state.focused) { + signal(cm, "blur", cm); + cm.state.focused = false; + rmClass(cm.display.wrapper, "CodeMirror-focused"); + } + clearInterval(cm.display.blinker); + setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150); + } + + // CONTEXT MENU HANDLING + + // To make the context menu work, we need to briefly unhide the + // textarea (making it as unobtrusive as possible) to let the + // right-click take effect on it. + function onContextMenu(cm, e) { + if (signalDOMEvent(cm, e, "contextmenu")) return; + var display = cm.display; + if (eventInWidget(display, e) || contextMenuInGutter(cm, e)) return; + + var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; + if (!pos || presto) return; // Opera is difficult. + + // Reset the current text selection only if the click is done outside of the selection + // and 'resetSelectionOnContextMenu' option is true. + var reset = cm.options.resetSelectionOnContextMenu; + if (reset && cm.doc.sel.contains(pos) == -1) + operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); + + var oldCSS = display.input.style.cssText; + display.inputDiv.style.position = "absolute"; + display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + + "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " + + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; + focusInput(cm); + resetInput(cm); + // Adds "Select all" to context menu in FF + if (!cm.somethingSelected()) display.input.value = display.prevInput = " "; + display.selForContextMenu = cm.doc.sel; + clearTimeout(display.detectingSelectAll); + + // Select-all will be greyed out if there's nothing to select, so + // this adds a zero-width space so that we can later check whether + // it got selected. + function prepareSelectAllHack() { + if (display.input.selectionStart != null) { + var selected = cm.somethingSelected(); + var extval = display.input.value = "\u200b" + (selected ? display.input.value : ""); + display.prevInput = selected ? "" : "\u200b"; + display.input.selectionStart = 1; display.input.selectionEnd = extval.length; + // Re-set this, in case some other handler touched the + // selection in the meantime. + display.selForContextMenu = cm.doc.sel; + } + } + function rehide() { + display.inputDiv.style.position = "relative"; + display.input.style.cssText = oldCSS; + if (ie && ie_version < 9) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos; + slowPoll(cm); + + // Try to detect the user choosing select-all + if (display.input.selectionStart != null) { + if (!ie || (ie && ie_version < 9)) prepareSelectAllHack(); + var i = 0, poll = function() { + if (display.selForContextMenu == cm.doc.sel && display.input.selectionStart == 0) + operation(cm, commands.selectAll)(cm); + else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500); + else resetInput(cm); + }; + display.detectingSelectAll = setTimeout(poll, 200); + } + } + + if (ie && ie_version >= 9) prepareSelectAllHack(); + if (captureRightClick) { + e_stop(e); + var mouseup = function() { + off(window, "mouseup", mouseup); + setTimeout(rehide, 20); + }; + on(window, "mouseup", mouseup); + } else { + setTimeout(rehide, 50); + } + } + + function contextMenuInGutter(cm, e) { + if (!hasHandler(cm, "gutterContextMenu")) return false; + return gutterEvent(cm, e, "gutterContextMenu", false, signal); + } + + // UPDATING + + // Compute the position of the end of a change (its 'to' property + // refers to the pre-change end). + var changeEnd = CodeMirror.changeEnd = function(change) { + if (!change.text) return change.to; + return Pos(change.from.line + change.text.length - 1, + lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); + }; + + // Adjust a position to refer to the post-change position of the + // same text, or the end of the change if the change covers it. + function adjustForChange(pos, change) { + if (cmp(pos, change.from) < 0) return pos; + if (cmp(pos, change.to) <= 0) return changeEnd(change); + + var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; + if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch; + return Pos(line, ch); + } + + function computeSelAfterChange(doc, change) { + var out = []; + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + out.push(new Range(adjustForChange(range.anchor, change), + adjustForChange(range.head, change))); + } + return normalizeSelection(out, doc.sel.primIndex); + } + + function offsetPos(pos, old, nw) { + if (pos.line == old.line) + return Pos(nw.line, pos.ch - old.ch + nw.ch); + else + return Pos(nw.line + (pos.line - old.line), pos.ch); + } + + // Used by replaceSelections to allow moving the selection to the + // start or around the replaced test. Hint may be "start" or "around". + function computeReplacedSel(doc, changes, hint) { + var out = []; + var oldPrev = Pos(doc.first, 0), newPrev = oldPrev; + for (var i = 0; i < changes.length; i++) { + var change = changes[i]; + var from = offsetPos(change.from, oldPrev, newPrev); + var to = offsetPos(changeEnd(change), oldPrev, newPrev); + oldPrev = change.to; + newPrev = to; + if (hint == "around") { + var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0; + out[i] = new Range(inv ? to : from, inv ? from : to); + } else { + out[i] = new Range(from, from); + } + } + return new Selection(out, doc.sel.primIndex); + } + + // Allow "beforeChange" event handlers to influence a change + function filterChange(doc, change, update) { + var obj = { + canceled: false, + from: change.from, + to: change.to, + text: change.text, + origin: change.origin, + cancel: function() { this.canceled = true; } + }; + if (update) obj.update = function(from, to, text, origin) { + if (from) this.from = clipPos(doc, from); + if (to) this.to = clipPos(doc, to); + if (text) this.text = text; + if (origin !== undefined) this.origin = origin; + }; + signal(doc, "beforeChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); + + if (obj.canceled) return null; + return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}; + } + + // Apply a change to a document, and add it to the document's + // history, and propagating it to all linked documents. + function makeChange(doc, change, ignoreReadOnly) { + if (doc.cm) { + if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly); + if (doc.cm.state.suppressEdits) return; + } + + if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { + change = filterChange(doc, change, true); + if (!change) return; + } + + // Possibly split or suppress the update based on the presence + // of read-only spans in its range. + var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); + if (split) { + for (var i = split.length - 1; i >= 0; --i) + makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}); + } else { + makeChangeInner(doc, change); + } + } + + function makeChangeInner(doc, change) { + if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return; + var selAfter = computeSelAfterChange(doc, change); + addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); + + makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); + var rebased = []; + + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); + }); + } + + // Revert a change stored in a document's history. + function makeChangeFromHistory(doc, type, allowSelectionOnly) { + if (doc.cm && doc.cm.state.suppressEdits) return; + + var hist = doc.history, event, selAfter = doc.sel; + var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done; + + // Verify that there is a useable event (so that ctrl-z won't + // needlessly clear selection events) + for (var i = 0; i < source.length; i++) { + event = source[i]; + if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) + break; + } + if (i == source.length) return; + hist.lastOrigin = hist.lastSelOrigin = null; + + for (;;) { + event = source.pop(); + if (event.ranges) { + pushSelectionToHistory(event, dest); + if (allowSelectionOnly && !event.equals(doc.sel)) { + setSelection(doc, event, {clearRedo: false}); + return; + } + selAfter = event; + } + else break; + } + + // Build up a reverse change object to add to the opposite history + // stack (redo when undoing, and vice versa). + var antiChanges = []; + pushSelectionToHistory(selAfter, dest); + dest.push({changes: antiChanges, generation: hist.generation}); + hist.generation = event.generation || ++hist.maxGeneration; + + var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); + + for (var i = event.changes.length - 1; i >= 0; --i) { + var change = event.changes[i]; + change.origin = type; + if (filter && !filterChange(doc, change, false)) { + source.length = 0; + return; + } + + antiChanges.push(historyChangeFromChange(doc, change)); + + var after = i ? computeSelAfterChange(doc, change, null) : lst(source); + makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); + if (!i && doc.cm) doc.cm.scrollIntoView(change); + var rebased = []; + + // Propagate to the linked documents + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); + }); + } + } + + // Sub-views need their line numbers shifted when text is added + // above or below them in the parent document. + function shiftDoc(doc, distance) { + if (distance == 0) return; + doc.first += distance; + doc.sel = new Selection(map(doc.sel.ranges, function(range) { + return new Range(Pos(range.anchor.line + distance, range.anchor.ch), + Pos(range.head.line + distance, range.head.ch)); + }), doc.sel.primIndex); + if (doc.cm) { + regChange(doc.cm, doc.first, doc.first - distance, distance); + for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) + regLineChange(doc.cm, l, "gutter"); + } + } + + // More lower-level change function, handling only a single document + // (not linked ones). + function makeChangeSingleDoc(doc, change, selAfter, spans) { + if (doc.cm && !doc.cm.curOp) + return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans); + + if (change.to.line < doc.first) { + shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); + return; + } + if (change.from.line > doc.lastLine()) return; + + // Clip the change to the size of this doc + if (change.from.line < doc.first) { + var shift = change.text.length - 1 - (doc.first - change.from.line); + shiftDoc(doc, shift); + change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), + text: [lst(change.text)], origin: change.origin}; + } + var last = doc.lastLine(); + if (change.to.line > last) { + change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), + text: [change.text[0]], origin: change.origin}; + } + + change.removed = getBetween(doc, change.from, change.to); + + if (!selAfter) selAfter = computeSelAfterChange(doc, change, null); + if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans); + else updateDoc(doc, change, spans); + setSelectionNoUndo(doc, selAfter, sel_dontScroll); + } + + // Handle the interaction of a change to a document with the editor + // that this document is part of. + function makeChangeSingleDocInEditor(cm, change, spans) { + var doc = cm.doc, display = cm.display, from = change.from, to = change.to; + + var recomputeMaxLength = false, checkWidthStart = from.line; + if (!cm.options.lineWrapping) { + checkWidthStart = lineNo(visualLine(getLine(doc, from.line))); + doc.iter(checkWidthStart, to.line + 1, function(line) { + if (line == display.maxLine) { + recomputeMaxLength = true; + return true; + } + }); + } + + if (doc.sel.contains(change.from, change.to) > -1) + signalCursorActivity(cm); + + updateDoc(doc, change, spans, estimateHeight(cm)); + + if (!cm.options.lineWrapping) { + doc.iter(checkWidthStart, from.line + change.text.length, function(line) { + var len = lineLength(line); + if (len > display.maxLineLength) { + display.maxLine = line; + display.maxLineLength = len; + display.maxLineChanged = true; + recomputeMaxLength = false; + } + }); + if (recomputeMaxLength) cm.curOp.updateMaxLine = true; + } + + // Adjust frontier, schedule worker + doc.frontier = Math.min(doc.frontier, from.line); + startWorker(cm, 400); + + var lendiff = change.text.length - (to.line - from.line) - 1; + // Remember that these lines changed, for updating the display + if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) + regLineChange(cm, from.line, "text"); + else + regChange(cm, from.line, to.line + 1, lendiff); + + var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change"); + if (changeHandler || changesHandler) { + var obj = { + from: from, to: to, + text: change.text, + removed: change.removed, + origin: change.origin + }; + if (changeHandler) signalLater(cm, "change", cm, obj); + if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); + } + cm.display.selForContextMenu = null; + } + + function replaceRange(doc, code, from, to, origin) { + if (!to) to = from; + if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } + if (typeof code == "string") code = splitLines(code); + makeChange(doc, {from: from, to: to, text: code, origin: origin}); + } + + // SCROLLING THINGS INTO VIEW + + // If an editor sits on the top or bottom of the window, partially + // scrolled out of view, this ensures that the cursor is visible. + function maybeScrollWindow(cm, coords) { + var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; + if (coords.top + box.top < 0) doScroll = true; + else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; + if (doScroll != null && !phantom) { + var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + + (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " + + (coords.bottom - coords.top + scrollerCutOff) + "px; left: " + + coords.left + "px; width: 2px;"); + cm.display.lineSpace.appendChild(scrollNode); + scrollNode.scrollIntoView(doScroll); + cm.display.lineSpace.removeChild(scrollNode); + } + } + + // Scroll a given position into view (immediately), verifying that + // it actually became visible (as line heights are accurately + // measured, the position of something may 'drift' during drawing). + function scrollPosIntoView(cm, pos, end, margin) { + if (margin == null) margin = 0; + for (;;) { + var changed = false, coords = cursorCoords(cm, pos); + var endCoords = !end || end == pos ? coords : cursorCoords(cm, end); + var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left), + Math.min(coords.top, endCoords.top) - margin, + Math.max(coords.left, endCoords.left), + Math.max(coords.bottom, endCoords.bottom) + margin); + var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; + if (scrollPos.scrollTop != null) { + setScrollTop(cm, scrollPos.scrollTop); + if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true; + } + if (scrollPos.scrollLeft != null) { + setScrollLeft(cm, scrollPos.scrollLeft); + if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; + } + if (!changed) return coords; + } + } + + // Scroll a given set of coordinates into view (immediately). + function scrollIntoView(cm, x1, y1, x2, y2) { + var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2); + if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop); + if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft); + } + + // Calculate a new scroll position needed to scroll the given + // rectangle into view. Returns an object with scrollTop and + // scrollLeft properties. When these are undefined, the + // vertical/horizontal position does not need to be adjusted. + function calculateScrollPos(cm, x1, y1, x2, y2) { + var display = cm.display, snapMargin = textHeight(cm.display); + if (y1 < 0) y1 = 0; + var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop; + var screen = display.scroller.clientHeight - scrollerCutOff, result = {}; + var docBottom = cm.doc.height + paddingVert(display); + var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin; + if (y1 < screentop) { + result.scrollTop = atTop ? 0 : y1; + } else if (y2 > screentop + screen) { + var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen); + if (newTop != screentop) result.scrollTop = newTop; + } + + var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; + var screenw = display.scroller.clientWidth - scrollerCutOff; + x1 += display.gutters.offsetWidth; x2 += display.gutters.offsetWidth; + var gutterw = display.gutters.offsetWidth; + var atLeft = x1 < gutterw + 10; + if (x1 < screenleft + gutterw || atLeft) { + if (atLeft) x1 = 0; + result.scrollLeft = Math.max(0, x1 - 10 - gutterw); + } else if (x2 > screenw + screenleft - 3) { + result.scrollLeft = x2 + 10 - screenw; + } + return result; + } + + // Store a relative adjustment to the scroll position in the current + // operation (to be applied when the operation finishes). + function addToScrollPos(cm, left, top) { + if (left != null || top != null) resolveScrollToPos(cm); + if (left != null) + cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left; + if (top != null) + cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top; + } + + // Make sure that at the end of the operation the current cursor is + // shown. + function ensureCursorVisible(cm) { + resolveScrollToPos(cm); + var cur = cm.getCursor(), from = cur, to = cur; + if (!cm.options.lineWrapping) { + from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur; + to = Pos(cur.line, cur.ch + 1); + } + cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true}; + } + + // When an operation has its scrollToPos property set, and another + // scroll action is applied before the end of the operation, this + // 'simulates' scrolling that position into view in a cheap way, so + // that the effect of intermediate scroll commands is not ignored. + function resolveScrollToPos(cm) { + var range = cm.curOp.scrollToPos; + if (range) { + cm.curOp.scrollToPos = null; + var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); + var sPos = calculateScrollPos(cm, Math.min(from.left, to.left), + Math.min(from.top, to.top) - range.margin, + Math.max(from.right, to.right), + Math.max(from.bottom, to.bottom) + range.margin); + cm.scrollTo(sPos.scrollLeft, sPos.scrollTop); + } + } + + // API UTILITIES + + // Indent the given line. The how parameter can be "smart", + // "add"/null, "subtract", or "prev". When aggressive is false + // (typically set to true for forced single-line indents), empty + // lines are not indented, and places where the mode returns Pass + // are left alone. + function indentLine(cm, n, how, aggressive) { + var doc = cm.doc, state; + if (how == null) how = "add"; + if (how == "smart") { + // Fall back to "prev" when the mode doesn't have an indentation + // method. + if (!cm.doc.mode.indent) how = "prev"; + else state = getStateBefore(cm, n); + } + + var tabSize = cm.options.tabSize; + var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); + if (line.stateAfter) line.stateAfter = null; + var curSpaceString = line.text.match(/^\s*/)[0], indentation; + if (!aggressive && !/\S/.test(line.text)) { + indentation = 0; + how = "not"; + } else if (how == "smart") { + indentation = cm.doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); + if (indentation == Pass) { + if (!aggressive) return; + how = "prev"; + } + } + if (how == "prev") { + if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize); + else indentation = 0; + } else if (how == "add") { + indentation = curSpace + cm.options.indentUnit; + } else if (how == "subtract") { + indentation = curSpace - cm.options.indentUnit; + } else if (typeof how == "number") { + indentation = curSpace + how; + } + indentation = Math.max(0, indentation); + + var indentString = "", pos = 0; + if (cm.options.indentWithTabs) + for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} + if (pos < indentation) indentString += spaceStr(indentation - pos); + + if (indentString != curSpaceString) { + replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); + } else { + // Ensure that, if the cursor was in the whitespace at the start + // of the line, it is moved to the end of that space. + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + if (range.head.line == n && range.head.ch < curSpaceString.length) { + var pos = Pos(n, curSpaceString.length); + replaceOneSelection(doc, i, new Range(pos, pos)); + break; + } + } + } + line.stateAfter = null; + } + + // Utility for applying a change to a line by handle or number, + // returning the number and optionally registering the line as + // changed. + function changeLine(doc, handle, changeType, op) { + var no = handle, line = handle; + if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); + else no = lineNo(handle); + if (no == null) return null; + if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType); + return line; + } + + // Helper for deleting text near the selection(s), used to implement + // backspace, delete, and similar functionality. + function deleteNearSelection(cm, compute) { + var ranges = cm.doc.sel.ranges, kill = []; + // Build up a set of ranges to kill first, merging overlapping + // ranges. + for (var i = 0; i < ranges.length; i++) { + var toKill = compute(ranges[i]); + while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { + var replaced = kill.pop(); + if (cmp(replaced.from, toKill.from) < 0) { + toKill.from = replaced.from; + break; + } + } + kill.push(toKill); + } + // Next, remove those actual ranges. + runInOp(cm, function() { + for (var i = kill.length - 1; i >= 0; i--) + replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); + ensureCursorVisible(cm); + }); + } + + // Used for horizontal relative motion. Dir is -1 or 1 (left or + // right), unit can be "char", "column" (like char, but doesn't + // cross line boundaries), "word" (across next word), or "group" (to + // the start of next group of word or non-word-non-whitespace + // chars). The visually param controls whether, in right-to-left + // text, direction 1 means to move towards the next index in the + // string, or towards the character to the right of the current + // position. The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosH(doc, pos, dir, unit, visually) { + var line = pos.line, ch = pos.ch, origDir = dir; + var lineObj = getLine(doc, line); + var possible = true; + function findNextLine() { + var l = line + dir; + if (l < doc.first || l >= doc.first + doc.size) return (possible = false); + line = l; + return lineObj = getLine(doc, l); + } + function moveOnce(boundToLine) { + var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true); + if (next == null) { + if (!boundToLine && findNextLine()) { + if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); + else ch = dir < 0 ? lineObj.text.length : 0; + } else return (possible = false); + } else ch = next; + return true; + } + + if (unit == "char") moveOnce(); + else if (unit == "column") moveOnce(true); + else if (unit == "word" || unit == "group") { + var sawType = null, group = unit == "group"; + var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); + for (var first = true;; first = false) { + if (dir < 0 && !moveOnce(!first)) break; + var cur = lineObj.text.charAt(ch) || "\n"; + var type = isWordChar(cur, helper) ? "w" + : group && cur == "\n" ? "n" + : !group || /\s/.test(cur) ? null + : "p"; + if (group && !first && !type) type = "s"; + if (sawType && sawType != type) { + if (dir < 0) {dir = 1; moveOnce();} + break; + } + + if (type) sawType = type; + if (dir > 0 && !moveOnce(!first)) break; + } + } + var result = skipAtomic(doc, Pos(line, ch), origDir, true); + if (!possible) result.hitSide = true; + return result; + } + + // For relative vertical movement. Dir may be -1 or 1. Unit can be + // "page" or "line". The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosV(cm, pos, dir, unit) { + var doc = cm.doc, x = pos.left, y; + if (unit == "page") { + var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); + y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display)); + } else if (unit == "line") { + y = dir > 0 ? pos.bottom + 3 : pos.top - 3; + } + for (;;) { + var target = coordsChar(cm, x, y); + if (!target.outside) break; + if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } + y += dir * 5; + } + return target; + } + + // Find the word at the given position (as returned by coordsChar). + function findWordAt(cm, pos) { + var doc = cm.doc, line = getLine(doc, pos.line).text; + var start = pos.ch, end = pos.ch; + if (line) { + var helper = cm.getHelper(pos, "wordChars"); + if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; + var startChar = line.charAt(start); + var check = isWordChar(startChar, helper) + ? function(ch) { return isWordChar(ch, helper); } + : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} + : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; + while (start > 0 && check(line.charAt(start - 1))) --start; + while (end < line.length && check(line.charAt(end))) ++end; + } + return new Range(Pos(pos.line, start), Pos(pos.line, end)); + } + + // EDITOR METHODS + + // The publicly visible API. Note that methodOp(f) means + // 'wrap f in an operation, performed on its `this` parameter'. + + // This is not the complete set of editor methods. Most of the + // methods defined on the Doc type are also injected into + // CodeMirror.prototype, for backwards compatibility and + // convenience. + + CodeMirror.prototype = { + constructor: CodeMirror, + focus: function(){window.focus(); focusInput(this); fastPoll(this);}, + + setOption: function(option, value) { + var options = this.options, old = options[option]; + if (options[option] == value && option != "mode") return; + options[option] = value; + if (optionHandlers.hasOwnProperty(option)) + operation(this, optionHandlers[option])(this, value, old); + }, + + getOption: function(option) {return this.options[option];}, + getDoc: function() {return this.doc;}, + + addKeyMap: function(map, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](map); + }, + removeKeyMap: function(map) { + var maps = this.state.keyMaps; + for (var i = 0; i < maps.length; ++i) + if (maps[i] == map || (typeof maps[i] != "string" && maps[i].name == map)) { + maps.splice(i, 1); + return true; + } + }, + + addOverlay: methodOp(function(spec, options) { + var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); + if (mode.startState) throw new Error("Overlays may not be stateful."); + this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque}); + this.state.modeGen++; + regChange(this); + }), + removeOverlay: methodOp(function(spec) { + var overlays = this.state.overlays; + for (var i = 0; i < overlays.length; ++i) { + var cur = overlays[i].modeSpec; + if (cur == spec || typeof spec == "string" && cur.name == spec) { + overlays.splice(i, 1); + this.state.modeGen++; + regChange(this); + return; + } + } + }), + + indentLine: methodOp(function(n, dir, aggressive) { + if (typeof dir != "string" && typeof dir != "number") { + if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; + else dir = dir ? "add" : "subtract"; + } + if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); + }), + indentSelection: methodOp(function(how) { + var ranges = this.doc.sel.ranges, end = -1; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (!range.empty()) { + var start = Math.max(end, range.from().line); + var to = range.to(); + end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; + for (var j = start; j < end; ++j) + indentLine(this, j, how); + } else if (range.head.line > end) { + indentLine(this, range.head.line, how, true); + end = range.head.line; + if (i == this.doc.sel.primIndex) ensureCursorVisible(this); + } + } + }), + + // Fetch the parser token for a given character. Useful for hacks + // that want to inspect the mode state (say, for completion). + getTokenAt: function(pos, precise) { + var doc = this.doc; + pos = clipPos(doc, pos); + var state = getStateBefore(this, pos.line, precise), mode = this.doc.mode; + var line = getLine(doc, pos.line); + var stream = new StringStream(line.text, this.options.tabSize); + while (stream.pos < pos.ch && !stream.eol()) { + stream.start = stream.pos; + var style = readToken(mode, stream, state); + } + return {start: stream.start, + end: stream.pos, + string: stream.current(), + type: style || null, + state: state}; + }, + + getTokenTypeAt: function(pos) { + pos = clipPos(this.doc, pos); + var styles = getLineStyles(this, getLine(this.doc, pos.line)); + var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; + var type; + if (ch == 0) type = styles[2]; + else for (;;) { + var mid = (before + after) >> 1; + if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; + else if (styles[mid * 2 + 1] < ch) before = mid + 1; + else { type = styles[mid * 2 + 2]; break; } + } + var cut = type ? type.indexOf("cm-overlay ") : -1; + return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1); + }, + + getModeAt: function(pos) { + var mode = this.doc.mode; + if (!mode.innerMode) return mode; + return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; + }, + + getHelper: function(pos, type) { + return this.getHelpers(pos, type)[0]; + }, + + getHelpers: function(pos, type) { + var found = []; + if (!helpers.hasOwnProperty(type)) return helpers; + var help = helpers[type], mode = this.getModeAt(pos); + if (typeof mode[type] == "string") { + if (help[mode[type]]) found.push(help[mode[type]]); + } else if (mode[type]) { + for (var i = 0; i < mode[type].length; i++) { + var val = help[mode[type][i]]; + if (val) found.push(val); + } + } else if (mode.helperType && help[mode.helperType]) { + found.push(help[mode.helperType]); + } else if (help[mode.name]) { + found.push(help[mode.name]); + } + for (var i = 0; i < help._global.length; i++) { + var cur = help._global[i]; + if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) + found.push(cur.val); + } + return found; + }, + + getStateAfter: function(line, precise) { + var doc = this.doc; + line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); + return getStateBefore(this, line + 1, precise); + }, + + cursorCoords: function(start, mode) { + var pos, range = this.doc.sel.primary(); + if (start == null) pos = range.head; + else if (typeof start == "object") pos = clipPos(this.doc, start); + else pos = start ? range.from() : range.to(); + return cursorCoords(this, pos, mode || "page"); + }, + + charCoords: function(pos, mode) { + return charCoords(this, clipPos(this.doc, pos), mode || "page"); + }, + + coordsChar: function(coords, mode) { + coords = fromCoordSystem(this, coords, mode || "page"); + return coordsChar(this, coords.left, coords.top); + }, + + lineAtHeight: function(height, mode) { + height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top; + return lineAtHeight(this.doc, height + this.display.viewOffset); + }, + heightAtLine: function(line, mode) { + var end = false, last = this.doc.first + this.doc.size - 1; + if (line < this.doc.first) line = this.doc.first; + else if (line > last) { line = last; end = true; } + var lineObj = getLine(this.doc, line); + return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top + + (end ? this.doc.height - heightAtLine(lineObj) : 0); + }, + + defaultTextHeight: function() { return textHeight(this.display); }, + defaultCharWidth: function() { return charWidth(this.display); }, + + setGutterMarker: methodOp(function(line, gutterID, value) { + return changeLine(this.doc, line, "gutter", function(line) { + var markers = line.gutterMarkers || (line.gutterMarkers = {}); + markers[gutterID] = value; + if (!value && isEmpty(markers)) line.gutterMarkers = null; + return true; + }); + }), + + clearGutter: methodOp(function(gutterID) { + var cm = this, doc = cm.doc, i = doc.first; + doc.iter(function(line) { + if (line.gutterMarkers && line.gutterMarkers[gutterID]) { + line.gutterMarkers[gutterID] = null; + regLineChange(cm, i, "gutter"); + if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null; + } + ++i; + }); + }), + + addLineWidget: methodOp(function(handle, node, options) { + return addLineWidget(this, handle, node, options); + }), + + removeLineWidget: function(widget) { widget.clear(); }, + + lineInfo: function(line) { + if (typeof line == "number") { + if (!isLine(this.doc, line)) return null; + var n = line; + line = getLine(this.doc, line); + if (!line) return null; + } else { + var n = lineNo(line); + if (n == null) return null; + } + return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, + textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, + widgets: line.widgets}; + }, + + getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};}, + + addWidget: function(pos, node, scroll, vert, horiz) { + var display = this.display; + pos = cursorCoords(this, clipPos(this.doc, pos)); + var top = pos.bottom, left = pos.left; + node.style.position = "absolute"; + display.sizer.appendChild(node); + if (vert == "over") { + top = pos.top; + } else if (vert == "above" || vert == "near") { + var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), + hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); + // Default to positioning above (if specified and possible); otherwise default to positioning below + if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) + top = pos.top - node.offsetHeight; + else if (pos.bottom + node.offsetHeight <= vspace) + top = pos.bottom; + if (left + node.offsetWidth > hspace) + left = hspace - node.offsetWidth; + } + node.style.top = top + "px"; + node.style.left = node.style.right = ""; + if (horiz == "right") { + left = display.sizer.clientWidth - node.offsetWidth; + node.style.right = "0px"; + } else { + if (horiz == "left") left = 0; + else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2; + node.style.left = left + "px"; + } + if (scroll) + scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight); + }, + + triggerOnKeyDown: methodOp(onKeyDown), + triggerOnKeyPress: methodOp(onKeyPress), + triggerOnKeyUp: methodOp(onKeyUp), + + execCommand: function(cmd) { + if (commands.hasOwnProperty(cmd)) + return commands[cmd](this); + }, + + findPosH: function(from, amount, unit, visually) { + var dir = 1; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + cur = findPosH(this.doc, cur, dir, unit, visually); + if (cur.hitSide) break; + } + return cur; + }, + + moveH: methodOp(function(dir, unit) { + var cm = this; + cm.extendSelectionsBy(function(range) { + if (cm.display.shift || cm.doc.extend || range.empty()) + return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually); + else + return dir < 0 ? range.from() : range.to(); + }, sel_move); + }), + + deleteH: methodOp(function(dir, unit) { + var sel = this.doc.sel, doc = this.doc; + if (sel.somethingSelected()) + doc.replaceSelection("", null, "+delete"); + else + deleteNearSelection(this, function(range) { + var other = findPosH(doc, range.head, dir, unit, false); + return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other}; + }); + }), + + findPosV: function(from, amount, unit, goalColumn) { + var dir = 1, x = goalColumn; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + var coords = cursorCoords(this, cur, "div"); + if (x == null) x = coords.left; + else coords.left = x; + cur = findPosV(this, coords, dir, unit); + if (cur.hitSide) break; + } + return cur; + }, + + moveV: methodOp(function(dir, unit) { + var cm = this, doc = this.doc, goals = []; + var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected(); + doc.extendSelectionsBy(function(range) { + if (collapse) + return dir < 0 ? range.from() : range.to(); + var headPos = cursorCoords(cm, range.head, "div"); + if (range.goalColumn != null) headPos.left = range.goalColumn; + goals.push(headPos.left); + var pos = findPosV(cm, headPos, dir, unit); + if (unit == "page" && range == doc.sel.primary()) + addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top); + return pos; + }, sel_move); + if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++) + doc.sel.ranges[i].goalColumn = goals[i]; + }), + + toggleOverwrite: function(value) { + if (value != null && value == this.state.overwrite) return; + if (this.state.overwrite = !this.state.overwrite) + addClass(this.display.cursorDiv, "CodeMirror-overwrite"); + else + rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); + + signal(this, "overwriteToggle", this, this.state.overwrite); + }, + hasFocus: function() { return activeElt() == this.display.input; }, + + scrollTo: methodOp(function(x, y) { + if (x != null || y != null) resolveScrollToPos(this); + if (x != null) this.curOp.scrollLeft = x; + if (y != null) this.curOp.scrollTop = y; + }), + getScrollInfo: function() { + var scroller = this.display.scroller, co = scrollerCutOff; + return {left: scroller.scrollLeft, top: scroller.scrollTop, + height: scroller.scrollHeight - co, width: scroller.scrollWidth - co, + clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co}; + }, + + scrollIntoView: methodOp(function(range, margin) { + if (range == null) { + range = {from: this.doc.sel.primary().head, to: null}; + if (margin == null) margin = this.options.cursorScrollMargin; + } else if (typeof range == "number") { + range = {from: Pos(range, 0), to: null}; + } else if (range.from == null) { + range = {from: range, to: null}; + } + if (!range.to) range.to = range.from; + range.margin = margin || 0; + + if (range.from.line != null) { + resolveScrollToPos(this); + this.curOp.scrollToPos = range; + } else { + var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left), + Math.min(range.from.top, range.to.top) - range.margin, + Math.max(range.from.right, range.to.right), + Math.max(range.from.bottom, range.to.bottom) + range.margin); + this.scrollTo(sPos.scrollLeft, sPos.scrollTop); + } + }), + + setSize: methodOp(function(width, height) { + var cm = this; + function interpret(val) { + return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; + } + if (width != null) cm.display.wrapper.style.width = interpret(width); + if (height != null) cm.display.wrapper.style.height = interpret(height); + if (cm.options.lineWrapping) clearLineMeasurementCache(this); + var lineNo = cm.display.viewFrom; + cm.doc.iter(lineNo, cm.display.viewTo, function(line) { + if (line.widgets) for (var i = 0; i < line.widgets.length; i++) + if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; } + ++lineNo; + }); + cm.curOp.forceUpdate = true; + signal(cm, "refresh", this); + }), + + operation: function(f){return runInOp(this, f);}, + + refresh: methodOp(function() { + var oldHeight = this.display.cachedTextHeight; + regChange(this); + this.curOp.forceUpdate = true; + clearCaches(this); + this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop); + updateGutterSpace(this); + if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) + estimateLineHeights(this); + signal(this, "refresh", this); + }), + + swapDoc: methodOp(function(doc) { + var old = this.doc; + old.cm = null; + attachDoc(this, doc); + clearCaches(this); + resetInput(this); + this.scrollTo(doc.scrollLeft, doc.scrollTop); + signalLater(this, "swapDoc", this, old); + return old; + }), + + getInputField: function(){return this.display.input;}, + getWrapperElement: function(){return this.display.wrapper;}, + getScrollerElement: function(){return this.display.scroller;}, + getGutterElement: function(){return this.display.gutters;} + }; + eventMixin(CodeMirror); + + // OPTION DEFAULTS + + // The default configuration options. + var defaults = CodeMirror.defaults = {}; + // Functions to run when options are changed. + var optionHandlers = CodeMirror.optionHandlers = {}; + + function option(name, deflt, handle, notOnInit) { + CodeMirror.defaults[name] = deflt; + if (handle) optionHandlers[name] = + notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle; + } + + // Passed to option handlers when there is no old value. + var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}}; + + // These two are, on init, called from the constructor because they + // have to be initialized before the editor can start at all. + option("value", "", function(cm, val) { + cm.setValue(val); + }, true); + option("mode", null, function(cm, val) { + cm.doc.modeOption = val; + loadMode(cm); + }, true); + + option("indentUnit", 2, loadMode, true); + option("indentWithTabs", false); + option("smartIndent", true); + option("tabSize", 4, function(cm) { + resetModeState(cm); + clearCaches(cm); + regChange(cm); + }, true); + option("specialChars", /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/g, function(cm, val) { + cm.options.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); + cm.refresh(); + }, true); + option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true); + option("electricChars", true); + option("rtlMoveVisually", !windows); + option("wholeLineUpdateBefore", true); + + option("theme", "default", function(cm) { + themeChanged(cm); + guttersChanged(cm); + }, true); + option("keyMap", "default", keyMapChanged); + option("extraKeys", null); + + option("lineWrapping", false, wrappingChanged, true); + option("gutters", [], function(cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("fixedGutter", true, function(cm, val) { + cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; + cm.refresh(); + }, true); + option("coverGutterNextToScrollbar", false, updateScrollbars, true); + option("lineNumbers", false, function(cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("firstLineNumber", 1, guttersChanged, true); + option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true); + option("showCursorWhenSelecting", false, updateSelection, true); + + option("resetSelectionOnContextMenu", true); + + option("readOnly", false, function(cm, val) { + if (val == "nocursor") { + onBlur(cm); + cm.display.input.blur(); + cm.display.disabled = true; + } else { + cm.display.disabled = false; + if (!val) resetInput(cm); + } + }); + option("disableInput", false, function(cm, val) {if (!val) resetInput(cm);}, true); + option("dragDrop", true); + + option("cursorBlinkRate", 530); + option("cursorScrollMargin", 0); + option("cursorHeight", 1, updateSelection, true); + option("singleCursorHeightPerLine", true, updateSelection, true); + option("workTime", 100); + option("workDelay", 100); + option("flattenSpans", true, resetModeState, true); + option("addModeClass", false, resetModeState, true); + option("pollInterval", 100); + option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;}); + option("historyEventDelay", 1250); + option("viewportMargin", 10, function(cm){cm.refresh();}, true); + option("maxHighlightLength", 10000, resetModeState, true); + option("moveInputWithCursor", true, function(cm, val) { + if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0; + }); + + option("tabindex", null, function(cm, val) { + cm.display.input.tabIndex = val || ""; + }); + option("autofocus", null); + + // MODE DEFINITION AND QUERYING + + // Known modes, by name and by MIME + var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; + + // Extra arguments are stored as the mode's dependencies, which is + // used by (legacy) mechanisms like loadmode.js to automatically + // load a mode. (Preferred mechanism is the require/define calls.) + CodeMirror.defineMode = function(name, mode) { + if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name; + if (arguments.length > 2) { + mode.dependencies = []; + for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]); + } + modes[name] = mode; + }; + + CodeMirror.defineMIME = function(mime, spec) { + mimeModes[mime] = spec; + }; + + // Given a MIME type, a {name, ...options} config object, or a name + // string, return a mode config object. + CodeMirror.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + var found = mimeModes[spec.name]; + if (typeof found == "string") found = {name: found}; + spec = createObj(found, spec); + spec.name = found.name; + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { + return CodeMirror.resolveMode("application/xml"); + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; + }; + + // Given a mode spec (anything that resolveMode accepts), find and + // initialize an actual mode object. + CodeMirror.getMode = function(options, spec) { + var spec = CodeMirror.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) return CodeMirror.getMode(options, "text/plain"); + var modeObj = mfactory(options, spec); + if (modeExtensions.hasOwnProperty(spec.name)) { + var exts = modeExtensions[spec.name]; + for (var prop in exts) { + if (!exts.hasOwnProperty(prop)) continue; + if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; + modeObj[prop] = exts[prop]; + } + } + modeObj.name = spec.name; + if (spec.helperType) modeObj.helperType = spec.helperType; + if (spec.modeProps) for (var prop in spec.modeProps) + modeObj[prop] = spec.modeProps[prop]; + + return modeObj; + }; + + // Minimal default mode. + CodeMirror.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; + }); + CodeMirror.defineMIME("text/plain", "null"); + + // This can be used to attach properties to mode objects from + // outside the actual mode definition. + var modeExtensions = CodeMirror.modeExtensions = {}; + CodeMirror.extendMode = function(mode, properties) { + var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); + copyObj(properties, exts); + }; + + // EXTENSIONS + + CodeMirror.defineExtension = function(name, func) { + CodeMirror.prototype[name] = func; + }; + CodeMirror.defineDocExtension = function(name, func) { + Doc.prototype[name] = func; + }; + CodeMirror.defineOption = option; + + var initHooks = []; + CodeMirror.defineInitHook = function(f) {initHooks.push(f);}; + + var helpers = CodeMirror.helpers = {}; + CodeMirror.registerHelper = function(type, name, value) { + if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []}; + helpers[type][name] = value; + }; + CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { + CodeMirror.registerHelper(type, name, value); + helpers[type]._global.push({pred: predicate, val: value}); + }; + + // MODE STATE HANDLING + + // Utility functions for working with state. Exported because nested + // modes need to do this for their inner modes. + + var copyState = CodeMirror.copyState = function(mode, state) { + if (state === true) return state; + if (mode.copyState) return mode.copyState(state); + var nstate = {}; + for (var n in state) { + var val = state[n]; + if (val instanceof Array) val = val.concat([]); + nstate[n] = val; + } + return nstate; + }; + + var startState = CodeMirror.startState = function(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; + }; + + // Given a mode and a state (for that mode), find the inner mode and + // state at the position that the state refers to. + CodeMirror.innerMode = function(mode, state) { + while (mode.innerMode) { + var info = mode.innerMode(state); + if (!info || info.mode == mode) break; + state = info.state; + mode = info.mode; + } + return info || {mode: mode, state: state}; + }; + + // STANDARD COMMANDS + + // Commands are parameter-less actions that can be performed on an + // editor, mostly used for keybindings. + var commands = CodeMirror.commands = { + selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);}, + singleSelection: function(cm) { + cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); + }, + killLine: function(cm) { + deleteNearSelection(cm, function(range) { + if (range.empty()) { + var len = getLine(cm.doc, range.head.line).text.length; + if (range.head.ch == len && range.head.line < cm.lastLine()) + return {from: range.head, to: Pos(range.head.line + 1, 0)}; + else + return {from: range.head, to: Pos(range.head.line, len)}; + } else { + return {from: range.from(), to: range.to()}; + } + }); + }, + deleteLine: function(cm) { + deleteNearSelection(cm, function(range) { + return {from: Pos(range.from().line, 0), + to: clipPos(cm.doc, Pos(range.to().line + 1, 0))}; + }); + }, + delLineLeft: function(cm) { + deleteNearSelection(cm, function(range) { + return {from: Pos(range.from().line, 0), to: range.from()}; + }); + }, + undo: function(cm) {cm.undo();}, + redo: function(cm) {cm.redo();}, + undoSelection: function(cm) {cm.undoSelection();}, + redoSelection: function(cm) {cm.redoSelection();}, + goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));}, + goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));}, + goLineStart: function(cm) { + cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); }, + {origin: "+move", bias: 1}); + }, + goLineStartSmart: function(cm) { + cm.extendSelectionsBy(function(range) { + var start = lineStart(cm, range.head.line); + var line = cm.getLineHandle(start.line); + var order = getOrder(line); + if (!order || order[0].level == 0) { + var firstNonWS = Math.max(0, line.text.search(/\S/)); + var inWS = range.head.line == start.line && range.head.ch <= firstNonWS && range.head.ch; + return Pos(start.line, inWS ? 0 : firstNonWS); + } + return start; + }, {origin: "+move", bias: 1}); + }, + goLineEnd: function(cm) { + cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); }, + {origin: "+move", bias: -1}); + }, + goLineRight: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); + }, sel_move); + }, + goLineLeft: function(cm) { + cm.extendSelectionsBy(function(range) { + var top = cm.charCoords(range.head, "div").top + 5; + return cm.coordsChar({left: 0, top: top}, "div"); + }, sel_move); + }, + goLineUp: function(cm) {cm.moveV(-1, "line");}, + goLineDown: function(cm) {cm.moveV(1, "line");}, + goPageUp: function(cm) {cm.moveV(-1, "page");}, + goPageDown: function(cm) {cm.moveV(1, "page");}, + goCharLeft: function(cm) {cm.moveH(-1, "char");}, + goCharRight: function(cm) {cm.moveH(1, "char");}, + goColumnLeft: function(cm) {cm.moveH(-1, "column");}, + goColumnRight: function(cm) {cm.moveH(1, "column");}, + goWordLeft: function(cm) {cm.moveH(-1, "word");}, + goGroupRight: function(cm) {cm.moveH(1, "group");}, + goGroupLeft: function(cm) {cm.moveH(-1, "group");}, + goWordRight: function(cm) {cm.moveH(1, "word");}, + delCharBefore: function(cm) {cm.deleteH(-1, "char");}, + delCharAfter: function(cm) {cm.deleteH(1, "char");}, + delWordBefore: function(cm) {cm.deleteH(-1, "word");}, + delWordAfter: function(cm) {cm.deleteH(1, "word");}, + delGroupBefore: function(cm) {cm.deleteH(-1, "group");}, + delGroupAfter: function(cm) {cm.deleteH(1, "group");}, + indentAuto: function(cm) {cm.indentSelection("smart");}, + indentMore: function(cm) {cm.indentSelection("add");}, + indentLess: function(cm) {cm.indentSelection("subtract");}, + insertTab: function(cm) {cm.replaceSelection("\t");}, + insertSoftTab: function(cm) { + var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].from(); + var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); + spaces.push(new Array(tabSize - col % tabSize + 1).join(" ")); + } + cm.replaceSelections(spaces); + }, + defaultTab: function(cm) { + if (cm.somethingSelected()) cm.indentSelection("add"); + else cm.execCommand("insertTab"); + }, + transposeChars: function(cm) { + runInOp(cm, function() { + var ranges = cm.listSelections(), newSel = []; + for (var i = 0; i < ranges.length; i++) { + var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; + if (line) { + if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1); + if (cur.ch > 0) { + cur = new Pos(cur.line, cur.ch + 1); + cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), + Pos(cur.line, cur.ch - 2), cur, "+transpose"); + } else if (cur.line > cm.doc.first) { + var prev = getLine(cm.doc, cur.line - 1).text; + if (prev) + cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1), + Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose"); + } + } + newSel.push(new Range(cur, cur)); + } + cm.setSelections(newSel); + }); + }, + newlineAndIndent: function(cm) { + runInOp(cm, function() { + var len = cm.listSelections().length; + for (var i = 0; i < len; i++) { + var range = cm.listSelections()[i]; + cm.replaceRange("\n", range.anchor, range.head, "+input"); + cm.indentLine(range.from().line + 1, null, true); + ensureCursorVisible(cm); + } + }); + }, + toggleOverwrite: function(cm) {cm.toggleOverwrite();} + }; + + // STANDARD KEYMAPS + + var keyMap = CodeMirror.keyMap = {}; + keyMap.basic = { + "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", + "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", + "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", + "Tab": "defaultTab", "Shift-Tab": "indentAuto", + "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", + "Esc": "singleSelection" + }; + // Note that the save and find-related commands aren't defined by + // default. User code or addons can define them. Unknown commands + // are simply ignored. + keyMap.pcDefault = { + "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", + "Ctrl-Home": "goDocStart", "Ctrl-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd", + "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", + "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", + "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", + "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", + "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", + fallthrough: "basic" + }; + keyMap.macDefault = { + "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", + "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", + "Alt-Right": "goGroupRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delGroupBefore", + "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", + "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", + "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delLineLeft", + "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", + fallthrough: ["basic", "emacsy"] + }; + // Very basic readline/emacs-style bindings, which are standard on Mac. + keyMap.emacsy = { + "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", + "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", + "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", + "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars" + }; + keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; + + // KEYMAP DISPATCH + + function getKeyMap(val) { + if (typeof val == "string") return keyMap[val]; + else return val; + } + + // Given an array of keymaps and a key name, call handle on any + // bindings found, until that returns a truthy value, at which point + // we consider the key handled. Implements things like binding a key + // to false stopping further handling and keymap fallthrough. + var lookupKey = CodeMirror.lookupKey = function(name, maps, handle) { + function lookup(map) { + map = getKeyMap(map); + var found = map[name]; + if (found === false) return "stop"; + if (found != null && handle(found)) return true; + if (map.nofallthrough) return "stop"; + + var fallthrough = map.fallthrough; + if (fallthrough == null) return false; + if (Object.prototype.toString.call(fallthrough) != "[object Array]") + return lookup(fallthrough); + for (var i = 0; i < fallthrough.length; ++i) { + var done = lookup(fallthrough[i]); + if (done) return done; + } + return false; + } + + for (var i = 0; i < maps.length; ++i) { + var done = lookup(maps[i]); + if (done) return done != "stop"; + } + }; + + // Modifier key presses don't count as 'real' key presses for the + // purpose of keymap fallthrough. + var isModifierKey = CodeMirror.isModifierKey = function(event) { + var name = keyNames[event.keyCode]; + return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; + }; + + // Look up the name of a key as indicated by an event object. + var keyName = CodeMirror.keyName = function(event, noShift) { + if (presto && event.keyCode == 34 && event["char"]) return false; + var name = keyNames[event.keyCode]; + if (name == null || event.altGraphKey) return false; + if (event.altKey) name = "Alt-" + name; + if (flipCtrlCmd ? event.metaKey : event.ctrlKey) name = "Ctrl-" + name; + if (flipCtrlCmd ? event.ctrlKey : event.metaKey) name = "Cmd-" + name; + if (!noShift && event.shiftKey) name = "Shift-" + name; + return name; + }; + + // FROMTEXTAREA + + CodeMirror.fromTextArea = function(textarea, options) { + if (!options) options = {}; + options.value = textarea.value; + if (!options.tabindex && textarea.tabindex) + options.tabindex = textarea.tabindex; + if (!options.placeholder && textarea.placeholder) + options.placeholder = textarea.placeholder; + // Set autofocus to true if this textarea is focused, or if it has + // autofocus and no other element is focused. + if (options.autofocus == null) { + var hasFocus = activeElt(); + options.autofocus = hasFocus == textarea || + textarea.getAttribute("autofocus") != null && hasFocus == document.body; + } + + function save() {textarea.value = cm.getValue();} + if (textarea.form) { + on(textarea.form, "submit", save); + // Deplorable hack to make the submit method do the right thing. + if (!options.leaveSubmitMethodAlone) { + var form = textarea.form, realSubmit = form.submit; + try { + var wrappedSubmit = form.submit = function() { + save(); + form.submit = realSubmit; + form.submit(); + form.submit = wrappedSubmit; + }; + } catch(e) {} + } + } + + textarea.style.display = "none"; + var cm = CodeMirror(function(node) { + textarea.parentNode.insertBefore(node, textarea.nextSibling); + }, options); + cm.save = save; + cm.getTextArea = function() { return textarea; }; + cm.toTextArea = function() { + save(); + textarea.parentNode.removeChild(cm.getWrapperElement()); + textarea.style.display = ""; + if (textarea.form) { + off(textarea.form, "submit", save); + if (typeof textarea.form.submit == "function") + textarea.form.submit = realSubmit; + } + }; + return cm; + }; + + // STRING STREAM + + // Fed to the mode parsers, provides helper functions to make + // parsers more succinct. + + var StringStream = CodeMirror.StringStream = function(string, tabSize) { + this.pos = this.start = 0; + this.string = string; + this.tabSize = tabSize || 8; + this.lastColumnPos = this.lastColumnValue = 0; + this.lineStart = 0; + }; + + StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == this.lineStart;}, + peek: function() {return this.string.charAt(this.pos) || undefined;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() { + if (this.lastColumnPos < this.start) { + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); + this.lastColumnPos = this.start; + } + return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + indentation: function() { + return countColumn(this.string, null, this.tabSize) - + (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + } + }; + + // TEXTMARKERS + + // Created with markText and setBookmark methods. A TextMarker is a + // handle that can be used to clear or find a marked position in the + // document. Line objects hold arrays (markedSpans) containing + // {from, to, marker} object pointing to such marker objects, and + // indicating that such a marker is present on that line. Multiple + // lines may point to the same marker when it spans across lines. + // The spans will have null for their from/to properties when the + // marker continues beyond the start/end of the line. Markers have + // links back to the lines they currently touch. + + var TextMarker = CodeMirror.TextMarker = function(doc, type) { + this.lines = []; + this.type = type; + this.doc = doc; + }; + eventMixin(TextMarker); + + // Clear the marker. + TextMarker.prototype.clear = function() { + if (this.explicitlyCleared) return; + var cm = this.doc.cm, withOp = cm && !cm.curOp; + if (withOp) startOperation(cm); + if (hasHandler(this, "clear")) { + var found = this.find(); + if (found) signalLater(this, "clear", found.from, found.to); + } + var min = null, max = null; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text"); + else if (cm) { + if (span.to != null) max = lineNo(line); + if (span.from != null) min = lineNo(line); + } + line.markedSpans = removeMarkedSpan(line.markedSpans, span); + if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) + updateLineHeight(line, textHeight(cm.display)); + } + if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { + var visual = visualLine(this.lines[i]), len = lineLength(visual); + if (len > cm.display.maxLineLength) { + cm.display.maxLine = visual; + cm.display.maxLineLength = len; + cm.display.maxLineChanged = true; + } + } + + if (min != null && cm && this.collapsed) regChange(cm, min, max + 1); + this.lines.length = 0; + this.explicitlyCleared = true; + if (this.atomic && this.doc.cantEdit) { + this.doc.cantEdit = false; + if (cm) reCheckSelection(cm.doc); + } + if (cm) signalLater(cm, "markerCleared", cm, this); + if (withOp) endOperation(cm); + if (this.parent) this.parent.clear(); + }; + + // Find the position of the marker in the document. Returns a {from, + // to} object by default. Side can be passed to get a specific side + // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the + // Pos objects returned contain a line object, rather than a line + // number (used to prevent looking up the same line twice). + TextMarker.prototype.find = function(side, lineObj) { + if (side == null && this.type == "bookmark") side = 1; + var from, to; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (span.from != null) { + from = Pos(lineObj ? line : lineNo(line), span.from); + if (side == -1) return from; + } + if (span.to != null) { + to = Pos(lineObj ? line : lineNo(line), span.to); + if (side == 1) return to; + } + } + return from && {from: from, to: to}; + }; + + // Signals that the marker's widget changed, and surrounding layout + // should be recomputed. + TextMarker.prototype.changed = function() { + var pos = this.find(-1, true), widget = this, cm = this.doc.cm; + if (!pos || !cm) return; + runInOp(cm, function() { + var line = pos.line, lineN = lineNo(pos.line); + var view = findViewForLine(cm, lineN); + if (view) { + clearLineMeasurementCacheFor(view); + cm.curOp.selectionChanged = cm.curOp.forceUpdate = true; + } + cm.curOp.updateMaxLine = true; + if (!lineIsHidden(widget.doc, line) && widget.height != null) { + var oldHeight = widget.height; + widget.height = null; + var dHeight = widgetHeight(widget) - oldHeight; + if (dHeight) + updateLineHeight(line, line.height + dHeight); + } + }); + }; + + TextMarker.prototype.attachLine = function(line) { + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) + (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); + } + this.lines.push(line); + }; + TextMarker.prototype.detachLine = function(line) { + this.lines.splice(indexOf(this.lines, line), 1); + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); + } + }; + + // Collapsed markers have unique ids, in order to be able to order + // them, which is needed for uniquely determining an outer marker + // when they overlap (they may nest, but not partially overlap). + var nextMarkerId = 0; + + // Create a marker, wire it up to the right lines, and + function markText(doc, from, to, options, type) { + // Shared markers (across linked documents) are handled separately + // (markTextShared will call out to this again, once per + // document). + if (options && options.shared) return markTextShared(doc, from, to, options, type); + // Ensure we are in an operation. + if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); + + var marker = new TextMarker(doc, type), diff = cmp(from, to); + if (options) copyObj(options, marker, false); + // Don't connect empty markers unless clearWhenEmpty is false + if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) + return marker; + if (marker.replacedWith) { + // Showing up as a widget implies collapsed (widget replaces text) + marker.collapsed = true; + marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget"); + if (!options.handleMouseEvents) marker.widgetNode.ignoreEvents = true; + if (options.insertLeft) marker.widgetNode.insertLeft = true; + } + if (marker.collapsed) { + if (conflictingCollapsedRange(doc, from.line, from, to, marker) || + from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) + throw new Error("Inserting collapsed marker partially overlapping an existing one"); + sawCollapsedSpans = true; + } + + if (marker.addToHistory) + addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); + + var curLine = from.line, cm = doc.cm, updateMaxLine; + doc.iter(curLine, to.line + 1, function(line) { + if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) + updateMaxLine = true; + if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0); + addMarkedSpan(line, new MarkedSpan(marker, + curLine == from.line ? from.ch : null, + curLine == to.line ? to.ch : null)); + ++curLine; + }); + // lineIsHidden depends on the presence of the spans, so needs a second pass + if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) { + if (lineIsHidden(doc, line)) updateLineHeight(line, 0); + }); + + if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); }); + + if (marker.readOnly) { + sawReadOnlySpans = true; + if (doc.history.done.length || doc.history.undone.length) + doc.clearHistory(); + } + if (marker.collapsed) { + marker.id = ++nextMarkerId; + marker.atomic = true; + } + if (cm) { + // Sync editor state + if (updateMaxLine) cm.curOp.updateMaxLine = true; + if (marker.collapsed) + regChange(cm, from.line, to.line + 1); + else if (marker.className || marker.title || marker.startStyle || marker.endStyle) + for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text"); + if (marker.atomic) reCheckSelection(cm.doc); + signalLater(cm, "markerAdded", cm, marker); + } + return marker; + } + + // SHARED TEXTMARKERS + + // A shared marker spans multiple linked documents. It is + // implemented as a meta-marker-object controlling multiple normal + // markers. + var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) { + this.markers = markers; + this.primary = primary; + for (var i = 0; i < markers.length; ++i) + markers[i].parent = this; + }; + eventMixin(SharedTextMarker); + + SharedTextMarker.prototype.clear = function() { + if (this.explicitlyCleared) return; + this.explicitlyCleared = true; + for (var i = 0; i < this.markers.length; ++i) + this.markers[i].clear(); + signalLater(this, "clear"); + }; + SharedTextMarker.prototype.find = function(side, lineObj) { + return this.primary.find(side, lineObj); + }; + + function markTextShared(doc, from, to, options, type) { + options = copyObj(options); + options.shared = false; + var markers = [markText(doc, from, to, options, type)], primary = markers[0]; + var widget = options.widgetNode; + linkedDocs(doc, function(doc) { + if (widget) options.widgetNode = widget.cloneNode(true); + markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); + for (var i = 0; i < doc.linked.length; ++i) + if (doc.linked[i].isParent) return; + primary = lst(markers); + }); + return new SharedTextMarker(markers, primary); + } + + function findSharedMarkers(doc) { + return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), + function(m) { return m.parent; }); + } + + function copySharedMarkers(doc, markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], pos = marker.find(); + var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); + if (cmp(mFrom, mTo)) { + var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); + marker.markers.push(subMark); + subMark.parent = marker; + } + } + } + + function detachSharedMarkers(markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], linked = [marker.primary.doc];; + linkedDocs(marker.primary.doc, function(d) { linked.push(d); }); + for (var j = 0; j < marker.markers.length; j++) { + var subMarker = marker.markers[j]; + if (indexOf(linked, subMarker.doc) == -1) { + subMarker.parent = null; + marker.markers.splice(j--, 1); + } + } + } + } + + // TEXTMARKER SPANS + + function MarkedSpan(marker, from, to) { + this.marker = marker; + this.from = from; this.to = to; + } + + // Search an array of spans for a span matching the given marker. + function getMarkedSpanFor(spans, marker) { + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.marker == marker) return span; + } + } + // Remove a span from an array, returning undefined if no spans are + // left (we don't store arrays for lines without spans). + function removeMarkedSpan(spans, span) { + for (var r, i = 0; i < spans.length; ++i) + if (spans[i] != span) (r || (r = [])).push(spans[i]); + return r; + } + // Add a span to a line. + function addMarkedSpan(line, span) { + line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; + span.marker.attachLine(line); + } + + // Used for the algorithm that adjusts markers for a change in the + // document. These functions cut an array of spans at a given + // character position, returning an array of remaining chunks (or + // undefined if nothing remains). + function markedSpansBefore(old, startCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); + if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); + (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)); + } + } + return nw; + } + function markedSpansAfter(old, endCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); + if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh); + (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, + span.to == null ? null : span.to - endCh)); + } + } + return nw; + } + + // Given a change object, compute the new set of marker spans that + // cover the line in which the change took place. Removes spans + // entirely within the change, reconnects spans belonging to the + // same marker that appear on both sides of the change, and cuts off + // spans partially within the change. Returns an array of span + // arrays with one element for each line in (after) the change. + function stretchSpansOverChange(doc, change) { + var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; + var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; + if (!oldFirst && !oldLast) return null; + + var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0; + // Get the spans that 'stick out' on both sides + var first = markedSpansBefore(oldFirst, startCh, isInsert); + var last = markedSpansAfter(oldLast, endCh, isInsert); + + // Next, merge those two ends + var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); + if (first) { + // Fix up .to properties of first + for (var i = 0; i < first.length; ++i) { + var span = first[i]; + if (span.to == null) { + var found = getMarkedSpanFor(last, span.marker); + if (!found) span.to = startCh; + else if (sameLine) span.to = found.to == null ? null : found.to + offset; + } + } + } + if (last) { + // Fix up .from in last (or move them into first in case of sameLine) + for (var i = 0; i < last.length; ++i) { + var span = last[i]; + if (span.to != null) span.to += offset; + if (span.from == null) { + var found = getMarkedSpanFor(first, span.marker); + if (!found) { + span.from = offset; + if (sameLine) (first || (first = [])).push(span); + } + } else { + span.from += offset; + if (sameLine) (first || (first = [])).push(span); + } + } + } + // Make sure we didn't create any zero-length spans + if (first) first = clearEmptySpans(first); + if (last && last != first) last = clearEmptySpans(last); + + var newMarkers = [first]; + if (!sameLine) { + // Fill gap with whole-line-spans + var gap = change.text.length - 2, gapMarkers; + if (gap > 0 && first) + for (var i = 0; i < first.length; ++i) + if (first[i].to == null) + (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null)); + for (var i = 0; i < gap; ++i) + newMarkers.push(gapMarkers); + newMarkers.push(last); + } + return newMarkers; + } + + // Remove spans that are empty and don't have a clearWhenEmpty + // option of false. + function clearEmptySpans(spans) { + for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) + spans.splice(i--, 1); + } + if (!spans.length) return null; + return spans; + } + + // Used for un/re-doing changes from the history. Combines the + // result of computing the existing spans with the set of spans that + // existed in the history (so that deleting around a span and then + // undoing brings back the span). + function mergeOldSpans(doc, change) { + var old = getOldSpans(doc, change); + var stretched = stretchSpansOverChange(doc, change); + if (!old) return stretched; + if (!stretched) return old; + + for (var i = 0; i < old.length; ++i) { + var oldCur = old[i], stretchCur = stretched[i]; + if (oldCur && stretchCur) { + spans: for (var j = 0; j < stretchCur.length; ++j) { + var span = stretchCur[j]; + for (var k = 0; k < oldCur.length; ++k) + if (oldCur[k].marker == span.marker) continue spans; + oldCur.push(span); + } + } else if (stretchCur) { + old[i] = stretchCur; + } + } + return old; + } + + // Used to 'clip' out readOnly ranges when making a change. + function removeReadOnlyRanges(doc, from, to) { + var markers = null; + doc.iter(from.line, to.line + 1, function(line) { + if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { + var mark = line.markedSpans[i].marker; + if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) + (markers || (markers = [])).push(mark); + } + }); + if (!markers) return null; + var parts = [{from: from, to: to}]; + for (var i = 0; i < markers.length; ++i) { + var mk = markers[i], m = mk.find(0); + for (var j = 0; j < parts.length; ++j) { + var p = parts[j]; + if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue; + var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to); + if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) + newParts.push({from: p.from, to: m.from}); + if (dto > 0 || !mk.inclusiveRight && !dto) + newParts.push({from: m.to, to: p.to}); + parts.splice.apply(parts, newParts); + j += newParts.length - 1; + } + } + return parts; + } + + // Connect or disconnect spans from a line. + function detachMarkedSpans(line) { + var spans = line.markedSpans; + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.detachLine(line); + line.markedSpans = null; + } + function attachMarkedSpans(line, spans) { + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.attachLine(line); + line.markedSpans = spans; + } + + // Helpers used when computing which overlapping collapsed span + // counts as the larger one. + function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; } + function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; } + + // Returns a number indicating which of two overlapping collapsed + // spans is larger (and thus includes the other). Falls back to + // comparing ids when the spans cover exactly the same range. + function compareCollapsedMarkers(a, b) { + var lenDiff = a.lines.length - b.lines.length; + if (lenDiff != 0) return lenDiff; + var aPos = a.find(), bPos = b.find(); + var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b); + if (fromCmp) return -fromCmp; + var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b); + if (toCmp) return toCmp; + return b.id - a.id; + } + + // Find out whether a line ends or starts in a collapsed span. If + // so, return the marker for that span. + function collapsedSpanAtSide(line, start) { + var sps = sawCollapsedSpans && line.markedSpans, found; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && + (!found || compareCollapsedMarkers(found, sp.marker) < 0)) + found = sp.marker; + } + return found; + } + function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); } + function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); } + + // Test whether there exists a collapsed span that partially + // overlaps (covers the start or end, but not both) of a new span. + // Such overlap is not allowed. + function conflictingCollapsedRange(doc, lineNo, from, to, marker) { + var line = getLine(doc, lineNo); + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) for (var i = 0; i < sps.length; ++i) { + var sp = sps[i]; + if (!sp.marker.collapsed) continue; + var found = sp.marker.find(0); + var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker); + var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker); + if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue; + if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) || + fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight))) + return true; + } + } + + // A visual line is a line as drawn on the screen. Folding, for + // example, can cause multiple logical lines to appear on the same + // visual line. This finds the start of the visual line that the + // given line is part of (usually that is the line itself). + function visualLine(line) { + var merged; + while (merged = collapsedSpanAtStart(line)) + line = merged.find(-1, true).line; + return line; + } + + // Returns an array of logical lines that continue the visual line + // started by the argument, or undefined if there are no such lines. + function visualLineContinued(line) { + var merged, lines; + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line; + (lines || (lines = [])).push(line); + } + return lines; + } + + // Get the line number of the start of the visual line that the + // given line number is part of. + function visualLineNo(doc, lineN) { + var line = getLine(doc, lineN), vis = visualLine(line); + if (line == vis) return lineN; + return lineNo(vis); + } + // Get the line number of the start of the next visual line after + // the given line. + function visualLineEndNo(doc, lineN) { + if (lineN > doc.lastLine()) return lineN; + var line = getLine(doc, lineN), merged; + if (!lineIsHidden(doc, line)) return lineN; + while (merged = collapsedSpanAtEnd(line)) + line = merged.find(1, true).line; + return lineNo(line) + 1; + } + + // Compute whether a line is hidden. Lines count as hidden when they + // are part of a visual line that starts with another line, or when + // they are entirely covered by collapsed, non-widget span. + function lineIsHidden(doc, line) { + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (!sp.marker.collapsed) continue; + if (sp.from == null) return true; + if (sp.marker.widgetNode) continue; + if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) + return true; + } + } + function lineIsHiddenInner(doc, line, span) { + if (span.to == null) { + var end = span.marker.find(1, true); + return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)); + } + if (span.marker.inclusiveRight && span.to == line.text.length) + return true; + for (var sp, i = 0; i < line.markedSpans.length; ++i) { + sp = line.markedSpans[i]; + if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && + (sp.to == null || sp.to != span.from) && + (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && + lineIsHiddenInner(doc, line, sp)) return true; + } + } + + // LINE WIDGETS + + // Line widgets are block elements displayed above or below a line. + + var LineWidget = CodeMirror.LineWidget = function(cm, node, options) { + if (options) for (var opt in options) if (options.hasOwnProperty(opt)) + this[opt] = options[opt]; + this.cm = cm; + this.node = node; + }; + eventMixin(LineWidget); + + function adjustScrollWhenAboveVisible(cm, line, diff) { + if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) + addToScrollPos(cm, null, diff); + } + + LineWidget.prototype.clear = function() { + var cm = this.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); + if (no == null || !ws) return; + for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); + if (!ws.length) line.widgets = null; + var height = widgetHeight(this); + runInOp(cm, function() { + adjustScrollWhenAboveVisible(cm, line, -height); + regLineChange(cm, no, "widget"); + updateLineHeight(line, Math.max(0, line.height - height)); + }); + }; + LineWidget.prototype.changed = function() { + var oldH = this.height, cm = this.cm, line = this.line; + this.height = null; + var diff = widgetHeight(this) - oldH; + if (!diff) return; + runInOp(cm, function() { + cm.curOp.forceUpdate = true; + adjustScrollWhenAboveVisible(cm, line, diff); + updateLineHeight(line, line.height + diff); + }); + }; + + function widgetHeight(widget) { + if (widget.height != null) return widget.height; + if (!contains(document.body, widget.node)) { + var parentStyle = "position: relative;"; + if (widget.coverGutter) + parentStyle += "margin-left: -" + widget.cm.getGutterElement().offsetWidth + "px;"; + removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, parentStyle)); + } + return widget.height = widget.node.offsetHeight; + } + + function addLineWidget(cm, handle, node, options) { + var widget = new LineWidget(cm, node, options); + if (widget.noHScroll) cm.display.alignWidgets = true; + changeLine(cm.doc, handle, "widget", function(line) { + var widgets = line.widgets || (line.widgets = []); + if (widget.insertAt == null) widgets.push(widget); + else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); + widget.line = line; + if (!lineIsHidden(cm.doc, line)) { + var aboveVisible = heightAtLine(line) < cm.doc.scrollTop; + updateLineHeight(line, line.height + widgetHeight(widget)); + if (aboveVisible) addToScrollPos(cm, null, widget.height); + cm.curOp.forceUpdate = true; + } + return true; + }); + return widget; + } + + // LINE DATA STRUCTURE + + // Line objects. These hold state related to a line, including + // highlighting info (the styles array). + var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) { + this.text = text; + attachMarkedSpans(this, markedSpans); + this.height = estimateHeight ? estimateHeight(this) : 1; + }; + eventMixin(Line); + Line.prototype.lineNo = function() { return lineNo(this); }; + + // Change the content (text, markers) of a line. Automatically + // invalidates cached information and tries to re-estimate the + // line's height. + function updateLine(line, text, markedSpans, estimateHeight) { + line.text = text; + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + if (line.order != null) line.order = null; + detachMarkedSpans(line); + attachMarkedSpans(line, markedSpans); + var estHeight = estimateHeight ? estimateHeight(line) : 1; + if (estHeight != line.height) updateLineHeight(line, estHeight); + } + + // Detach a line from the document tree and its markers. + function cleanUpLine(line) { + line.parent = null; + detachMarkedSpans(line); + } + + function extractLineClasses(type, output) { + if (type) for (;;) { + var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/); + if (!lineClass) break; + type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length); + var prop = lineClass[1] ? "bgClass" : "textClass"; + if (output[prop] == null) + output[prop] = lineClass[2]; + else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) + output[prop] += " " + lineClass[2]; + } + return type; + } + + function callBlankLine(mode, state) { + if (mode.blankLine) return mode.blankLine(state); + if (!mode.innerMode) return; + var inner = CodeMirror.innerMode(mode, state); + if (inner.mode.blankLine) return inner.mode.blankLine(inner.state); + } + + function readToken(mode, stream, state) { + for (var i = 0; i < 10; i++) { + var style = mode.token(stream, state); + if (stream.pos > stream.start) return style; + } + throw new Error("Mode " + mode.name + " failed to advance stream."); + } + + // Run the given mode's parser over a line, calling f for each token. + function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { + var flattenSpans = mode.flattenSpans; + if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; + var curStart = 0, curStyle = null; + var stream = new StringStream(text, cm.options.tabSize), style; + if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses); + while (!stream.eol()) { + if (stream.pos > cm.options.maxHighlightLength) { + flattenSpans = false; + if (forceToEnd) processLine(cm, text, state, stream.pos); + stream.pos = text.length; + style = null; + } else { + style = extractLineClasses(readToken(mode, stream, state), lineClasses); + } + if (cm.options.addModeClass) { + var mName = CodeMirror.innerMode(mode, state).mode.name; + if (mName) style = "m-" + (style ? mName + " " + style : mName); + } + if (!flattenSpans || curStyle != style) { + if (curStart < stream.start) f(stream.start, curStyle); + curStart = stream.start; curStyle = style; + } + stream.start = stream.pos; + } + while (curStart < stream.pos) { + // Webkit seems to refuse to render text nodes longer than 57444 characters + var pos = Math.min(stream.pos, curStart + 50000); + f(pos, curStyle); + curStart = pos; + } + } + + // Compute a style array (an array starting with a mode generation + // -- for invalidation -- followed by pairs of end positions and + // style strings), which is used to highlight the tokens on the + // line. + function highlightLine(cm, line, state, forceToEnd) { + // A styles array always starts with a number identifying the + // mode/overlays that it is based on (for easy invalidation). + var st = [cm.state.modeGen], lineClasses = {}; + // Compute the base array of styles + runMode(cm, line.text, cm.doc.mode, state, function(end, style) { + st.push(end, style); + }, lineClasses, forceToEnd); + + // Run overlays, adjust style array. + for (var o = 0; o < cm.state.overlays.length; ++o) { + var overlay = cm.state.overlays[o], i = 1, at = 0; + runMode(cm, line.text, overlay.mode, true, function(end, style) { + var start = i; + // Ensure there's a token end at the current position, and that i points at it + while (at < end) { + var i_end = st[i]; + if (i_end > end) + st.splice(i, 1, end, st[i+1], i_end); + i += 2; + at = Math.min(end, i_end); + } + if (!style) return; + if (overlay.opaque) { + st.splice(start, i - start, end, "cm-overlay " + style); + i = start + 2; + } else { + for (; start < i; start += 2) { + var cur = st[start+1]; + st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style; + } + } + }, lineClasses); + } + + return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}; + } + + function getLineStyles(cm, line) { + if (!line.styles || line.styles[0] != cm.state.modeGen) { + var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line))); + line.styles = result.styles; + if (result.classes) line.styleClasses = result.classes; + else if (line.styleClasses) line.styleClasses = null; + } + return line.styles; + } + + // Lightweight form of highlight -- proceed over this line and + // update state, but don't save a style array. Used for lines that + // aren't currently visible. + function processLine(cm, text, state, startAt) { + var mode = cm.doc.mode; + var stream = new StringStream(text, cm.options.tabSize); + stream.start = stream.pos = startAt || 0; + if (text == "") callBlankLine(mode, state); + while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { + readToken(mode, stream, state); + stream.start = stream.pos; + } + } + + // Convert a style as returned by a mode (either null, or a string + // containing one or more styles) to a CSS style. This is cached, + // and also looks for line-wide styles. + var styleToClassCache = {}, styleToClassCacheWithMode = {}; + function interpretTokenStyle(style, options) { + if (!style || /^\s*$/.test(style)) return null; + var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; + return cache[style] || + (cache[style] = style.replace(/\S+/g, "cm-$&")); + } + + // Render the DOM representation of the text of a line. Also builds + // up a 'line map', which points at the DOM nodes that represent + // specific stretches of text, and is used by the measuring code. + // The returned object contains the DOM node, this map, and + // information about line-wide styles that were set by the mode. + function buildLineContent(cm, lineView) { + // The padding-right forces the element to have a 'border', which + // is needed on Webkit to be able to get line-level bounding + // rectangles for it (in measureChar). + var content = elt("span", null, null, webkit ? "padding-right: .1px" : null); + var builder = {pre: elt("pre", [content]), content: content, col: 0, pos: 0, cm: cm}; + lineView.measure = {}; + + // Iterate over the logical lines that make up this visual line. + for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { + var line = i ? lineView.rest[i - 1] : lineView.line, order; + builder.pos = 0; + builder.addToken = buildToken; + // Optionally wire in some hacks into the token-rendering + // algorithm, to deal with browser quirks. + if ((ie || webkit) && cm.getOption("lineWrapping")) + builder.addToken = buildTokenSplitSpaces(builder.addToken); + if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line))) + builder.addToken = buildTokenBadBidi(builder.addToken, order); + builder.map = []; + insertLineContent(line, builder, getLineStyles(cm, line)); + if (line.styleClasses) { + if (line.styleClasses.bgClass) + builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); + if (line.styleClasses.textClass) + builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); + } + + // Ensure at least a single node is present, for measuring. + if (builder.map.length == 0) + builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); + + // Store the map and a cache object for the current logical line + if (i == 0) { + lineView.measure.map = builder.map; + lineView.measure.cache = {}; + } else { + (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map); + (lineView.measure.caches || (lineView.measure.caches = [])).push({}); + } + } + + signal(cm, "renderLine", cm, lineView.line, builder.pre); + if (builder.pre.className) + builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); + return builder; + } + + function defaultSpecialCharPlaceholder(ch) { + var token = elt("span", "\u2022", "cm-invalidchar"); + token.title = "\\u" + ch.charCodeAt(0).toString(16); + return token; + } + + // Build up the DOM representation for a single token, and add it to + // the line map. Takes care to render special characters separately. + function buildToken(builder, text, style, startStyle, endStyle, title) { + if (!text) return; + var special = builder.cm.options.specialChars, mustWrap = false; + if (!special.test(text)) { + builder.col += text.length; + var content = document.createTextNode(text); + builder.map.push(builder.pos, builder.pos + text.length, content); + if (ie && ie_version < 9) mustWrap = true; + builder.pos += text.length; + } else { + var content = document.createDocumentFragment(), pos = 0; + while (true) { + special.lastIndex = pos; + var m = special.exec(text); + var skipped = m ? m.index - pos : text.length - pos; + if (skipped) { + var txt = document.createTextNode(text.slice(pos, pos + skipped)); + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); + else content.appendChild(txt); + builder.map.push(builder.pos, builder.pos + skipped, txt); + builder.col += skipped; + builder.pos += skipped; + } + if (!m) break; + pos += skipped + 1; + if (m[0] == "\t") { + var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; + var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); + builder.col += tabWidth; + } else { + var txt = builder.cm.options.specialCharPlaceholder(m[0]); + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); + else content.appendChild(txt); + builder.col += 1; + } + builder.map.push(builder.pos, builder.pos + 1, txt); + builder.pos++; + } + } + if (style || startStyle || endStyle || mustWrap) { + var fullStyle = style || ""; + if (startStyle) fullStyle += startStyle; + if (endStyle) fullStyle += endStyle; + var token = elt("span", [content], fullStyle); + if (title) token.title = title; + return builder.content.appendChild(token); + } + builder.content.appendChild(content); + } + + function buildTokenSplitSpaces(inner) { + function split(old) { + var out = " "; + for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0"; + out += " "; + return out; + } + return function(builder, text, style, startStyle, endStyle, title) { + inner(builder, text.replace(/ {3,}/g, split), style, startStyle, endStyle, title); + }; + } + + // Work around nonsense dimensions being reported for stretches of + // right-to-left text. + function buildTokenBadBidi(inner, order) { + return function(builder, text, style, startStyle, endStyle, title) { + style = style ? style + " cm-force-border" : "cm-force-border"; + var start = builder.pos, end = start + text.length; + for (;;) { + // Find the part that overlaps with the start of this text + for (var i = 0; i < order.length; i++) { + var part = order[i]; + if (part.to > start && part.from <= start) break; + } + if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title); + inner(builder, text.slice(0, part.to - start), style, startStyle, null, title); + startStyle = null; + text = text.slice(part.to - start); + start = part.to; + } + }; + } + + function buildCollapsedSpan(builder, size, marker, ignoreWidget) { + var widget = !ignoreWidget && marker.widgetNode; + if (widget) { + builder.map.push(builder.pos, builder.pos + size, widget); + builder.content.appendChild(widget); + } + builder.pos += size; + } + + // Outputs a number of spans to make up a line, taking highlighting + // and marked text into account. + function insertLineContent(line, builder, styles) { + var spans = line.markedSpans, allText = line.text, at = 0; + if (!spans) { + for (var i = 1; i < styles.length; i+=2) + builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options)); + return; + } + + var len = allText.length, pos = 0, i = 1, text = "", style; + var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; + for (;;) { + if (nextChange == pos) { // Update current marker set + spanStyle = spanEndStyle = spanStartStyle = title = ""; + collapsed = null; nextChange = Infinity; + var foundBookmarks = []; + for (var j = 0; j < spans.length; ++j) { + var sp = spans[j], m = sp.marker; + if (sp.from <= pos && (sp.to == null || sp.to > pos)) { + if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; } + if (m.className) spanStyle += " " + m.className; + if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; + if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle; + if (m.title && !title) title = m.title; + if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) + collapsed = sp; + } else if (sp.from > pos && nextChange > sp.from) { + nextChange = sp.from; + } + if (m.type == "bookmark" && sp.from == pos && m.widgetNode) foundBookmarks.push(m); + } + if (collapsed && (collapsed.from || 0) == pos) { + buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, + collapsed.marker, collapsed.from == null); + if (collapsed.to == null) return; + } + if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j) + buildCollapsedSpan(builder, 0, foundBookmarks[j]); + } + if (pos >= len) break; + + var upto = Math.min(len, nextChange); + while (true) { + if (text) { + var end = pos + text.length; + if (!collapsed) { + var tokenText = end > upto ? text.slice(0, upto - pos) : text; + builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, + spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title); + } + if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} + pos = end; + spanStartStyle = ""; + } + text = allText.slice(at, at = styles[i++]); + style = interpretTokenStyle(styles[i++], builder.cm.options); + } + } + } + + // DOCUMENT DATA STRUCTURE + + // By default, updates that start and end at the beginning of a line + // are treated specially, in order to make the association of line + // widgets and marker elements with the text behave more intuitive. + function isWholeLineUpdate(doc, change) { + return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && + (!doc.cm || doc.cm.options.wholeLineUpdateBefore); + } + + // Perform a change on the document data structure. + function updateDoc(doc, change, markedSpans, estimateHeight) { + function spansFor(n) {return markedSpans ? markedSpans[n] : null;} + function update(line, text, spans) { + updateLine(line, text, spans, estimateHeight); + signalLater(line, "change", line, change); + } + + var from = change.from, to = change.to, text = change.text; + var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); + var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; + + // Adjust the line structure + if (isWholeLineUpdate(doc, change)) { + // This is a whole-line replace. Treated specially to make + // sure line objects move the way they are supposed to. + for (var i = 0, added = []; i < text.length - 1; ++i) + added.push(new Line(text[i], spansFor(i), estimateHeight)); + update(lastLine, lastLine.text, lastSpans); + if (nlines) doc.remove(from.line, nlines); + if (added.length) doc.insert(from.line, added); + } else if (firstLine == lastLine) { + if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); + } else { + for (var added = [], i = 1; i < text.length - 1; ++i) + added.push(new Line(text[i], spansFor(i), estimateHeight)); + added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + doc.insert(from.line + 1, added); + } + } else if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); + doc.remove(from.line + 1, nlines); + } else { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); + for (var i = 1, added = []; i < text.length - 1; ++i) + added.push(new Line(text[i], spansFor(i), estimateHeight)); + if (nlines > 1) doc.remove(from.line + 1, nlines - 1); + doc.insert(from.line + 1, added); + } + + signalLater(doc, "change", doc, change); + } + + // The document is represented as a BTree consisting of leaves, with + // chunk of lines in them, and branches, with up to ten leaves or + // other branch nodes below them. The top node is always a branch + // node, and is the document object itself (meaning it has + // additional methods and properties). + // + // All nodes have parent links. The tree is used both to go from + // line numbers to line objects, and to go from objects to numbers. + // It also indexes by height, and is used to convert between height + // and line object, and to find the total height of the document. + // + // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html + + function LeafChunk(lines) { + this.lines = lines; + this.parent = null; + for (var i = 0, height = 0; i < lines.length; ++i) { + lines[i].parent = this; + height += lines[i].height; + } + this.height = height; + } + + LeafChunk.prototype = { + chunkSize: function() { return this.lines.length; }, + // Remove the n lines at offset 'at'. + removeInner: function(at, n) { + for (var i = at, e = at + n; i < e; ++i) { + var line = this.lines[i]; + this.height -= line.height; + cleanUpLine(line); + signalLater(line, "delete"); + } + this.lines.splice(at, n); + }, + // Helper used to collapse a small branch into a single leaf. + collapse: function(lines) { + lines.push.apply(lines, this.lines); + }, + // Insert the given array of lines at offset 'at', count them as + // having the given height. + insertInner: function(at, lines, height) { + this.height += height; + this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); + for (var i = 0; i < lines.length; ++i) lines[i].parent = this; + }, + // Used to iterate over a part of the tree. + iterN: function(at, n, op) { + for (var e = at + n; at < e; ++at) + if (op(this.lines[at])) return true; + } + }; + + function BranchChunk(children) { + this.children = children; + var size = 0, height = 0; + for (var i = 0; i < children.length; ++i) { + var ch = children[i]; + size += ch.chunkSize(); height += ch.height; + ch.parent = this; + } + this.size = size; + this.height = height; + this.parent = null; + } + + BranchChunk.prototype = { + chunkSize: function() { return this.size; }, + removeInner: function(at, n) { + this.size -= n; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var rm = Math.min(n, sz - at), oldHeight = child.height; + child.removeInner(at, rm); + this.height -= oldHeight - child.height; + if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } + if ((n -= rm) == 0) break; + at = 0; + } else at -= sz; + } + // If the result is smaller than 25 lines, ensure that it is a + // single leaf node. + if (this.size - n < 25 && + (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { + var lines = []; + this.collapse(lines); + this.children = [new LeafChunk(lines)]; + this.children[0].parent = this; + } + }, + collapse: function(lines) { + for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines); + }, + insertInner: function(at, lines, height) { + this.size += lines.length; + this.height += height; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at <= sz) { + child.insertInner(at, lines, height); + if (child.lines && child.lines.length > 50) { + while (child.lines.length > 50) { + var spilled = child.lines.splice(child.lines.length - 25, 25); + var newleaf = new LeafChunk(spilled); + child.height -= newleaf.height; + this.children.splice(i + 1, 0, newleaf); + newleaf.parent = this; + } + this.maybeSpill(); + } + break; + } + at -= sz; + } + }, + // When a node has grown, check whether it should be split. + maybeSpill: function() { + if (this.children.length <= 10) return; + var me = this; + do { + var spilled = me.children.splice(me.children.length - 5, 5); + var sibling = new BranchChunk(spilled); + if (!me.parent) { // Become the parent node + var copy = new BranchChunk(me.children); + copy.parent = me; + me.children = [copy, sibling]; + me = copy; + } else { + me.size -= sibling.size; + me.height -= sibling.height; + var myIndex = indexOf(me.parent.children, me); + me.parent.children.splice(myIndex + 1, 0, sibling); + } + sibling.parent = me.parent; + } while (me.children.length > 10); + me.parent.maybeSpill(); + }, + iterN: function(at, n, op) { + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var used = Math.min(n, sz - at); + if (child.iterN(at, used, op)) return true; + if ((n -= used) == 0) break; + at = 0; + } else at -= sz; + } + } + }; + + var nextDocId = 0; + var Doc = CodeMirror.Doc = function(text, mode, firstLine) { + if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); + if (firstLine == null) firstLine = 0; + + BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); + this.first = firstLine; + this.scrollTop = this.scrollLeft = 0; + this.cantEdit = false; + this.cleanGeneration = 1; + this.frontier = firstLine; + var start = Pos(firstLine, 0); + this.sel = simpleSelection(start); + this.history = new History(null); + this.id = ++nextDocId; + this.modeOption = mode; + + if (typeof text == "string") text = splitLines(text); + updateDoc(this, {from: start, to: start, text: text}); + setSelection(this, simpleSelection(start), sel_dontScroll); + }; + + Doc.prototype = createObj(BranchChunk.prototype, { + constructor: Doc, + // Iterate over the document. Supports two forms -- with only one + // argument, it calls that for each line in the document. With + // three, it iterates over the range given by the first two (with + // the second being non-inclusive). + iter: function(from, to, op) { + if (op) this.iterN(from - this.first, to - from, op); + else this.iterN(this.first, this.first + this.size, from); + }, + + // Non-public interface for adding and removing lines. + insert: function(at, lines) { + var height = 0; + for (var i = 0; i < lines.length; ++i) height += lines[i].height; + this.insertInner(at - this.first, lines, height); + }, + remove: function(at, n) { this.removeInner(at - this.first, n); }, + + // From here, the methods are part of the public interface. Most + // are also available from CodeMirror (editor) instances. + + getValue: function(lineSep) { + var lines = getLines(this, this.first, this.first + this.size); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + setValue: docMethodOp(function(code) { + var top = Pos(this.first, 0), last = this.first + this.size - 1; + makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), + text: splitLines(code), origin: "setValue"}, true); + setSelection(this, simpleSelection(top)); + }), + replaceRange: function(code, from, to, origin) { + from = clipPos(this, from); + to = to ? clipPos(this, to) : from; + replaceRange(this, code, from, to, origin); + }, + getRange: function(from, to, lineSep) { + var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + + getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, + + getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);}, + getLineNumber: function(line) {return lineNo(line);}, + + getLineHandleVisualStart: function(line) { + if (typeof line == "number") line = getLine(this, line); + return visualLine(line); + }, + + lineCount: function() {return this.size;}, + firstLine: function() {return this.first;}, + lastLine: function() {return this.first + this.size - 1;}, + + clipPos: function(pos) {return clipPos(this, pos);}, + + getCursor: function(start) { + var range = this.sel.primary(), pos; + if (start == null || start == "head") pos = range.head; + else if (start == "anchor") pos = range.anchor; + else if (start == "end" || start == "to" || start === false) pos = range.to(); + else pos = range.from(); + return pos; + }, + listSelections: function() { return this.sel.ranges; }, + somethingSelected: function() {return this.sel.somethingSelected();}, + + setCursor: docMethodOp(function(line, ch, options) { + setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options); + }), + setSelection: docMethodOp(function(anchor, head, options) { + setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options); + }), + extendSelection: docMethodOp(function(head, other, options) { + extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); + }), + extendSelections: docMethodOp(function(heads, options) { + extendSelections(this, clipPosArray(this, heads, options)); + }), + extendSelectionsBy: docMethodOp(function(f, options) { + extendSelections(this, map(this.sel.ranges, f), options); + }), + setSelections: docMethodOp(function(ranges, primary, options) { + if (!ranges.length) return; + for (var i = 0, out = []; i < ranges.length; i++) + out[i] = new Range(clipPos(this, ranges[i].anchor), + clipPos(this, ranges[i].head)); + if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex); + setSelection(this, normalizeSelection(out, primary), options); + }), + addSelection: docMethodOp(function(anchor, head, options) { + var ranges = this.sel.ranges.slice(0); + ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))); + setSelection(this, normalizeSelection(ranges, ranges.length - 1), options); + }), + + getSelection: function(lineSep) { + var ranges = this.sel.ranges, lines; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + lines = lines ? lines.concat(sel) : sel; + } + if (lineSep === false) return lines; + else return lines.join(lineSep || "\n"); + }, + getSelections: function(lineSep) { + var parts = [], ranges = this.sel.ranges; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + if (lineSep !== false) sel = sel.join(lineSep || "\n"); + parts[i] = sel; + } + return parts; + }, + replaceSelection: function(code, collapse, origin) { + var dup = []; + for (var i = 0; i < this.sel.ranges.length; i++) + dup[i] = code; + this.replaceSelections(dup, collapse, origin || "+input"); + }, + replaceSelections: docMethodOp(function(code, collapse, origin) { + var changes = [], sel = this.sel; + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i]; + changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin}; + } + var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); + for (var i = changes.length - 1; i >= 0; i--) + makeChange(this, changes[i]); + if (newSel) setSelectionReplaceHistory(this, newSel); + else if (this.cm) ensureCursorVisible(this.cm); + }), + undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}), + redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}), + undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}), + redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}), + + setExtending: function(val) {this.extend = val;}, + getExtending: function() {return this.extend;}, + + historySize: function() { + var hist = this.history, done = 0, undone = 0; + for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done; + for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone; + return {undo: done, redo: undone}; + }, + clearHistory: function() {this.history = new History(this.history.maxGeneration);}, + + markClean: function() { + this.cleanGeneration = this.changeGeneration(true); + }, + changeGeneration: function(forceSplit) { + if (forceSplit) + this.history.lastOp = this.history.lastOrigin = null; + return this.history.generation; + }, + isClean: function (gen) { + return this.history.generation == (gen || this.cleanGeneration); + }, + + getHistory: function() { + return {done: copyHistoryArray(this.history.done), + undone: copyHistoryArray(this.history.undone)}; + }, + setHistory: function(histData) { + var hist = this.history = new History(this.history.maxGeneration); + hist.done = copyHistoryArray(histData.done.slice(0), null, true); + hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); + }, + + addLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, "class", function(line) { + var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass"; + if (!line[prop]) line[prop] = cls; + else if (new RegExp("(?:^|\\s)" + cls + "(?:$|\\s)").test(line[prop])) return false; + else line[prop] += " " + cls; + return true; + }); + }), + removeLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, "class", function(line) { + var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass"; + var cur = line[prop]; + if (!cur) return false; + else if (cls == null) line[prop] = null; + else { + var found = cur.match(new RegExp("(?:^|\\s+)" + cls + "(?:$|\\s+)")); + if (!found) return false; + var end = found.index + found[0].length; + line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; + } + return true; + }); + }), + + markText: function(from, to, options) { + return markText(this, clipPos(this, from), clipPos(this, to), options, "range"); + }, + setBookmark: function(pos, options) { + var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), + insertLeft: options && options.insertLeft, + clearWhenEmpty: false, shared: options && options.shared}; + pos = clipPos(this, pos); + return markText(this, pos, pos, realOpts, "bookmark"); + }, + findMarksAt: function(pos) { + pos = clipPos(this, pos); + var markers = [], spans = getLine(this, pos.line).markedSpans; + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if ((span.from == null || span.from <= pos.ch) && + (span.to == null || span.to >= pos.ch)) + markers.push(span.marker.parent || span.marker); + } + return markers; + }, + findMarks: function(from, to, filter) { + from = clipPos(this, from); to = clipPos(this, to); + var found = [], lineNo = from.line; + this.iter(from.line, to.line + 1, function(line) { + var spans = line.markedSpans; + if (spans) for (var i = 0; i < spans.length; i++) { + var span = spans[i]; + if (!(lineNo == from.line && from.ch > span.to || + span.from == null && lineNo != from.line|| + lineNo == to.line && span.from > to.ch) && + (!filter || filter(span.marker))) + found.push(span.marker.parent || span.marker); + } + ++lineNo; + }); + return found; + }, + getAllMarks: function() { + var markers = []; + this.iter(function(line) { + var sps = line.markedSpans; + if (sps) for (var i = 0; i < sps.length; ++i) + if (sps[i].from != null) markers.push(sps[i].marker); + }); + return markers; + }, + + posFromIndex: function(off) { + var ch, lineNo = this.first; + this.iter(function(line) { + var sz = line.text.length + 1; + if (sz > off) { ch = off; return true; } + off -= sz; + ++lineNo; + }); + return clipPos(this, Pos(lineNo, ch)); + }, + indexFromPos: function (coords) { + coords = clipPos(this, coords); + var index = coords.ch; + if (coords.line < this.first || coords.ch < 0) return 0; + this.iter(this.first, coords.line, function (line) { + index += line.text.length + 1; + }); + return index; + }, + + copy: function(copyHistory) { + var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first); + doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; + doc.sel = this.sel; + doc.extend = false; + if (copyHistory) { + doc.history.undoDepth = this.history.undoDepth; + doc.setHistory(this.getHistory()); + } + return doc; + }, + + linkedDoc: function(options) { + if (!options) options = {}; + var from = this.first, to = this.first + this.size; + if (options.from != null && options.from > from) from = options.from; + if (options.to != null && options.to < to) to = options.to; + var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from); + if (options.sharedHist) copy.history = this.history; + (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); + copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; + copySharedMarkers(copy, findSharedMarkers(this)); + return copy; + }, + unlinkDoc: function(other) { + if (other instanceof CodeMirror) other = other.doc; + if (this.linked) for (var i = 0; i < this.linked.length; ++i) { + var link = this.linked[i]; + if (link.doc != other) continue; + this.linked.splice(i, 1); + other.unlinkDoc(this); + detachSharedMarkers(findSharedMarkers(this)); + break; + } + // If the histories were shared, split them again + if (other.history == this.history) { + var splitIds = [other.id]; + linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true); + other.history = new History(null); + other.history.done = copyHistoryArray(this.history.done, splitIds); + other.history.undone = copyHistoryArray(this.history.undone, splitIds); + } + }, + iterLinkedDocs: function(f) {linkedDocs(this, f);}, + + getMode: function() {return this.mode;}, + getEditor: function() {return this.cm;} + }); + + // Public alias. + Doc.prototype.eachLine = Doc.prototype.iter; + + // Set up methods on CodeMirror's prototype to redirect to the editor's document. + var dontDelegate = "iter insert remove copy getEditor".split(" "); + for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) + CodeMirror.prototype[prop] = (function(method) { + return function() {return method.apply(this.doc, arguments);}; + })(Doc.prototype[prop]); + + eventMixin(Doc); + + // Call f for all linked documents. + function linkedDocs(doc, f, sharedHistOnly) { + function propagate(doc, skip, sharedHist) { + if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { + var rel = doc.linked[i]; + if (rel.doc == skip) continue; + var shared = sharedHist && rel.sharedHist; + if (sharedHistOnly && !shared) continue; + f(rel.doc, shared); + propagate(rel.doc, doc, shared); + } + } + propagate(doc, null, true); + } + + // Attach a document to an editor. + function attachDoc(cm, doc) { + if (doc.cm) throw new Error("This document is already in use."); + cm.doc = doc; + doc.cm = cm; + estimateLineHeights(cm); + loadMode(cm); + if (!cm.options.lineWrapping) findMaxLine(cm); + cm.options.mode = doc.modeOption; + regChange(cm); + } + + // LINE UTILITIES + + // Find the line object corresponding to the given line number. + function getLine(doc, n) { + n -= doc.first; + if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document."); + for (var chunk = doc; !chunk.lines;) { + for (var i = 0;; ++i) { + var child = chunk.children[i], sz = child.chunkSize(); + if (n < sz) { chunk = child; break; } + n -= sz; + } + } + return chunk.lines[n]; + } + + // Get the part of a document between two positions, as an array of + // strings. + function getBetween(doc, start, end) { + var out = [], n = start.line; + doc.iter(start.line, end.line + 1, function(line) { + var text = line.text; + if (n == end.line) text = text.slice(0, end.ch); + if (n == start.line) text = text.slice(start.ch); + out.push(text); + ++n; + }); + return out; + } + // Get the lines between from and to, as array of strings. + function getLines(doc, from, to) { + var out = []; + doc.iter(from, to, function(line) { out.push(line.text); }); + return out; + } + + // Update the height of a line, propagating the height change + // upwards to parent nodes. + function updateLineHeight(line, height) { + var diff = height - line.height; + if (diff) for (var n = line; n; n = n.parent) n.height += diff; + } + + // Given a line object, find its line number by walking up through + // its parent links. + function lineNo(line) { + if (line.parent == null) return null; + var cur = line.parent, no = indexOf(cur.lines, line); + for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { + for (var i = 0;; ++i) { + if (chunk.children[i] == cur) break; + no += chunk.children[i].chunkSize(); + } + } + return no + cur.first; + } + + // Find the line at the given vertical position, using the height + // information in the document tree. + function lineAtHeight(chunk, h) { + var n = chunk.first; + outer: do { + for (var i = 0; i < chunk.children.length; ++i) { + var child = chunk.children[i], ch = child.height; + if (h < ch) { chunk = child; continue outer; } + h -= ch; + n += child.chunkSize(); + } + return n; + } while (!chunk.lines); + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i], lh = line.height; + if (h < lh) break; + h -= lh; + } + return n + i; + } + + + // Find the height above the given line. + function heightAtLine(lineObj) { + lineObj = visualLine(lineObj); + + var h = 0, chunk = lineObj.parent; + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i]; + if (line == lineObj) break; + else h += line.height; + } + for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { + for (var i = 0; i < p.children.length; ++i) { + var cur = p.children[i]; + if (cur == chunk) break; + else h += cur.height; + } + } + return h; + } + + // Get the bidi ordering for the given line (and cache it). Returns + // false for lines that are fully left-to-right, and an array of + // BidiSpan objects otherwise. + function getOrder(line) { + var order = line.order; + if (order == null) order = line.order = bidiOrdering(line.text); + return order; + } + + // HISTORY + + function History(startGen) { + // Arrays of change events and selections. Doing something adds an + // event to done and clears undo. Undoing moves events from done + // to undone, redoing moves them in the other direction. + this.done = []; this.undone = []; + this.undoDepth = Infinity; + // Used to track when changes can be merged into a single undo + // event + this.lastModTime = this.lastSelTime = 0; + this.lastOp = null; + this.lastOrigin = this.lastSelOrigin = null; + // Used by the isClean() method + this.generation = this.maxGeneration = startGen || 1; + } + + // Create a history change event from an updateDoc-style change + // object. + function historyChangeFromChange(doc, change) { + var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; + attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); + linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true); + return histChange; + } + + // Pop all selection events off the end of a history array. Stop at + // a change event. + function clearSelectionEvents(array) { + while (array.length) { + var last = lst(array); + if (last.ranges) array.pop(); + else break; + } + } + + // Find the top change event in the history. Pop off selection + // events that are in the way. + function lastChangeEvent(hist, force) { + if (force) { + clearSelectionEvents(hist.done); + return lst(hist.done); + } else if (hist.done.length && !lst(hist.done).ranges) { + return lst(hist.done); + } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { + hist.done.pop(); + return lst(hist.done); + } + } + + // Register a change in the history. Merges changes that are within + // a single operation, ore are close together with an origin that + // allows merging (starting with "+") into a single event. + function addChangeToHistory(doc, change, selAfter, opId) { + var hist = doc.history; + hist.undone.length = 0; + var time = +new Date, cur; + + if ((hist.lastOp == opId || + hist.lastOrigin == change.origin && change.origin && + ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) || + change.origin.charAt(0) == "*")) && + (cur = lastChangeEvent(hist, hist.lastOp == opId))) { + // Merge this change into the last event + var last = lst(cur.changes); + if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { + // Optimized case for simple insertion -- don't want to add + // new changesets for every character typed + last.to = changeEnd(change); + } else { + // Add new sub-event + cur.changes.push(historyChangeFromChange(doc, change)); + } + } else { + // Can not be merged, start a new event. + var before = lst(hist.done); + if (!before || !before.ranges) + pushSelectionToHistory(doc.sel, hist.done); + cur = {changes: [historyChangeFromChange(doc, change)], + generation: hist.generation}; + hist.done.push(cur); + while (hist.done.length > hist.undoDepth) { + hist.done.shift(); + if (!hist.done[0].ranges) hist.done.shift(); + } + } + hist.done.push(selAfter); + hist.generation = ++hist.maxGeneration; + hist.lastModTime = hist.lastSelTime = time; + hist.lastOp = opId; + hist.lastOrigin = hist.lastSelOrigin = change.origin; + + if (!last) signal(doc, "historyAdded"); + } + + function selectionEventCanBeMerged(doc, origin, prev, sel) { + var ch = origin.charAt(0); + return ch == "*" || + ch == "+" && + prev.ranges.length == sel.ranges.length && + prev.somethingSelected() == sel.somethingSelected() && + new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500); + } + + // Called whenever the selection changes, sets the new selection as + // the pending selection in the history, and pushes the old pending + // selection into the 'done' array when it was significantly + // different (in number of selected ranges, emptiness, or time). + function addSelectionToHistory(doc, sel, opId, options) { + var hist = doc.history, origin = options && options.origin; + + // A new event is started when the previous origin does not match + // the current, or the origins don't allow matching. Origins + // starting with * are always merged, those starting with + are + // merged when similar and close together in time. + if (opId == hist.lastOp || + (origin && hist.lastSelOrigin == origin && + (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || + selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) + hist.done[hist.done.length - 1] = sel; + else + pushSelectionToHistory(sel, hist.done); + + hist.lastSelTime = +new Date; + hist.lastSelOrigin = origin; + hist.lastOp = opId; + if (options && options.clearRedo !== false) + clearSelectionEvents(hist.undone); + } + + function pushSelectionToHistory(sel, dest) { + var top = lst(dest); + if (!(top && top.ranges && top.equals(sel))) + dest.push(sel); + } + + // Used to store marked span information in the history. + function attachLocalSpans(doc, change, from, to) { + var existing = change["spans_" + doc.id], n = 0; + doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) { + if (line.markedSpans) + (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; + ++n; + }); + } + + // When un/re-doing restores text containing marked spans, those + // that have been explicitly cleared should not be restored. + function removeClearedSpans(spans) { + if (!spans) return null; + for (var i = 0, out; i < spans.length; ++i) { + if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); } + else if (out) out.push(spans[i]); + } + return !out ? spans : out.length ? out : null; + } + + // Retrieve and filter the old marked spans stored in a change event. + function getOldSpans(doc, change) { + var found = change["spans_" + doc.id]; + if (!found) return null; + for (var i = 0, nw = []; i < change.text.length; ++i) + nw.push(removeClearedSpans(found[i])); + return nw; + } + + // Used both to provide a JSON-safe object in .getHistory, and, when + // detaching a document, to split the history in two + function copyHistoryArray(events, newGroup, instantiateSel) { + for (var i = 0, copy = []; i < events.length; ++i) { + var event = events[i]; + if (event.ranges) { + copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event); + continue; + } + var changes = event.changes, newChanges = []; + copy.push({changes: newChanges}); + for (var j = 0; j < changes.length; ++j) { + var change = changes[j], m; + newChanges.push({from: change.from, to: change.to, text: change.text}); + if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { + if (indexOf(newGroup, Number(m[1])) > -1) { + lst(newChanges)[prop] = change[prop]; + delete change[prop]; + } + } + } + } + return copy; + } + + // Rebasing/resetting history to deal with externally-sourced changes + + function rebaseHistSelSingle(pos, from, to, diff) { + if (to < pos.line) { + pos.line += diff; + } else if (from < pos.line) { + pos.line = from; + pos.ch = 0; + } + } + + // Tries to rebase an array of history events given a change in the + // document. If the change touches the same lines as the event, the + // event, and everything 'behind' it, is discarded. If the change is + // before the event, the event's positions are updated. Uses a + // copy-on-write scheme for the positions, to avoid having to + // reallocate them all on every rebase, but also avoid problems with + // shared position objects being unsafely updated. + function rebaseHistArray(array, from, to, diff) { + for (var i = 0; i < array.length; ++i) { + var sub = array[i], ok = true; + if (sub.ranges) { + if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; } + for (var j = 0; j < sub.ranges.length; j++) { + rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff); + rebaseHistSelSingle(sub.ranges[j].head, from, to, diff); + } + continue; + } + for (var j = 0; j < sub.changes.length; ++j) { + var cur = sub.changes[j]; + if (to < cur.from.line) { + cur.from = Pos(cur.from.line + diff, cur.from.ch); + cur.to = Pos(cur.to.line + diff, cur.to.ch); + } else if (from <= cur.to.line) { + ok = false; + break; + } + } + if (!ok) { + array.splice(0, i + 1); + i = 0; + } + } + } + + function rebaseHist(hist, change) { + var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; + rebaseHistArray(hist.done, from, to, diff); + rebaseHistArray(hist.undone, from, to, diff); + } + + // EVENT UTILITIES + + // Due to the fact that we still support jurassic IE versions, some + // compatibility wrappers are needed. + + var e_preventDefault = CodeMirror.e_preventDefault = function(e) { + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + }; + var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) { + if (e.stopPropagation) e.stopPropagation(); + else e.cancelBubble = true; + }; + function e_defaultPrevented(e) { + return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false; + } + var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);}; + + function e_target(e) {return e.target || e.srcElement;} + function e_button(e) { + var b = e.which; + if (b == null) { + if (e.button & 1) b = 1; + else if (e.button & 2) b = 3; + else if (e.button & 4) b = 2; + } + if (mac && e.ctrlKey && b == 1) b = 3; + return b; + } + + // EVENT HANDLING + + // Lightweight event framework. on/off also work on DOM nodes, + // registering native DOM handlers. + + var on = CodeMirror.on = function(emitter, type, f) { + if (emitter.addEventListener) + emitter.addEventListener(type, f, false); + else if (emitter.attachEvent) + emitter.attachEvent("on" + type, f); + else { + var map = emitter._handlers || (emitter._handlers = {}); + var arr = map[type] || (map[type] = []); + arr.push(f); + } + }; + + var off = CodeMirror.off = function(emitter, type, f) { + if (emitter.removeEventListener) + emitter.removeEventListener(type, f, false); + else if (emitter.detachEvent) + emitter.detachEvent("on" + type, f); + else { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + for (var i = 0; i < arr.length; ++i) + if (arr[i] == f) { arr.splice(i, 1); break; } + } + }; + + var signal = CodeMirror.signal = function(emitter, type /*, values...*/) { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + var args = Array.prototype.slice.call(arguments, 2); + for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args); + }; + + // Often, we want to signal events at a point where we are in the + // middle of some work, but don't want the handler to start calling + // other methods on the editor, which might be in an inconsistent + // state or simply not expect any other events to happen. + // signalLater looks whether there are any handlers, and schedules + // them to be executed when the last operation ends, or, if no + // operation is active, when a timeout fires. + var delayedCallbacks, delayedCallbackDepth = 0; + function signalLater(emitter, type /*, values...*/) { + var arr = emitter._handlers && emitter._handlers[type]; + if (!arr) return; + var args = Array.prototype.slice.call(arguments, 2); + if (!delayedCallbacks) { + ++delayedCallbackDepth; + delayedCallbacks = []; + setTimeout(fireDelayed, 0); + } + function bnd(f) {return function(){f.apply(null, args);};}; + for (var i = 0; i < arr.length; ++i) + delayedCallbacks.push(bnd(arr[i])); + } + + function fireDelayed() { + --delayedCallbackDepth; + var delayed = delayedCallbacks; + delayedCallbacks = null; + for (var i = 0; i < delayed.length; ++i) delayed[i](); + } + + // The DOM events that CodeMirror handles can be overridden by + // registering a (non-DOM) handler on the editor for the event name, + // and preventDefault-ing the event in that handler. + function signalDOMEvent(cm, e, override) { + signal(cm, override || e.type, cm, e); + return e_defaultPrevented(e) || e.codemirrorIgnore; + } + + function signalCursorActivity(cm) { + var arr = cm._handlers && cm._handlers.cursorActivity; + if (!arr) return; + var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []); + for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1) + set.push(arr[i]); + } + + function hasHandler(emitter, type) { + var arr = emitter._handlers && emitter._handlers[type]; + return arr && arr.length > 0; + } + + // Add on and off methods to a constructor's prototype, to make + // registering events on such objects more convenient. + function eventMixin(ctor) { + ctor.prototype.on = function(type, f) {on(this, type, f);}; + ctor.prototype.off = function(type, f) {off(this, type, f);}; + } + + // MISC UTILITIES + + // Number of pixels added to scroller and sizer to hide scrollbar + var scrollerCutOff = 30; + + // Returned or thrown by various protocols to signal 'I'm not + // handling this'. + var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}}; + + // Reused option objects for setSelection & friends + var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"}; + + function Delayed() {this.id = null;} + Delayed.prototype.set = function(ms, f) { + clearTimeout(this.id); + this.id = setTimeout(f, ms); + }; + + // Counts the column offset in a string, taking tabs into account. + // Used mostly to find indentation. + var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) { + if (end == null) { + end = string.search(/[^\s\u00a0]/); + if (end == -1) end = string.length; + } + for (var i = startIndex || 0, n = startValue || 0;;) { + var nextTab = string.indexOf("\t", i); + if (nextTab < 0 || nextTab >= end) + return n + (end - i); + n += nextTab - i; + n += tabSize - (n % tabSize); + i = nextTab + 1; + } + }; + + // The inverse of countColumn -- find the offset that corresponds to + // a particular column. + function findColumn(string, goal, tabSize) { + for (var pos = 0, col = 0;;) { + var nextTab = string.indexOf("\t", pos); + if (nextTab == -1) nextTab = string.length; + var skipped = nextTab - pos; + if (nextTab == string.length || col + skipped >= goal) + return pos + Math.min(skipped, goal - col); + col += nextTab - pos; + col += tabSize - (col % tabSize); + pos = nextTab + 1; + if (col >= goal) return pos; + } + } + + var spaceStrs = [""]; + function spaceStr(n) { + while (spaceStrs.length <= n) + spaceStrs.push(lst(spaceStrs) + " "); + return spaceStrs[n]; + } + + function lst(arr) { return arr[arr.length-1]; } + + var selectInput = function(node) { node.select(); }; + if (ios) // Mobile Safari apparently has a bug where select() is broken. + selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; + else if (ie) // Suppress mysterious IE10 errors + selectInput = function(node) { try { node.select(); } catch(_e) {} }; + + function indexOf(array, elt) { + for (var i = 0; i < array.length; ++i) + if (array[i] == elt) return i; + return -1; + } + if ([].indexOf) indexOf = function(array, elt) { return array.indexOf(elt); }; + function map(array, f) { + var out = []; + for (var i = 0; i < array.length; i++) out[i] = f(array[i], i); + return out; + } + if ([].map) map = function(array, f) { return array.map(f); }; + + function createObj(base, props) { + var inst; + if (Object.create) { + inst = Object.create(base); + } else { + var ctor = function() {}; + ctor.prototype = base; + inst = new ctor(); + } + if (props) copyObj(props, inst); + return inst; + }; + + function copyObj(obj, target, overwrite) { + if (!target) target = {}; + for (var prop in obj) + if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) + target[prop] = obj[prop]; + return target; + } + + function bind(f) { + var args = Array.prototype.slice.call(arguments, 1); + return function(){return f.apply(null, args);}; + } + + var nonASCIISingleCaseWordChar = /[\u00df\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; + var isWordCharBasic = CodeMirror.isWordChar = function(ch) { + return /\w/.test(ch) || ch > "\x80" && + (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); + }; + function isWordChar(ch, helper) { + if (!helper) return isWordCharBasic(ch); + if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true; + return helper.test(ch); + } + + function isEmpty(obj) { + for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; + return true; + } + + // Extending unicode characters. A series of a non-extending char + + // any number of extending chars is treated as a single unit as far + // as editing and measuring is concerned. This is not fully correct, + // since some scripts/fonts/browsers also treat other configurations + // of code points as a group. + var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/; + function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); } + + // DOM UTILITIES + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + var range; + if (document.createRange) range = function(node, start, end) { + var r = document.createRange(); + r.setEnd(node, end); + r.setStart(node, start); + return r; + }; + else range = function(node, start, end) { + var r = document.body.createTextRange(); + r.moveToElementText(node.parentNode); + r.collapse(true); + r.moveEnd("character", end); + r.moveStart("character", start); + return r; + }; + + function removeChildren(e) { + for (var count = e.childNodes.length; count > 0; --count) + e.removeChild(e.firstChild); + return e; + } + + function removeChildrenAndAdd(parent, e) { + return removeChildren(parent).appendChild(e); + } + + function contains(parent, child) { + if (parent.contains) + return parent.contains(child); + while (child = child.parentNode) + if (child == parent) return true; + } + + function activeElt() { return document.activeElement; } + // Older versions of IE throws unspecified error when touching + // document.activeElement in some cases (during loading, in iframe) + if (ie && ie_version < 11) activeElt = function() { + try { return document.activeElement; } + catch(e) { return document.body; } + }; + + function classTest(cls) { return new RegExp("\\b" + cls + "\\b\\s*"); } + function rmClass(node, cls) { + var test = classTest(cls); + if (test.test(node.className)) node.className = node.className.replace(test, ""); + } + function addClass(node, cls) { + if (!classTest(cls).test(node.className)) node.className += " " + cls; + } + function joinClasses(a, b) { + var as = a.split(" "); + for (var i = 0; i < as.length; i++) + if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]; + return b; + } + + // WINDOW-WIDE EVENTS + + // These must be handled carefully, because naively registering a + // handler for each editor will cause the editors to never be + // garbage collected. + + function forEachCodeMirror(f) { + if (!document.body.getElementsByClassName) return; + var byClass = document.body.getElementsByClassName("CodeMirror"); + for (var i = 0; i < byClass.length; i++) { + var cm = byClass[i].CodeMirror; + if (cm) f(cm); + } + } + + var globalsRegistered = false; + function ensureGlobalHandlers() { + if (globalsRegistered) return; + registerGlobalHandlers(); + globalsRegistered = true; + } + function registerGlobalHandlers() { + // When the window resizes, we need to refresh active editors. + var resizeTimer; + on(window, "resize", function() { + if (resizeTimer == null) resizeTimer = setTimeout(function() { + resizeTimer = null; + knownScrollbarWidth = null; + forEachCodeMirror(onResize); + }, 100); + }); + // When the window loses focus, we want to show the editor as blurred + on(window, "blur", function() { + forEachCodeMirror(onBlur); + }); + } + + // FEATURE DETECTION + + // Detect drag-and-drop + var dragAndDrop = function() { + // There is *some* kind of drag-and-drop support in IE6-8, but I + // couldn't get it to work yet. + if (ie && ie_version < 9) return false; + var div = elt('div'); + return "draggable" in div || "dragDrop" in div; + }(); + + var knownScrollbarWidth; + function scrollbarWidth(measure) { + if (knownScrollbarWidth != null) return knownScrollbarWidth; + var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: scroll"); + removeChildrenAndAdd(measure, test); + if (test.offsetWidth) + knownScrollbarWidth = test.offsetHeight - test.clientHeight; + return knownScrollbarWidth || 0; + } + + var zwspSupported; + function zeroWidthElement(measure) { + if (zwspSupported == null) { + var test = elt("span", "\u200b"); + removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); + if (measure.firstChild.offsetHeight != 0) + zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); + } + if (zwspSupported) return elt("span", "\u200b"); + else return elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); + } + + // Feature-detect IE's crummy client rect reporting for bidi text + var badBidiRects; + function hasBadBidiRects(measure) { + if (badBidiRects != null) return badBidiRects; + var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")); + var r0 = range(txt, 0, 1).getBoundingClientRect(); + if (r0.left == r0.right) return false; + var r1 = range(txt, 1, 2).getBoundingClientRect(); + return badBidiRects = (r1.right - r0.right < 3); + } + + // See if "".split is the broken IE version, if so, provide an + // alternative way to split lines. + var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) { + var pos = 0, result = [], l = string.length; + while (pos <= l) { + var nl = string.indexOf("\n", pos); + if (nl == -1) nl = string.length; + var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); + var rt = line.indexOf("\r"); + if (rt != -1) { + result.push(line.slice(0, rt)); + pos += rt + 1; + } else { + result.push(line); + pos = nl + 1; + } + } + return result; + } : function(string){return string.split(/\r\n?|\n/);}; + + var hasSelection = window.getSelection ? function(te) { + try { return te.selectionStart != te.selectionEnd; } + catch(e) { return false; } + } : function(te) { + try {var range = te.ownerDocument.selection.createRange();} + catch(e) {} + if (!range || range.parentElement() != te) return false; + return range.compareEndPoints("StartToEnd", range) != 0; + }; + + var hasCopyEvent = (function() { + var e = elt("div"); + if ("oncopy" in e) return true; + e.setAttribute("oncopy", "return;"); + return typeof e.oncopy == "function"; + })(); + + // KEY NAMES + + var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", + 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", + 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", + 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete", + 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", + 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"}; + CodeMirror.keyNames = keyNames; + (function() { + // Number keys + for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i); + // Alphabetic keys + for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i); + // Function keys + for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i; + })(); + + // BIDI HELPERS + + function iterateBidiSections(order, from, to, f) { + if (!order) return f(from, to, "ltr"); + var found = false; + for (var i = 0; i < order.length; ++i) { + var part = order[i]; + if (part.from < to && part.to > from || from == to && part.to == from) { + f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr"); + found = true; + } + } + if (!found) f(from, to, "ltr"); + } + + function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } + function bidiRight(part) { return part.level % 2 ? part.from : part.to; } + + function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; } + function lineRight(line) { + var order = getOrder(line); + if (!order) return line.text.length; + return bidiRight(lst(order)); + } + + function lineStart(cm, lineN) { + var line = getLine(cm.doc, lineN); + var visual = visualLine(line); + if (visual != line) lineN = lineNo(visual); + var order = getOrder(visual); + var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); + return Pos(lineN, ch); + } + function lineEnd(cm, lineN) { + var merged, line = getLine(cm.doc, lineN); + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line; + lineN = null; + } + var order = getOrder(line); + var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); + return Pos(lineN == null ? lineNo(line) : lineN, ch); + } + + function compareBidiLevel(order, a, b) { + var linedir = order[0].level; + if (a == linedir) return true; + if (b == linedir) return false; + return a < b; + } + var bidiOther; + function getBidiPartAt(order, pos) { + bidiOther = null; + for (var i = 0, found; i < order.length; ++i) { + var cur = order[i]; + if (cur.from < pos && cur.to > pos) return i; + if ((cur.from == pos || cur.to == pos)) { + if (found == null) { + found = i; + } else if (compareBidiLevel(order, cur.level, order[found].level)) { + if (cur.from != cur.to) bidiOther = found; + return i; + } else { + if (cur.from != cur.to) bidiOther = i; + return found; + } + } + } + return found; + } + + function moveInLine(line, pos, dir, byUnit) { + if (!byUnit) return pos + dir; + do pos += dir; + while (pos > 0 && isExtendingChar(line.text.charAt(pos))); + return pos; + } + + // This is needed in order to move 'visually' through bi-directional + // text -- i.e., pressing left should make the cursor go left, even + // when in RTL text. The tricky part is the 'jumps', where RTL and + // LTR text touch each other. This often requires the cursor offset + // to move more than one unit, in order to visually move one unit. + function moveVisually(line, start, dir, byUnit) { + var bidi = getOrder(line); + if (!bidi) return moveLogically(line, start, dir, byUnit); + var pos = getBidiPartAt(bidi, start), part = bidi[pos]; + var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); + + for (;;) { + if (target > part.from && target < part.to) return target; + if (target == part.from || target == part.to) { + if (getBidiPartAt(bidi, target) == pos) return target; + part = bidi[pos += dir]; + return (dir > 0) == part.level % 2 ? part.to : part.from; + } else { + part = bidi[pos += dir]; + if (!part) return null; + if ((dir > 0) == part.level % 2) + target = moveInLine(line, part.to, -1, byUnit); + else + target = moveInLine(line, part.from, 1, byUnit); + } + } + } + + function moveLogically(line, start, dir, byUnit) { + var target = start + dir; + if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir; + return target < 0 || target > line.text.length ? null : target; + } + + // Bidirectional ordering algorithm + // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm + // that this (partially) implements. + + // One-char codes used for character types: + // L (L): Left-to-Right + // R (R): Right-to-Left + // r (AL): Right-to-Left Arabic + // 1 (EN): European Number + // + (ES): European Number Separator + // % (ET): European Number Terminator + // n (AN): Arabic Number + // , (CS): Common Number Separator + // m (NSM): Non-Spacing Mark + // b (BN): Boundary Neutral + // s (B): Paragraph Separator + // t (S): Segment Separator + // w (WS): Whitespace + // N (ON): Other Neutrals + + // Returns null if characters are ordered as they appear + // (left-to-right), or an array of sections ({from, to, level} + // objects) in the order in which they occur visually. + var bidiOrdering = (function() { + // Character types for codepoints 0 to 0xff + var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"; + // Character types for codepoints 0x600 to 0x6ff + var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"; + function charType(code) { + if (code <= 0xf7) return lowTypes.charAt(code); + else if (0x590 <= code && code <= 0x5f4) return "R"; + else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600); + else if (0x6ee <= code && code <= 0x8ac) return "r"; + else if (0x2000 <= code && code <= 0x200b) return "w"; + else if (code == 0x200c) return "b"; + else return "L"; + } + + var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; + var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; + // Browsers seem to always treat the boundaries of block elements as being L. + var outerType = "L"; + + function BidiSpan(level, from, to) { + this.level = level; + this.from = from; this.to = to; + } + + return function(str) { + if (!bidiRE.test(str)) return false; + var len = str.length, types = []; + for (var i = 0, type; i < len; ++i) + types.push(type = charType(str.charCodeAt(i))); + + // W1. Examine each non-spacing mark (NSM) in the level run, and + // change the type of the NSM to the type of the previous + // character. If the NSM is at the start of the level run, it will + // get the type of sor. + for (var i = 0, prev = outerType; i < len; ++i) { + var type = types[i]; + if (type == "m") types[i] = prev; + else prev = type; + } + + // W2. Search backwards from each instance of a European number + // until the first strong type (R, L, AL, or sor) is found. If an + // AL is found, change the type of the European number to Arabic + // number. + // W3. Change all ALs to R. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (type == "1" && cur == "r") types[i] = "n"; + else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; } + } + + // W4. A single European separator between two European numbers + // changes to a European number. A single common separator between + // two numbers of the same type changes to that type. + for (var i = 1, prev = types[0]; i < len - 1; ++i) { + var type = types[i]; + if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1"; + else if (type == "," && prev == types[i+1] && + (prev == "1" || prev == "n")) types[i] = prev; + prev = type; + } + + // W5. A sequence of European terminators adjacent to European + // numbers changes to all European numbers. + // W6. Otherwise, separators and terminators change to Other + // Neutral. + for (var i = 0; i < len; ++i) { + var type = types[i]; + if (type == ",") types[i] = "N"; + else if (type == "%") { + for (var end = i + 1; end < len && types[end] == "%"; ++end) {} + var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // W7. Search backwards from each instance of a European number + // until the first strong type (R, L, or sor) is found. If an L is + // found, then change the type of the European number to L. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (cur == "L" && type == "1") types[i] = "L"; + else if (isStrong.test(type)) cur = type; + } + + // N1. A sequence of neutrals takes the direction of the + // surrounding strong text if the text on both sides has the same + // direction. European and Arabic numbers act as if they were R in + // terms of their influence on neutrals. Start-of-level-run (sor) + // and end-of-level-run (eor) are used at level run boundaries. + // N2. Any remaining neutrals take the embedding direction. + for (var i = 0; i < len; ++i) { + if (isNeutral.test(types[i])) { + for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {} + var before = (i ? types[i-1] : outerType) == "L"; + var after = (end < len ? types[end] : outerType) == "L"; + var replace = before || after ? "L" : "R"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // Here we depart from the documented algorithm, in order to avoid + // building up an actual levels array. Since there are only three + // levels (0, 1, 2) in an implementation that doesn't take + // explicit embedding into account, we can build up the order on + // the fly, without following the level-based algorithm. + var order = [], m; + for (var i = 0; i < len;) { + if (countsAsLeft.test(types[i])) { + var start = i; + for (++i; i < len && countsAsLeft.test(types[i]); ++i) {} + order.push(new BidiSpan(0, start, i)); + } else { + var pos = i, at = order.length; + for (++i; i < len && types[i] != "L"; ++i) {} + for (var j = pos; j < i;) { + if (countsAsNum.test(types[j])) { + if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j)); + var nstart = j; + for (++j; j < i && countsAsNum.test(types[j]); ++j) {} + order.splice(at, 0, new BidiSpan(2, nstart, j)); + pos = j; + } else ++j; + } + if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i)); + } + } + if (order[0].level == 1 && (m = str.match(/^\s+/))) { + order[0].from = m[0].length; + order.unshift(new BidiSpan(0, 0, m[0].length)); + } + if (lst(order).level == 1 && (m = str.match(/\s+$/))) { + lst(order).to -= m[0].length; + order.push(new BidiSpan(0, len - m[0].length, len)); + } + if (order[0].level != lst(order).level) + order.push(new BidiSpan(order[0].level, len, len)); + + return order; + }; + })(); + + // THE END + + CodeMirror.version = "4.3.0"; + + return CodeMirror; +}); diff --git a/Upload/admin/jscripts/codemirror/lib/index.html b/Upload/admin/jscripts/codemirror/lib/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/lib/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/jscripts/codemirror/mode/css/css.js b/Upload/admin/jscripts/codemirror/mode/css/css.js new file mode 100644 index 0000000..2678c57 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/css/css.js @@ -0,0 +1,717 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("css", function(config, parserConfig) { + if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css"); + + var indentUnit = config.indentUnit, + tokenHooks = parserConfig.tokenHooks, + mediaTypes = parserConfig.mediaTypes || {}, + mediaFeatures = parserConfig.mediaFeatures || {}, + propertyKeywords = parserConfig.propertyKeywords || {}, + nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {}, + colorKeywords = parserConfig.colorKeywords || {}, + valueKeywords = parserConfig.valueKeywords || {}, + fontProperties = parserConfig.fontProperties || {}, + allowNested = parserConfig.allowNested; + + var type, override; + function ret(style, tp) { type = tp; return style; } + + // Tokenizers + + function tokenBase(stream, state) { + var ch = stream.next(); + if (tokenHooks[ch]) { + var result = tokenHooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == "@") { + stream.eatWhile(/[\w\\\-]/); + return ret("def", stream.current()); + } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) { + return ret(null, "compare"); + } else if (ch == "\"" || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (ch == "#") { + stream.eatWhile(/[\w\\\-]/); + return ret("atom", "hash"); + } else if (ch == "!") { + stream.match(/^\s*\w*/); + return ret("keyword", "important"); + } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) { + stream.eatWhile(/[\w.%]/); + return ret("number", "unit"); + } else if (ch === "-") { + if (/[\d.]/.test(stream.peek())) { + stream.eatWhile(/[\w.%]/); + return ret("number", "unit"); + } else if (stream.match(/^\w+-/)) { + return ret("meta", "meta"); + } + } else if (/[,+>*\/]/.test(ch)) { + return ret(null, "select-op"); + } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) { + return ret("qualifier", "qualifier"); + } else if (/[:;{}\[\]\(\)]/.test(ch)) { + return ret(null, ch); + } else if (ch == "u" && stream.match("rl(")) { + stream.backUp(1); + state.tokenize = tokenParenthesized; + return ret("property", "word"); + } else if (/[\w\\\-]/.test(ch)) { + stream.eatWhile(/[\w\\\-]/); + return ret("property", "word"); + } else { + return ret(null, null); + } + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + if (quote == ")") stream.backUp(1); + break; + } + escaped = !escaped && ch == "\\"; + } + if (ch == quote || !escaped && quote != ")") state.tokenize = null; + return ret("string", "string"); + }; + } + + function tokenParenthesized(stream, state) { + stream.next(); // Must be '(' + if (!stream.match(/\s*[\"\')]/, false)) + state.tokenize = tokenString(")"); + else + state.tokenize = null; + return ret(null, "("); + } + + // Context management + + function Context(type, indent, prev) { + this.type = type; + this.indent = indent; + this.prev = prev; + } + + function pushContext(state, stream, type) { + state.context = new Context(type, stream.indentation() + indentUnit, state.context); + return type; + } + + function popContext(state) { + state.context = state.context.prev; + return state.context.type; + } + + function pass(type, stream, state) { + return states[state.context.type](type, stream, state); + } + function popAndPass(type, stream, state, n) { + for (var i = n || 1; i > 0; i--) + state.context = state.context.prev; + return pass(type, stream, state); + } + + // Parser + + function wordAsValue(stream) { + var word = stream.current().toLowerCase(); + if (valueKeywords.hasOwnProperty(word)) + override = "atom"; + else if (colorKeywords.hasOwnProperty(word)) + override = "keyword"; + else + override = "variable"; + } + + var states = {}; + + states.top = function(type, stream, state) { + if (type == "{") { + return pushContext(state, stream, "block"); + } else if (type == "}" && state.context.prev) { + return popContext(state); + } else if (type == "@media") { + return pushContext(state, stream, "media"); + } else if (type == "@font-face") { + return "font_face_before"; + } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) { + return "keyframes"; + } else if (type && type.charAt(0) == "@") { + return pushContext(state, stream, "at"); + } else if (type == "hash") { + override = "builtin"; + } else if (type == "word") { + override = "tag"; + } else if (type == "variable-definition") { + return "maybeprop"; + } else if (type == "interpolation") { + return pushContext(state, stream, "interpolation"); + } else if (type == ":") { + return "pseudo"; + } else if (allowNested && type == "(") { + return pushContext(state, stream, "parens"); + } + return state.context.type; + }; + + states.block = function(type, stream, state) { + if (type == "word") { + var word = stream.current().toLowerCase(); + if (propertyKeywords.hasOwnProperty(word)) { + override = "property"; + return "maybeprop"; + } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) { + override = "string-2"; + return "maybeprop"; + } else if (allowNested) { + override = stream.match(/^\s*:/, false) ? "property" : "tag"; + return "block"; + } else { + override += " error"; + return "maybeprop"; + } + } else if (type == "meta") { + return "block"; + } else if (!allowNested && (type == "hash" || type == "qualifier")) { + override = "error"; + return "block"; + } else { + return states.top(type, stream, state); + } + }; + + states.maybeprop = function(type, stream, state) { + if (type == ":") return pushContext(state, stream, "prop"); + return pass(type, stream, state); + }; + + states.prop = function(type, stream, state) { + if (type == ";") return popContext(state); + if (type == "{" && allowNested) return pushContext(state, stream, "propBlock"); + if (type == "}" || type == "{") return popAndPass(type, stream, state); + if (type == "(") return pushContext(state, stream, "parens"); + + if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) { + override += " error"; + } else if (type == "word") { + wordAsValue(stream); + } else if (type == "interpolation") { + return pushContext(state, stream, "interpolation"); + } + return "prop"; + }; + + states.propBlock = function(type, _stream, state) { + if (type == "}") return popContext(state); + if (type == "word") { override = "property"; return "maybeprop"; } + return state.context.type; + }; + + states.parens = function(type, stream, state) { + if (type == "{" || type == "}") return popAndPass(type, stream, state); + if (type == ")") return popContext(state); + if (type == "(") return pushContext(state, stream, "parens"); + if (type == "word") wordAsValue(stream); + return "parens"; + }; + + states.pseudo = function(type, stream, state) { + if (type == "word") { + override = "variable-3"; + return state.context.type; + } + return pass(type, stream, state); + }; + + states.media = function(type, stream, state) { + if (type == "(") return pushContext(state, stream, "media_parens"); + if (type == "}") return popAndPass(type, stream, state); + if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top"); + + if (type == "word") { + var word = stream.current().toLowerCase(); + if (word == "only" || word == "not" || word == "and") + override = "keyword"; + else if (mediaTypes.hasOwnProperty(word)) + override = "attribute"; + else if (mediaFeatures.hasOwnProperty(word)) + override = "property"; + else + override = "error"; + } + return state.context.type; + }; + + states.media_parens = function(type, stream, state) { + if (type == ")") return popContext(state); + if (type == "{" || type == "}") return popAndPass(type, stream, state, 2); + return states.media(type, stream, state); + }; + + states.font_face_before = function(type, stream, state) { + if (type == "{") + return pushContext(state, stream, "font_face"); + return pass(type, stream, state); + }; + + states.font_face = function(type, stream, state) { + if (type == "}") return popContext(state); + if (type == "word") { + if (!fontProperties.hasOwnProperty(stream.current().toLowerCase())) + override = "error"; + else + override = "property"; + return "maybeprop"; + } + return "font_face"; + }; + + states.keyframes = function(type, stream, state) { + if (type == "word") { override = "variable"; return "keyframes"; } + if (type == "{") return pushContext(state, stream, "top"); + return pass(type, stream, state); + }; + + states.at = function(type, stream, state) { + if (type == ";") return popContext(state); + if (type == "{" || type == "}") return popAndPass(type, stream, state); + if (type == "word") override = "tag"; + else if (type == "hash") override = "builtin"; + return "at"; + }; + + states.interpolation = function(type, stream, state) { + if (type == "}") return popContext(state); + if (type == "{" || type == ";") return popAndPass(type, stream, state); + if (type != "variable") override = "error"; + return "interpolation"; + }; + + return { + startState: function(base) { + return {tokenize: null, + state: "top", + context: new Context("top", base || 0, null)}; + }, + + token: function(stream, state) { + if (!state.tokenize && stream.eatSpace()) return null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style && typeof style == "object") { + type = style[1]; + style = style[0]; + } + override = style; + state.state = states[state.state](type, stream, state); + return override; + }, + + indent: function(state, textAfter) { + var cx = state.context, ch = textAfter && textAfter.charAt(0); + var indent = cx.indent; + if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev; + if (cx.prev && + (ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") || + ch == ")" && (cx.type == "parens" || cx.type == "media_parens") || + ch == "{" && (cx.type == "at" || cx.type == "media"))) { + indent = cx.indent - indentUnit; + cx = cx.prev; + } + return indent; + }, + + electricChars: "}", + blockCommentStart: "/*", + blockCommentEnd: "*/", + fold: "brace" + }; +}); + + function keySet(array) { + var keys = {}; + for (var i = 0; i < array.length; ++i) { + keys[array[i]] = true; + } + return keys; + } + + var mediaTypes_ = [ + "all", "aural", "braille", "handheld", "print", "projection", "screen", + "tty", "tv", "embossed" + ], mediaTypes = keySet(mediaTypes_); + + var mediaFeatures_ = [ + "width", "min-width", "max-width", "height", "min-height", "max-height", + "device-width", "min-device-width", "max-device-width", "device-height", + "min-device-height", "max-device-height", "aspect-ratio", + "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio", + "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color", + "max-color", "color-index", "min-color-index", "max-color-index", + "monochrome", "min-monochrome", "max-monochrome", "resolution", + "min-resolution", "max-resolution", "scan", "grid" + ], mediaFeatures = keySet(mediaFeatures_); + + var propertyKeywords_ = [ + "align-content", "align-items", "align-self", "alignment-adjust", + "alignment-baseline", "anchor-point", "animation", "animation-delay", + "animation-direction", "animation-duration", "animation-fill-mode", + "animation-iteration-count", "animation-name", "animation-play-state", + "animation-timing-function", "appearance", "azimuth", "backface-visibility", + "background", "background-attachment", "background-clip", "background-color", + "background-image", "background-origin", "background-position", + "background-repeat", "background-size", "baseline-shift", "binding", + "bleed", "bookmark-label", "bookmark-level", "bookmark-state", + "bookmark-target", "border", "border-bottom", "border-bottom-color", + "border-bottom-left-radius", "border-bottom-right-radius", + "border-bottom-style", "border-bottom-width", "border-collapse", + "border-color", "border-image", "border-image-outset", + "border-image-repeat", "border-image-slice", "border-image-source", + "border-image-width", "border-left", "border-left-color", + "border-left-style", "border-left-width", "border-radius", "border-right", + "border-right-color", "border-right-style", "border-right-width", + "border-spacing", "border-style", "border-top", "border-top-color", + "border-top-left-radius", "border-top-right-radius", "border-top-style", + "border-top-width", "border-width", "bottom", "box-decoration-break", + "box-shadow", "box-sizing", "break-after", "break-before", "break-inside", + "caption-side", "clear", "clip", "color", "color-profile", "column-count", + "column-fill", "column-gap", "column-rule", "column-rule-color", + "column-rule-style", "column-rule-width", "column-span", "column-width", + "columns", "content", "counter-increment", "counter-reset", "crop", "cue", + "cue-after", "cue-before", "cursor", "direction", "display", + "dominant-baseline", "drop-initial-after-adjust", + "drop-initial-after-align", "drop-initial-before-adjust", + "drop-initial-before-align", "drop-initial-size", "drop-initial-value", + "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis", + "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", + "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings", + "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust", + "font-stretch", "font-style", "font-synthesis", "font-variant", + "font-variant-alternates", "font-variant-caps", "font-variant-east-asian", + "font-variant-ligatures", "font-variant-numeric", "font-variant-position", + "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", + "grid-auto-position", "grid-auto-rows", "grid-column", "grid-column-end", + "grid-column-start", "grid-row", "grid-row-end", "grid-row-start", + "grid-template", "grid-template-areas", "grid-template-columns", + "grid-template-rows", "hanging-punctuation", "height", "hyphens", + "icon", "image-orientation", "image-rendering", "image-resolution", + "inline-box-align", "justify-content", "left", "letter-spacing", + "line-break", "line-height", "line-stacking", "line-stacking-ruby", + "line-stacking-shift", "line-stacking-strategy", "list-style", + "list-style-image", "list-style-position", "list-style-type", "margin", + "margin-bottom", "margin-left", "margin-right", "margin-top", + "marker-offset", "marks", "marquee-direction", "marquee-loop", + "marquee-play-count", "marquee-speed", "marquee-style", "max-height", + "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index", + "nav-left", "nav-right", "nav-up", "object-fit", "object-position", + "opacity", "order", "orphans", "outline", + "outline-color", "outline-offset", "outline-style", "outline-width", + "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y", + "padding", "padding-bottom", "padding-left", "padding-right", "padding-top", + "page", "page-break-after", "page-break-before", "page-break-inside", + "page-policy", "pause", "pause-after", "pause-before", "perspective", + "perspective-origin", "pitch", "pitch-range", "play-during", "position", + "presentation-level", "punctuation-trim", "quotes", "region-break-after", + "region-break-before", "region-break-inside", "region-fragment", + "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness", + "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang", + "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin", + "shape-outside", "size", "speak", "speak-as", "speak-header", + "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set", + "tab-size", "table-layout", "target", "target-name", "target-new", + "target-position", "text-align", "text-align-last", "text-decoration", + "text-decoration-color", "text-decoration-line", "text-decoration-skip", + "text-decoration-style", "text-emphasis", "text-emphasis-color", + "text-emphasis-position", "text-emphasis-style", "text-height", + "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow", + "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position", + "text-wrap", "top", "transform", "transform-origin", "transform-style", + "transition", "transition-delay", "transition-duration", + "transition-property", "transition-timing-function", "unicode-bidi", + "vertical-align", "visibility", "voice-balance", "voice-duration", + "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", + "voice-volume", "volume", "white-space", "widows", "width", "word-break", + "word-spacing", "word-wrap", "z-index", + // SVG-specific + "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", + "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", + "color-interpolation", "color-interpolation-filters", + "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", + "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke", + "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", + "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", + "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", + "glyph-orientation-vertical", "text-anchor", "writing-mode" + ], propertyKeywords = keySet(propertyKeywords_); + + var nonStandardPropertyKeywords = [ + "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", + "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", + "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside", + "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", + "searchfield-results-decoration", "zoom" + ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords); + + var colorKeywords_ = [ + "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", + "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", + "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", + "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", + "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", + "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", + "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", + "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", + "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", + "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", + "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", + "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", + "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink", + "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", + "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", + "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", + "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", + "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", + "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", + "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", + "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", + "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", + "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", + "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", + "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", + "whitesmoke", "yellow", "yellowgreen" + ], colorKeywords = keySet(colorKeywords_); + + var valueKeywords_ = [ + "above", "absolute", "activeborder", "activecaption", "afar", + "after-white-space", "ahead", "alias", "all", "all-scroll", "alternate", + "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", + "arabic-indic", "armenian", "asterisks", "auto", "avoid", "avoid-column", "avoid-page", + "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary", + "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", + "both", "bottom", "break", "break-all", "break-word", "button", "button-bevel", + "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian", + "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", + "cell", "center", "checkbox", "circle", "cjk-earthly-branch", + "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", + "col-resize", "collapse", "column", "compact", "condensed", "contain", "content", + "content-box", "context-menu", "continuous", "copy", "cover", "crop", + "cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal", + "decimal-leading-zero", "default", "default-button", "destination-atop", + "destination-in", "destination-out", "destination-over", "devanagari", + "disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted", + "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", + "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede", + "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er", + "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", + "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et", + "ethiopic-halehame-gez", "ethiopic-halehame-om-et", + "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", + "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", + "ethiopic-halehame-tig", "ew-resize", "expanded", "extra-condensed", + "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes", + "forwards", "from", "geometricPrecision", "georgian", "graytext", "groove", + "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew", + "help", "hidden", "hide", "higher", "highlight", "highlighttext", + "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore", + "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", + "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", + "inline-block", "inline-table", "inset", "inside", "intrinsic", "invert", + "italic", "justify", "kannada", "katakana", "katakana-iroha", "keep-all", "khmer", + "landscape", "lao", "large", "larger", "left", "level", "lighter", + "line-through", "linear", "lines", "list-item", "listbox", "listitem", + "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", + "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", + "lower-roman", "lowercase", "ltr", "malayalam", "match", + "media-controls-background", "media-current-time-display", + "media-fullscreen-button", "media-mute-button", "media-play-button", + "media-return-to-realtime-button", "media-rewind-button", + "media-seek-back-button", "media-seek-forward-button", "media-slider", + "media-sliderthumb", "media-time-remaining-display", "media-volume-slider", + "media-volume-slider-container", "media-volume-sliderthumb", "medium", + "menu", "menulist", "menulist-button", "menulist-text", + "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", + "mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize", + "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", + "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", + "ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", + "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", + "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", + "painted", "page", "paused", "persian", "plus-darker", "plus-lighter", "pointer", + "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button", + "radio", "read-only", "read-write", "read-write-plaintext-only", "rectangle", "region", + "relative", "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba", + "ridge", "right", "round", "row-resize", "rtl", "run-in", "running", + "s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield", + "searchfield-cancel-button", "searchfield-decoration", + "searchfield-results-button", "searchfield-results-decoration", + "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", + "single", "skip-white-space", "slide", "slider-horizontal", + "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", + "small", "small-caps", "small-caption", "smaller", "solid", "somali", + "source-atop", "source-in", "source-out", "source-over", "space", "square", + "square-button", "start", "static", "status-bar", "stretch", "stroke", + "sub", "subpixel-antialiased", "super", "sw-resize", "table", + "table-caption", "table-cell", "table-column", "table-column-group", + "table-footer-group", "table-header-group", "table-row", "table-row-group", + "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai", + "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", + "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", + "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", + "transparent", "ultra-condensed", "ultra-expanded", "underline", "up", + "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", + "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", + "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", + "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", + "window", "windowframe", "windowtext", "x-large", "x-small", "xor", + "xx-large", "xx-small" + ], valueKeywords = keySet(valueKeywords_); + + var fontProperties_ = [ + "font-family", "src", "unicode-range", "font-variant", "font-feature-settings", + "font-stretch", "font-weight", "font-style" + ], fontProperties = keySet(fontProperties_); + + var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_) + .concat(nonStandardPropertyKeywords).concat(colorKeywords_).concat(valueKeywords_); + CodeMirror.registerHelper("hintWords", "css", allWords); + + function tokenCComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == "/") { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return ["comment", "comment"]; + } + + function tokenSGMLComment(stream, state) { + if (stream.skipTo("-->")) { + stream.match("-->"); + state.tokenize = null; + } else { + stream.skipToEnd(); + } + return ["comment", "comment"]; + } + + CodeMirror.defineMIME("text/css", { + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + fontProperties: fontProperties, + tokenHooks: { + "<": function(stream, state) { + if (!stream.match("!--")) return false; + state.tokenize = tokenSGMLComment; + return tokenSGMLComment(stream, state); + }, + "/": function(stream, state) { + if (!stream.eat("*")) return false; + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + }, + name: "css" + }); + + CodeMirror.defineMIME("text/x-scss", { + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + fontProperties: fontProperties, + allowNested: true, + tokenHooks: { + "/": function(stream, state) { + if (stream.eat("/")) { + stream.skipToEnd(); + return ["comment", "comment"]; + } else if (stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } else { + return ["operator", "operator"]; + } + }, + ":": function(stream) { + if (stream.match(/\s*\{/)) + return [null, "{"]; + return false; + }, + "$": function(stream) { + stream.match(/^[\w-]+/); + if (stream.match(/^\s*:/, false)) + return ["variable-2", "variable-definition"]; + return ["variable-2", "variable"]; + }, + "#": function(stream) { + if (!stream.eat("{")) return false; + return [null, "interpolation"]; + } + }, + name: "css", + helperType: "scss" + }); + + CodeMirror.defineMIME("text/x-less", { + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + fontProperties: fontProperties, + allowNested: true, + tokenHooks: { + "/": function(stream, state) { + if (stream.eat("/")) { + stream.skipToEnd(); + return ["comment", "comment"]; + } else if (stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } else { + return ["operator", "operator"]; + } + }, + "@": function(stream) { + if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false; + stream.eatWhile(/[\w\\\-]/); + if (stream.match(/^\s*:/, false)) + return ["variable-2", "variable-definition"]; + return ["variable-2", "variable"]; + }, + "&": function() { + return ["atom", "atom"]; + } + }, + name: "css", + helperType: "less" + }); + +}); diff --git a/Upload/admin/jscripts/codemirror/mode/css/index.html b/Upload/admin/jscripts/codemirror/mode/css/index.html new file mode 100644 index 0000000..80ef518 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/css/index.html @@ -0,0 +1,70 @@ + + +CodeMirror: CSS mode + + + + + + + + + +
+

CSS mode

+ + + +

MIME types defined: text/css, text/x-scss (demo), text/x-less (demo).

+ +

Parsing/Highlighting Tests: normal, verbose.

+ +
diff --git a/Upload/admin/jscripts/codemirror/mode/css/less.html b/Upload/admin/jscripts/codemirror/mode/css/less.html new file mode 100644 index 0000000..1030ca4 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/css/less.html @@ -0,0 +1,152 @@ + + +CodeMirror: LESS mode + + + + + + + + + + +
+

LESS mode

+
+ + +

The LESS mode is a sub-mode of the CSS mode (defined in css.js.

+ +

Parsing/Highlighting Tests: normal, verbose.

+
diff --git a/Upload/admin/jscripts/codemirror/mode/css/less_test.js b/Upload/admin/jscripts/codemirror/mode/css/less_test.js new file mode 100644 index 0000000..2ba6998 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/css/less_test.js @@ -0,0 +1,51 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + "use strict"; + + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-less"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "less"); } + + MT("variable", + "[variable-2 @base]: [atom #f04615];", + "[qualifier .class] {", + " [property width]: [variable percentage]([number 0.5]); [comment // returns `50%`]", + " [property color]: [variable saturate]([variable-2 @base], [number 5%]);", + "}"); + + MT("amp", + "[qualifier .child], [qualifier .sibling] {", + " [qualifier .parent] [atom &] {", + " [property color]: [keyword black];", + " }", + " [atom &] + [atom &] {", + " [property color]: [keyword red];", + " }", + "}"); + + MT("mixin", + "[qualifier .mixin] ([variable dark]; [variable-2 @color]) {", + " [property color]: [variable darken]([variable-2 @color], [number 10%]);", + "}", + "[qualifier .mixin] ([variable light]; [variable-2 @color]) {", + " [property color]: [variable lighten]([variable-2 @color], [number 10%]);", + "}", + "[qualifier .mixin] ([variable-2 @_]; [variable-2 @color]) {", + " [property display]: [atom block];", + "}", + "[variable-2 @switch]: [variable light];", + "[qualifier .class] {", + " [qualifier .mixin]([variable-2 @switch]; [atom #888]);", + "}"); + + MT("nest", + "[qualifier .one] {", + " [def @media] ([property width]: [number 400px]) {", + " [property font-size]: [number 1.2em];", + " [def @media] [attribute print] [keyword and] [property color] {", + " [property color]: [keyword blue];", + " }", + " }", + "}"); +})(); diff --git a/Upload/admin/jscripts/codemirror/mode/css/scss.html b/Upload/admin/jscripts/codemirror/mode/css/scss.html new file mode 100644 index 0000000..0677d08 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/css/scss.html @@ -0,0 +1,157 @@ + + +CodeMirror: SCSS mode + + + + + + + + + +
+

SCSS mode

+
+ + +

The SCSS mode is a sub-mode of the CSS mode (defined in css.js.

+ +

Parsing/Highlighting Tests: normal, verbose.

+ +
diff --git a/Upload/admin/jscripts/codemirror/mode/css/scss_test.js b/Upload/admin/jscripts/codemirror/mode/css/scss_test.js new file mode 100644 index 0000000..8dcea9e --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/css/scss_test.js @@ -0,0 +1,110 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-scss"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); } + + MT('url_with_quotation', + "[tag foo] { [property background]:[atom url]([string test.jpg]) }"); + + MT('url_with_double_quotes', + "[tag foo] { [property background]:[atom url]([string \"test.jpg\"]) }"); + + MT('url_with_single_quotes', + "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) }"); + + MT('string', + "[def @import] [string \"compass/css3\"]"); + + MT('important_keyword', + "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) [keyword !important] }"); + + MT('variable', + "[variable-2 $blue]:[atom #333]"); + + MT('variable_as_attribute', + "[tag foo] { [property color]:[variable-2 $blue] }"); + + MT('numbers', + "[tag foo] { [property padding]:[number 10px] [number 10] [number 10em] [number 8in] }"); + + MT('number_percentage', + "[tag foo] { [property width]:[number 80%] }"); + + MT('selector', + "[builtin #hello][qualifier .world]{}"); + + MT('singleline_comment', + "[comment // this is a comment]"); + + MT('multiline_comment', + "[comment /*foobar*/]"); + + MT('attribute_with_hyphen', + "[tag foo] { [property font-size]:[number 10px] }"); + + MT('string_after_attribute', + "[tag foo] { [property content]:[string \"::\"] }"); + + MT('directives', + "[def @include] [qualifier .mixin]"); + + MT('basic_structure', + "[tag p] { [property background]:[keyword red]; }"); + + MT('nested_structure', + "[tag p] { [tag a] { [property color]:[keyword red]; } }"); + + MT('mixin', + "[def @mixin] [tag table-base] {}"); + + MT('number_without_semicolon', + "[tag p] {[property width]:[number 12]}", + "[tag a] {[property color]:[keyword red];}"); + + MT('atom_in_nested_block', + "[tag p] { [tag a] { [property color]:[atom #000]; } }"); + + MT('interpolation_in_property', + "[tag foo] { #{[variable-2 $hello]}:[number 2]; }"); + + MT('interpolation_in_selector', + "[tag foo]#{[variable-2 $hello]} { [property color]:[atom #000]; }"); + + MT('interpolation_error', + "[tag foo]#{[error foo]} { [property color]:[atom #000]; }"); + + MT("divide_operator", + "[tag foo] { [property width]:[number 4] [operator /] [number 2] }"); + + MT('nested_structure_with_id_selector', + "[tag p] { [builtin #hello] { [property color]:[keyword red]; } }"); + + MT('indent_mixin', + "[def @mixin] [tag container] (", + " [variable-2 $a]: [number 10],", + " [variable-2 $b]: [number 10])", + "{}"); + + MT('indent_nested', + "[tag foo] {", + " [tag bar] {", + " }", + "}"); + + MT('indent_parentheses', + "[tag foo] {", + " [property color]: [variable darken]([variable-2 $blue],", + " [number 9%]);", + "}"); + + MT('indent_vardef', + "[variable-2 $name]:", + " [string 'val'];", + "[tag tag] {", + " [tag inner] {", + " [property margin]: [number 3px];", + " }", + "}"); +})(); diff --git a/Upload/admin/jscripts/codemirror/mode/css/test.js b/Upload/admin/jscripts/codemirror/mode/css/test.js new file mode 100644 index 0000000..d236e2a --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/css/test.js @@ -0,0 +1,135 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "css"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + // Error, because "foobarhello" is neither a known type or property, but + // property was expected (after "and"), and it should be in parenthese. + MT("atMediaUnknownType", + "[def @media] [attribute screen] [keyword and] [error foobarhello] { }"); + + // Soft error, because "foobarhello" is not a known property or type. + MT("atMediaUnknownProperty", + "[def @media] [attribute screen] [keyword and] ([error foobarhello]) { }"); + + // Make sure nesting works with media queries + MT("atMediaMaxWidthNested", + "[def @media] [attribute screen] [keyword and] ([property max-width]: [number 25px]) { [tag foo] { } }"); + + MT("tagSelector", + "[tag foo] { }"); + + MT("classSelector", + "[qualifier .foo-bar_hello] { }"); + + MT("idSelector", + "[builtin #foo] { [error #foo] }"); + + MT("tagSelectorUnclosed", + "[tag foo] { [property margin]: [number 0] } [tag bar] { }"); + + MT("tagStringNoQuotes", + "[tag foo] { [property font-family]: [variable hello] [variable world]; }"); + + MT("tagStringDouble", + "[tag foo] { [property font-family]: [string \"hello world\"]; }"); + + MT("tagStringSingle", + "[tag foo] { [property font-family]: [string 'hello world']; }"); + + MT("tagColorKeyword", + "[tag foo] {", + " [property color]: [keyword black];", + " [property color]: [keyword navy];", + " [property color]: [keyword yellow];", + "}"); + + MT("tagColorHex3", + "[tag foo] { [property background]: [atom #fff]; }"); + + MT("tagColorHex6", + "[tag foo] { [property background]: [atom #ffffff]; }"); + + MT("tagColorHex4", + "[tag foo] { [property background]: [atom&error #ffff]; }"); + + MT("tagColorHexInvalid", + "[tag foo] { [property background]: [atom&error #ffg]; }"); + + MT("tagNegativeNumber", + "[tag foo] { [property margin]: [number -5px]; }"); + + MT("tagPositiveNumber", + "[tag foo] { [property padding]: [number 5px]; }"); + + MT("tagVendor", + "[tag foo] { [meta -foo-][property box-sizing]: [meta -foo-][atom border-box]; }"); + + MT("tagBogusProperty", + "[tag foo] { [property&error barhelloworld]: [number 0]; }"); + + MT("tagTwoProperties", + "[tag foo] { [property margin]: [number 0]; [property padding]: [number 0]; }"); + + MT("tagTwoPropertiesURL", + "[tag foo] { [property background]: [atom url]([string //example.com/foo.png]); [property padding]: [number 0]; }"); + + MT("commentSGML", + "[comment ]"); + + MT("commentSGML2", + "[comment ] [tag div] {}"); + + MT("indent_tagSelector", + "[tag strong], [tag em] {", + " [property background]: [atom rgba](", + " [number 255], [number 255], [number 0], [number .2]", + " );", + "}"); + + MT("indent_atMedia", + "[def @media] {", + " [tag foo] {", + " [property color]:", + " [keyword yellow];", + " }", + "}"); + + MT("indent_comma", + "[tag foo] {", + " [property font-family]: [variable verdana],", + " [atom sans-serif];", + "}"); + + MT("indent_parentheses", + "[tag foo]:[variable-3 before] {", + " [property background]: [atom url](", + "[string blahblah]", + "[string etc]", + "[string ]) [keyword !important];", + "}"); + + MT("font_face", + "[def @font-face] {", + " [property font-family]: [string 'myfont'];", + " [error nonsense]: [string 'abc'];", + " [property src]: [atom url]([string http://blah]),", + " [atom url]([string http://foo]);", + "}"); + + MT("empty_url", + "[def @import] [tag url]() [tag screen];"); + + MT("parens", + "[qualifier .foo] {", + " [property background-image]: [variable fade]([atom #000], [number 20%]);", + " [property border-image]: [variable linear-gradient](", + " [atom to] [atom bottom],", + " [variable fade]([atom #000], [number 20%]) [number 0%],", + " [variable fade]([atom #000], [number 20%]) [number 100%]", + " );", + "}"); +})(); diff --git a/Upload/admin/jscripts/codemirror/mode/htmlmixed/htmlmixed.js b/Upload/admin/jscripts/codemirror/mode/htmlmixed/htmlmixed.js new file mode 100644 index 0000000..dc48978 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/htmlmixed/htmlmixed.js @@ -0,0 +1,120 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("htmlmixed", function(config, parserConfig) { + var htmlMode = CodeMirror.getMode(config, {name: "xml", + htmlMode: true, + multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, + multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag}); + var cssMode = CodeMirror.getMode(config, "css"); + + var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes; + scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i, + mode: CodeMirror.getMode(config, "javascript")}); + if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) { + var conf = scriptTypesConf[i]; + scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)}); + } + scriptTypes.push({matches: /./, + mode: CodeMirror.getMode(config, "text/plain")}); + + function html(stream, state) { + var tagName = state.htmlState.tagName; + var style = htmlMode.token(stream, state.htmlState); + if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") { + // Script block: mode to change to depends on type attribute + var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i); + scriptType = scriptType ? scriptType[1] : ""; + if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1); + for (var i = 0; i < scriptTypes.length; ++i) { + var tp = scriptTypes[i]; + if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) { + if (tp.mode) { + state.token = script; + state.localMode = tp.mode; + state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, "")); + } + break; + } + } + } else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") { + state.token = css; + state.localMode = cssMode; + state.localState = cssMode.startState(htmlMode.indent(state.htmlState, "")); + } + return style; + } + function maybeBackup(stream, pat, style) { + var cur = stream.current(); + var close = cur.search(pat), m; + if (close > -1) stream.backUp(cur.length - close); + else if (m = cur.match(/<\/?$/)) { + stream.backUp(cur.length); + if (!stream.match(pat, false)) stream.match(cur); + } + return style; + } + function script(stream, state) { + if (stream.match(/^<\/\s*script\s*>/i, false)) { + state.token = html; + state.localState = state.localMode = null; + return html(stream, state); + } + return maybeBackup(stream, /<\/\s*script\s*>/, + state.localMode.token(stream, state.localState)); + } + function css(stream, state) { + if (stream.match(/^<\/\s*style\s*>/i, false)) { + state.token = html; + state.localState = state.localMode = null; + return html(stream, state); + } + return maybeBackup(stream, /<\/\s*style\s*>/, + cssMode.token(stream, state.localState)); + } + + return { + startState: function() { + var state = htmlMode.startState(); + return {token: html, localMode: null, localState: null, htmlState: state}; + }, + + copyState: function(state) { + if (state.localState) + var local = CodeMirror.copyState(state.localMode, state.localState); + return {token: state.token, localMode: state.localMode, localState: local, + htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; + }, + + token: function(stream, state) { + return state.token(stream, state); + }, + + indent: function(state, textAfter) { + if (!state.localMode || /^\s*<\//.test(textAfter)) + return htmlMode.indent(state.htmlState, textAfter); + else if (state.localMode.indent) + return state.localMode.indent(state.localState, textAfter); + else + return CodeMirror.Pass; + }, + + innerMode: function(state) { + return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode}; + } + }; +}, "xml", "javascript", "css"); + +CodeMirror.defineMIME("text/html", "htmlmixed"); + +}); diff --git a/Upload/admin/jscripts/codemirror/mode/htmlmixed/index.html b/Upload/admin/jscripts/codemirror/mode/htmlmixed/index.html new file mode 100644 index 0000000..bd06bb5 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/htmlmixed/index.html @@ -0,0 +1,85 @@ + + +CodeMirror: HTML mixed mode + + + + + + + + + + + + + +
+

HTML mixed mode

+
+ + +

The HTML mixed mode depends on the XML, JavaScript, and CSS modes.

+ +

It takes an optional mode configuration + option, scriptTypes, which can be used to add custom + behavior for specific <script type="..."> tags. If + given, it should hold an array of {matches, mode} + objects, where matches is a string or regexp that + matches the script type, and mode is + either null, for script types that should stay in + HTML mode, or a mode + spec corresponding to the mode that should be used for the + script.

+ +

MIME types defined: text/html + (redefined, only takes effect if you load this parser after the + XML parser).

+ +
diff --git a/Upload/admin/jscripts/codemirror/mode/javascript/index.html b/Upload/admin/jscripts/codemirror/mode/javascript/index.html new file mode 100644 index 0000000..faf5036 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/javascript/index.html @@ -0,0 +1,109 @@ + + +CodeMirror: JavaScript mode + + + + + + + + + + + + +
+

JavaScript mode

+ + +
+ + + +

+ JavaScript mode supports several configuration options: +

    +
  • json which will set the mode to expect JSON + data rather than a JavaScript program.
  • +
  • jsonld which will set the mode to expect + JSON-LD linked data rather + than a JavaScript program (demo).
  • +
  • typescript which will activate additional + syntax highlighting and some other things for TypeScript code + (demo).
  • +
  • statementIndent which (given a number) will + determine the amount of indentation to use for statements + continued on a new line.
  • +
+

+ +

MIME types defined: text/javascript, application/json, application/ld+json, text/typescript, application/typescript.

+
diff --git a/Upload/admin/jscripts/codemirror/mode/javascript/javascript.js b/Upload/admin/jscripts/codemirror/mode/javascript/javascript.js new file mode 100644 index 0000000..315674b --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/javascript/javascript.js @@ -0,0 +1,683 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// TODO actually recognize syntax of TypeScript constructs + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("javascript", function(config, parserConfig) { + var indentUnit = config.indentUnit; + var statementIndent = parserConfig.statementIndent; + var jsonldMode = parserConfig.jsonld; + var jsonMode = parserConfig.json || jsonldMode; + var isTS = parserConfig.typescript; + + // Tokenizer + + var keywords = function(){ + function kw(type) {return {type: type, style: "keyword"};} + var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); + var operator = kw("operator"), atom = {type: "atom", style: "atom"}; + + var jsKeywords = { + "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, + "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C, + "var": kw("var"), "const": kw("var"), "let": kw("var"), + "function": kw("function"), "catch": kw("catch"), + "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), + "in": operator, "typeof": operator, "instanceof": operator, + "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, + "this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"), + "yield": C, "export": kw("export"), "import": kw("import"), "extends": C + }; + + // Extend the 'normal' keywords with the TypeScript language extensions + if (isTS) { + var type = {type: "variable", style: "variable-3"}; + var tsKeywords = { + // object-like things + "interface": kw("interface"), + "extends": kw("extends"), + "constructor": kw("constructor"), + + // scope modifiers + "public": kw("public"), + "private": kw("private"), + "protected": kw("protected"), + "static": kw("static"), + + // types + "string": type, "number": type, "bool": type, "any": type + }; + + for (var attr in tsKeywords) { + jsKeywords[attr] = tsKeywords[attr]; + } + } + + return jsKeywords; + }(); + + var isOperatorChar = /[+\-*&%=<>!?|~^]/; + var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; + + function readRegexp(stream) { + var escaped = false, next, inSet = false; + while ((next = stream.next()) != null) { + if (!escaped) { + if (next == "/" && !inSet) return; + if (next == "[") inSet = true; + else if (inSet && next == "]") inSet = false; + } + escaped = !escaped && next == "\\"; + } + } + + // Used as scratch variables to communicate multiple values without + // consing up tons of objects. + var type, content; + function ret(tp, style, cont) { + type = tp; content = cont; + return style; + } + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { + return ret("number", "number"); + } else if (ch == "." && stream.match("..")) { + return ret("spread", "meta"); + } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + return ret(ch); + } else if (ch == "=" && stream.eat(">")) { + return ret("=>", "operator"); + } else if (ch == "0" && stream.eat(/x/i)) { + stream.eatWhile(/[\da-f]/i); + return ret("number", "number"); + } else if (/\d/.test(ch)) { + stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); + return ret("number", "number"); + } else if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } else if (stream.eat("/")) { + stream.skipToEnd(); + return ret("comment", "comment"); + } else if (state.lastType == "operator" || state.lastType == "keyword c" || + state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) { + readRegexp(stream); + stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla + return ret("regexp", "string-2"); + } else { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator", stream.current()); + } + } else if (ch == "`") { + state.tokenize = tokenQuasi; + return tokenQuasi(stream, state); + } else if (ch == "#") { + stream.skipToEnd(); + return ret("error", "error"); + } else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator", stream.current()); + } else { + stream.eatWhile(/[\w\$_]/); + var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; + return (known && state.lastType != ".") ? ret(known.type, known.style, word) : + ret("variable", "variable", word); + } + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next; + if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ + state.tokenize = tokenBase; + return ret("jsonld-keyword", "meta"); + } + while ((next = stream.next()) != null) { + if (next == quote && !escaped) break; + escaped = !escaped && next == "\\"; + } + if (!escaped) state.tokenize = tokenBase; + return ret("string", "string"); + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + function tokenQuasi(stream, state) { + var escaped = false, next; + while ((next = stream.next()) != null) { + if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && next == "\\"; + } + return ret("quasi", "string-2", stream.current()); + } + + var brackets = "([{}])"; + // This is a crude lookahead trick to try and notice that we're + // parsing the argument patterns for a fat-arrow function before we + // actually hit the arrow token. It only works if the arrow is on + // the same line as the arguments and there's no strange noise + // (comments) in between. Fallback is to only notice when we hit the + // arrow, and not declare the arguments as locals for the arrow + // body. + function findFatArrow(stream, state) { + if (state.fatArrowAt) state.fatArrowAt = null; + var arrow = stream.string.indexOf("=>", stream.start); + if (arrow < 0) return; + + var depth = 0, sawSomething = false; + for (var pos = arrow - 1; pos >= 0; --pos) { + var ch = stream.string.charAt(pos); + var bracket = brackets.indexOf(ch); + if (bracket >= 0 && bracket < 3) { + if (!depth) { ++pos; break; } + if (--depth == 0) break; + } else if (bracket >= 3 && bracket < 6) { + ++depth; + } else if (/[$\w]/.test(ch)) { + sawSomething = true; + } else if (sawSomething && !depth) { + ++pos; + break; + } + } + if (sawSomething && !depth) state.fatArrowAt = pos; + } + + // Parser + + var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true}; + + function JSLexical(indented, column, type, align, prev, info) { + this.indented = indented; + this.column = column; + this.type = type; + this.prev = prev; + this.info = info; + if (align != null) this.align = align; + } + + function inScope(state, varname) { + for (var v = state.localVars; v; v = v.next) + if (v.name == varname) return true; + for (var cx = state.context; cx; cx = cx.prev) { + for (var v = cx.vars; v; v = v.next) + if (v.name == varname) return true; + } + } + + function parseJS(state, style, type, content, stream) { + var cc = state.cc; + // Communicate our context to the combinators. + // (Less wasteful than consing up a hundred closures on every call.) + cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; + + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = true; + + while(true) { + var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; + if (combinator(type, content)) { + while(cc.length && cc[cc.length - 1].lex) + cc.pop()(); + if (cx.marked) return cx.marked; + if (type == "variable" && inScope(state, content)) return "variable-2"; + return style; + } + } + } + + // Combinator utils + + var cx = {state: null, column: null, marked: null, cc: null}; + function pass() { + for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); + } + function cont() { + pass.apply(null, arguments); + return true; + } + function register(varname) { + function inList(list) { + for (var v = list; v; v = v.next) + if (v.name == varname) return true; + return false; + } + var state = cx.state; + if (state.context) { + cx.marked = "def"; + if (inList(state.localVars)) return; + state.localVars = {name: varname, next: state.localVars}; + } else { + if (inList(state.globalVars)) return; + if (parserConfig.globalVars) + state.globalVars = {name: varname, next: state.globalVars}; + } + } + + // Combinators + + var defaultVars = {name: "this", next: {name: "arguments"}}; + function pushcontext() { + cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; + cx.state.localVars = defaultVars; + } + function popcontext() { + cx.state.localVars = cx.state.context.vars; + cx.state.context = cx.state.context.prev; + } + function pushlex(type, info) { + var result = function() { + var state = cx.state, indent = state.indented; + if (state.lexical.type == "stat") indent = state.lexical.indented; + state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); + }; + result.lex = true; + return result; + } + function poplex() { + var state = cx.state; + if (state.lexical.prev) { + if (state.lexical.type == ")") + state.indented = state.lexical.indented; + state.lexical = state.lexical.prev; + } + } + poplex.lex = true; + + function expect(wanted) { + function exp(type) { + if (type == wanted) return cont(); + else if (wanted == ";") return pass(); + else return cont(exp); + }; + return exp; + } + + function statement(type, value) { + if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); + if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); + if (type == "keyword b") return cont(pushlex("form"), statement, poplex); + if (type == "{") return cont(pushlex("}"), block, poplex); + if (type == ";") return cont(); + if (type == "if") { + if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) + cx.state.cc.pop()(); + return cont(pushlex("form"), expression, statement, poplex, maybeelse); + } + if (type == "function") return cont(functiondef); + if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); + if (type == "variable") return cont(pushlex("stat"), maybelabel); + if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), + block, poplex, poplex); + if (type == "case") return cont(expression, expect(":")); + if (type == "default") return cont(expect(":")); + if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), + statement, poplex, popcontext); + if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex); + if (type == "class") return cont(pushlex("form"), className, poplex); + if (type == "export") return cont(pushlex("form"), afterExport, poplex); + if (type == "import") return cont(pushlex("form"), afterImport, poplex); + return pass(pushlex("stat"), expression, expect(";"), poplex); + } + function expression(type) { + return expressionInner(type, false); + } + function expressionNoComma(type) { + return expressionInner(type, true); + } + function expressionInner(type, noComma) { + if (cx.state.fatArrowAt == cx.stream.start) { + var body = noComma ? arrowBodyNoComma : arrowBody; + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext); + else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext); + } + + var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; + if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); + if (type == "function") return cont(functiondef, maybeop); + if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression); + if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop); + if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); + if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); + if (type == "{") return contCommasep(objprop, "}", null, maybeop); + if (type == "quasi") { return pass(quasi, maybeop); } + return cont(); + } + function maybeexpression(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expression); + } + function maybeexpressionNoComma(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expressionNoComma); + } + + function maybeoperatorComma(type, value) { + if (type == ",") return cont(expression); + return maybeoperatorNoComma(type, value, false); + } + function maybeoperatorNoComma(type, value, noComma) { + var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; + var expr = noComma == false ? expression : expressionNoComma; + if (value == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); + if (type == "operator") { + if (/\+\+|--/.test(value)) return cont(me); + if (value == "?") return cont(expression, expect(":"), expr); + return cont(expr); + } + if (type == "quasi") { return pass(quasi, me); } + if (type == ";") return; + if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); + if (type == ".") return cont(property, me); + if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); + } + function quasi(type, value) { + if (type != "quasi") return pass(); + if (value.slice(value.length - 2) != "${") return cont(quasi); + return cont(expression, continueQuasi); + } + function continueQuasi(type) { + if (type == "}") { + cx.marked = "string-2"; + cx.state.tokenize = tokenQuasi; + return cont(quasi); + } + } + function arrowBody(type) { + findFatArrow(cx.stream, cx.state); + if (type == "{") return pass(statement); + return pass(expression); + } + function arrowBodyNoComma(type) { + findFatArrow(cx.stream, cx.state); + if (type == "{") return pass(statement); + return pass(expressionNoComma); + } + function maybelabel(type) { + if (type == ":") return cont(poplex, statement); + return pass(maybeoperatorComma, expect(";"), poplex); + } + function property(type) { + if (type == "variable") {cx.marked = "property"; return cont();} + } + function objprop(type, value) { + if (type == "variable" || cx.style == "keyword") { + cx.marked = "property"; + if (value == "get" || value == "set") return cont(getterSetter); + return cont(afterprop); + } else if (type == "number" || type == "string") { + cx.marked = jsonldMode ? "property" : (cx.style + " property"); + return cont(afterprop); + } else if (type == "jsonld-keyword") { + return cont(afterprop); + } else if (type == "[") { + return cont(expression, expect("]"), afterprop); + } + } + function getterSetter(type) { + if (type != "variable") return pass(afterprop); + cx.marked = "property"; + return cont(functiondef); + } + function afterprop(type) { + if (type == ":") return cont(expressionNoComma); + if (type == "(") return pass(functiondef); + } + function commasep(what, end) { + function proceed(type) { + if (type == ",") { + var lex = cx.state.lexical; + if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; + return cont(what, proceed); + } + if (type == end) return cont(); + return cont(expect(end)); + } + return function(type) { + if (type == end) return cont(); + return pass(what, proceed); + }; + } + function contCommasep(what, end, info) { + for (var i = 3; i < arguments.length; i++) + cx.cc.push(arguments[i]); + return cont(pushlex(end, info), commasep(what, end), poplex); + } + function block(type) { + if (type == "}") return cont(); + return pass(statement, block); + } + function maybetype(type) { + if (isTS && type == ":") return cont(typedef); + } + function typedef(type) { + if (type == "variable"){cx.marked = "variable-3"; return cont();} + } + function vardef() { + return pass(pattern, maybetype, maybeAssign, vardefCont); + } + function pattern(type, value) { + if (type == "variable") { register(value); return cont(); } + if (type == "[") return contCommasep(pattern, "]"); + if (type == "{") return contCommasep(proppattern, "}"); + } + function proppattern(type, value) { + if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { + register(value); + return cont(maybeAssign); + } + if (type == "variable") cx.marked = "property"; + return cont(expect(":"), pattern, maybeAssign); + } + function maybeAssign(_type, value) { + if (value == "=") return cont(expressionNoComma); + } + function vardefCont(type) { + if (type == ",") return cont(vardef); + } + function maybeelse(type, value) { + if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); + } + function forspec(type) { + if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); + } + function forspec1(type) { + if (type == "var") return cont(vardef, expect(";"), forspec2); + if (type == ";") return cont(forspec2); + if (type == "variable") return cont(formaybeinof); + return pass(expression, expect(";"), forspec2); + } + function formaybeinof(_type, value) { + if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } + return cont(maybeoperatorComma, forspec2); + } + function forspec2(type, value) { + if (type == ";") return cont(forspec3); + if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } + return pass(expression, expect(";"), forspec3); + } + function forspec3(type) { + if (type != ")") cont(expression); + } + function functiondef(type, value) { + if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} + if (type == "variable") {register(value); return cont(functiondef);} + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext); + } + function funarg(type) { + if (type == "spread") return cont(funarg); + return pass(pattern, maybetype); + } + function className(type, value) { + if (type == "variable") {register(value); return cont(classNameAfter);} + } + function classNameAfter(type, value) { + if (value == "extends") return cont(expression, classNameAfter); + if (type == "{") return cont(pushlex("}"), classBody, poplex); + } + function classBody(type, value) { + if (type == "variable" || cx.style == "keyword") { + cx.marked = "property"; + if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody); + return cont(functiondef, classBody); + } + if (value == "*") { + cx.marked = "keyword"; + return cont(classBody); + } + if (type == ";") return cont(classBody); + if (type == "}") return cont(); + } + function classGetterSetter(type) { + if (type != "variable") return pass(); + cx.marked = "property"; + return cont(); + } + function afterModule(type, value) { + if (type == "string") return cont(statement); + if (type == "variable") { register(value); return cont(maybeFrom); } + } + function afterExport(_type, value) { + if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } + if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } + return pass(statement); + } + function afterImport(type) { + if (type == "string") return cont(); + return pass(importSpec, maybeFrom); + } + function importSpec(type, value) { + if (type == "{") return contCommasep(importSpec, "}"); + if (type == "variable") register(value); + return cont(); + } + function maybeFrom(_type, value) { + if (value == "from") { cx.marked = "keyword"; return cont(expression); } + } + function arrayLiteral(type) { + if (type == "]") return cont(); + return pass(expressionNoComma, maybeArrayComprehension); + } + function maybeArrayComprehension(type) { + if (type == "for") return pass(comprehension, expect("]")); + if (type == ",") return cont(commasep(expressionNoComma, "]")); + return pass(commasep(expressionNoComma, "]")); + } + function comprehension(type) { + if (type == "for") return cont(forspec, comprehension); + if (type == "if") return cont(expression, comprehension); + } + + // Interface + + return { + startState: function(basecolumn) { + var state = { + tokenize: tokenBase, + lastType: "sof", + cc: [], + lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), + localVars: parserConfig.localVars, + context: parserConfig.localVars && {vars: parserConfig.localVars}, + indented: 0 + }; + if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") + state.globalVars = parserConfig.globalVars; + return state; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = false; + state.indented = stream.indentation(); + findFatArrow(stream, state); + } + if (state.tokenize != tokenComment && stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + if (type == "comment") return style; + state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; + return parseJS(state, style, type, content, stream); + }, + + indent: function(state, textAfter) { + if (state.tokenize == tokenComment) return CodeMirror.Pass; + if (state.tokenize != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; + // Kludge to prevent 'maybelse' from blocking lexical scope pops + if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { + var c = state.cc[i]; + if (c == poplex) lexical = lexical.prev; + else if (c != maybeelse) break; + } + if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; + if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") + lexical = lexical.prev; + var type = lexical.type, closing = firstChar == type; + + if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0); + else if (type == "form" && firstChar == "{") return lexical.indented; + else if (type == "form") return lexical.indented + indentUnit; + else if (type == "stat") + return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? statementIndent || indentUnit : 0); + else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) + return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); + else if (lexical.align) return lexical.column + (closing ? 0 : 1); + else return lexical.indented + (closing ? 0 : indentUnit); + }, + + electricChars: ":{}", + blockCommentStart: jsonMode ? null : "/*", + blockCommentEnd: jsonMode ? null : "*/", + lineComment: jsonMode ? null : "//", + fold: "brace", + + helperType: jsonMode ? "json" : "javascript", + jsonldMode: jsonldMode, + jsonMode: jsonMode + }; +}); + +CodeMirror.registerHelper("wordChars", "javascript", /[\\w$]/); + +CodeMirror.defineMIME("text/javascript", "javascript"); +CodeMirror.defineMIME("text/ecmascript", "javascript"); +CodeMirror.defineMIME("application/javascript", "javascript"); +CodeMirror.defineMIME("application/x-javascript", "javascript"); +CodeMirror.defineMIME("application/ecmascript", "javascript"); +CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); +CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); +CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true}); +CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); +CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); + +}); diff --git a/Upload/admin/jscripts/codemirror/mode/javascript/json-ld.html b/Upload/admin/jscripts/codemirror/mode/javascript/json-ld.html new file mode 100644 index 0000000..256bb0f --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/javascript/json-ld.html @@ -0,0 +1,72 @@ + + +CodeMirror: JSON-LD mode + + + + + + + + + + + + +
+

JSON-LD mode

+ + +
+ + + +

This is a specialization of the JavaScript mode.

+
diff --git a/Upload/admin/jscripts/codemirror/mode/javascript/test.js b/Upload/admin/jscripts/codemirror/mode/javascript/test.js new file mode 100644 index 0000000..a9cc993 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/javascript/test.js @@ -0,0 +1,181 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "javascript"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("locals", + "[keyword function] [variable foo]([def a], [def b]) { [keyword var] [def c] [operator =] [number 10]; [keyword return] [variable-2 a] [operator +] [variable-2 c] [operator +] [variable d]; }"); + + MT("comma-and-binop", + "[keyword function](){ [keyword var] [def x] [operator =] [number 1] [operator +] [number 2], [def y]; }"); + + MT("destructuring", + "([keyword function]([def a], [[[def b], [def c] ]]) {", + " [keyword let] {[def d], [property foo]: [def c][operator =][number 10], [def x]} [operator =] [variable foo]([variable-2 a]);", + " [[[variable-2 c], [variable y] ]] [operator =] [variable-2 c];", + "})();"); + + MT("class_body", + "[keyword class] [variable Foo] {", + " [property constructor]() {}", + " [property sayName]() {", + " [keyword return] [string-2 `foo${][variable foo][string-2 }oo`];", + " }", + "}"); + + MT("class", + "[keyword class] [variable Point] [keyword extends] [variable SuperThing] {", + " [property get] [property prop]() { [keyword return] [number 24]; }", + " [property constructor]([def x], [def y]) {", + " [keyword super]([string 'something']);", + " [keyword this].[property x] [operator =] [variable-2 x];", + " }", + "}"); + + MT("module", + "[keyword module] [string 'foo'] {", + " [keyword export] [keyword let] [def x] [operator =] [number 42];", + " [keyword export] [keyword *] [keyword from] [string 'somewhere'];", + "}"); + + MT("import", + "[keyword function] [variable foo]() {", + " [keyword import] [def $] [keyword from] [string 'jquery'];", + " [keyword module] [def crypto] [keyword from] [string 'crypto'];", + " [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];", + "}"); + + MT("const", + "[keyword function] [variable f]() {", + " [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];", + "}"); + + MT("for/of", + "[keyword for]([keyword let] [variable of] [keyword of] [variable something]) {}"); + + MT("generator", + "[keyword function*] [variable repeat]([def n]) {", + " [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])", + " [keyword yield] [variable-2 i];", + "}"); + + MT("fatArrow", + "[variable array].[property filter]([def a] [operator =>] [variable-2 a] [operator +] [number 1]);", + "[variable a];", // No longer in scope + "[keyword let] [variable f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];", + "[variable c];"); + + MT("spread", + "[keyword function] [variable f]([def a], [meta ...][def b]) {", + " [variable something]([variable-2 a], [meta ...][variable-2 b]);", + "}"); + + MT("comprehension", + "[keyword function] [variable f]() {", + " [[([variable x] [operator +] [number 1]) [keyword for] ([keyword var] [def x] [keyword in] [variable y]) [keyword if] [variable pred]([variable-2 x]) ]];", + " ([variable u] [keyword for] ([keyword var] [def u] [keyword of] [variable generateValues]()) [keyword if] ([variable-2 u].[property color] [operator ===] [string 'blue']));", + "}"); + + MT("quasi", + "[variable re][string-2 `fofdlakj${][variable x] [operator +] ([variable re][string-2 `foo`]) [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]"); + + MT("quasi_no_function", + "[variable x] [operator =] [string-2 `fofdlakj${][variable x] [operator +] [string-2 `foo`] [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]"); + + MT("indent_statement", + "[keyword var] [variable x] [operator =] [number 10]", + "[variable x] [operator +=] [variable y] [operator +]", + " [atom Infinity]", + "[keyword debugger];"); + + MT("indent_if", + "[keyword if] ([number 1])", + " [keyword break];", + "[keyword else] [keyword if] ([number 2])", + " [keyword continue];", + "[keyword else]", + " [number 10];", + "[keyword if] ([number 1]) {", + " [keyword break];", + "} [keyword else] [keyword if] ([number 2]) {", + " [keyword continue];", + "} [keyword else] {", + " [number 10];", + "}"); + + MT("indent_for", + "[keyword for] ([keyword var] [variable i] [operator =] [number 0];", + " [variable i] [operator <] [number 100];", + " [variable i][operator ++])", + " [variable doSomething]([variable i]);", + "[keyword debugger];"); + + MT("indent_c_style", + "[keyword function] [variable foo]()", + "{", + " [keyword debugger];", + "}"); + + MT("indent_else", + "[keyword for] (;;)", + " [keyword if] ([variable foo])", + " [keyword if] ([variable bar])", + " [number 1];", + " [keyword else]", + " [number 2];", + " [keyword else]", + " [number 3];"); + + MT("indent_below_if", + "[keyword for] (;;)", + " [keyword if] ([variable foo])", + " [number 1];", + "[number 2];"); + + MT("multilinestring", + "[keyword var] [variable x] [operator =] [string 'foo\\]", + "[string bar'];"); + + MT("scary_regexp", + "[string-2 /foo[[/]]bar/];"); + + var jsonld_mode = CodeMirror.getMode( + {indentUnit: 2}, + {name: "javascript", jsonld: true} + ); + function LD(name) { + test.mode(name, jsonld_mode, Array.prototype.slice.call(arguments, 1)); + } + + LD("json_ld_keywords", + '{', + ' [meta "@context"]: {', + ' [meta "@base"]: [string "http://example.com"],', + ' [meta "@vocab"]: [string "http://xmlns.com/foaf/0.1/"],', + ' [property "likesFlavor"]: {', + ' [meta "@container"]: [meta "@list"]', + ' [meta "@reverse"]: [string "@beFavoriteOf"]', + ' },', + ' [property "nick"]: { [meta "@container"]: [meta "@set"] },', + ' [property "nick"]: { [meta "@container"]: [meta "@index"] }', + ' },', + ' [meta "@graph"]: [[ {', + ' [meta "@id"]: [string "http://dbpedia.org/resource/John_Lennon"],', + ' [property "name"]: [string "John Lennon"],', + ' [property "modified"]: {', + ' [meta "@value"]: [string "2010-05-29T14:17:39+02:00"],', + ' [meta "@type"]: [string "http://www.w3.org/2001/XMLSchema#dateTime"]', + ' }', + ' } ]]', + '}'); + + LD("json_ld_fake", + '{', + ' [property "@fake"]: [string "@fake"],', + ' [property "@contextual"]: [string "@identifier"],', + ' [property "user@domain.com"]: [string "@graphical"],', + ' [property "@ID"]: [string "@@ID"]', + '}'); +})(); diff --git a/Upload/admin/jscripts/codemirror/mode/javascript/typescript.html b/Upload/admin/jscripts/codemirror/mode/javascript/typescript.html new file mode 100644 index 0000000..9cc5f49 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/javascript/typescript.html @@ -0,0 +1,61 @@ + + +CodeMirror: TypeScript mode + + + + + + + + + +
+

TypeScript mode

+ + +
+ + + +

This is a specialization of the JavaScript mode.

+
diff --git a/Upload/admin/jscripts/codemirror/mode/xml/index.html b/Upload/admin/jscripts/codemirror/mode/xml/index.html new file mode 100644 index 0000000..60ebd20 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/xml/index.html @@ -0,0 +1,57 @@ + + +CodeMirror: XML mode + + + + + + + + + +
+

XML mode

+
+ +

The XML mode supports two configuration parameters:

+
+
htmlMode (boolean)
+
This switches the mode to parse HTML instead of XML. This + means attributes do not have to be quoted, and some elements + (such as br) do not require a closing tag.
+
alignCDATA (boolean)
+
Setting this to true will force the opening tag of CDATA + blocks to not be indented.
+
+ +

MIME types defined: application/xml, text/html.

+
diff --git a/Upload/admin/jscripts/codemirror/mode/xml/test.js b/Upload/admin/jscripts/codemirror/mode/xml/test.js new file mode 100644 index 0000000..f48156b --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/xml/test.js @@ -0,0 +1,51 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "xml"), mname = "xml"; + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), mname); } + + MT("matching", + "[tag&bracket <][tag top][tag&bracket >]", + " text", + " [tag&bracket <][tag inner][tag&bracket />]", + "[tag&bracket ]"); + + MT("nonmatching", + "[tag&bracket <][tag top][tag&bracket >]", + " [tag&bracket <][tag inner][tag&bracket />]", + " [tag&bracket ]"); + + MT("doctype", + "[meta ]", + "[tag&bracket <][tag top][tag&bracket />]"); + + MT("cdata", + "[tag&bracket <][tag top][tag&bracket >]", + " [atom ]", + "[tag&bracket ]"); + + // HTML tests + mode = CodeMirror.getMode({indentUnit: 2}, "text/html"); + + MT("selfclose", + "[tag&bracket <][tag html][tag&bracket >]", + " [tag&bracket <][tag link] [attribute rel]=[string stylesheet] [attribute href]=[string \"/foobar\"][tag&bracket >]", + "[tag&bracket ]"); + + MT("list", + "[tag&bracket <][tag ol][tag&bracket >]", + " [tag&bracket <][tag li][tag&bracket >]one", + " [tag&bracket <][tag li][tag&bracket >]two", + "[tag&bracket ]"); + + MT("valueless", + "[tag&bracket <][tag input] [attribute type]=[string checkbox] [attribute checked][tag&bracket />]"); + + MT("pThenArticle", + "[tag&bracket <][tag p][tag&bracket >]", + " foo", + "[tag&bracket <][tag article][tag&bracket >]bar"); + +})(); diff --git a/Upload/admin/jscripts/codemirror/mode/xml/xml.js b/Upload/admin/jscripts/codemirror/mode/xml/xml.js new file mode 100644 index 0000000..786507d --- /dev/null +++ b/Upload/admin/jscripts/codemirror/mode/xml/xml.js @@ -0,0 +1,384 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("xml", function(config, parserConfig) { + var indentUnit = config.indentUnit; + var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1; + var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag; + if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true; + + var Kludges = parserConfig.htmlMode ? { + autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, + 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, + 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true, + 'track': true, 'wbr': true}, + implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true, + 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true, + 'th': true, 'tr': true}, + contextGrabbers: { + 'dd': {'dd': true, 'dt': true}, + 'dt': {'dd': true, 'dt': true}, + 'li': {'li': true}, + 'option': {'option': true, 'optgroup': true}, + 'optgroup': {'optgroup': true}, + 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true, + 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true, + 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, + 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true, + 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true}, + 'rp': {'rp': true, 'rt': true}, + 'rt': {'rp': true, 'rt': true}, + 'tbody': {'tbody': true, 'tfoot': true}, + 'td': {'td': true, 'th': true}, + 'tfoot': {'tbody': true}, + 'th': {'td': true, 'th': true}, + 'thead': {'tbody': true, 'tfoot': true}, + 'tr': {'tr': true} + }, + doNotIndent: {"pre": true}, + allowUnquoted: true, + allowMissing: true, + caseFold: true + } : { + autoSelfClosers: {}, + implicitlyClosed: {}, + contextGrabbers: {}, + doNotIndent: {}, + allowUnquoted: false, + allowMissing: false, + caseFold: false + }; + var alignCDATA = parserConfig.alignCDATA; + + // Return variables for tokenizers + var type, setStyle; + + function inText(stream, state) { + function chain(parser) { + state.tokenize = parser; + return parser(stream, state); + } + + var ch = stream.next(); + if (ch == "<") { + if (stream.eat("!")) { + if (stream.eat("[")) { + if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>")); + else return null; + } else if (stream.match("--")) { + return chain(inBlock("comment", "-->")); + } else if (stream.match("DOCTYPE", true, true)) { + stream.eatWhile(/[\w\._\-]/); + return chain(doctype(1)); + } else { + return null; + } + } else if (stream.eat("?")) { + stream.eatWhile(/[\w\._\-]/); + state.tokenize = inBlock("meta", "?>"); + return "meta"; + } else { + type = stream.eat("/") ? "closeTag" : "openTag"; + state.tokenize = inTag; + return "tag bracket"; + } + } else if (ch == "&") { + var ok; + if (stream.eat("#")) { + if (stream.eat("x")) { + ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); + } else { + ok = stream.eatWhile(/[\d]/) && stream.eat(";"); + } + } else { + ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); + } + return ok ? "atom" : "error"; + } else { + stream.eatWhile(/[^&<]/); + return null; + } + } + + function inTag(stream, state) { + var ch = stream.next(); + if (ch == ">" || (ch == "/" && stream.eat(">"))) { + state.tokenize = inText; + type = ch == ">" ? "endTag" : "selfcloseTag"; + return "tag bracket"; + } else if (ch == "=") { + type = "equals"; + return null; + } else if (ch == "<") { + state.tokenize = inText; + state.state = baseState; + state.tagName = state.tagStart = null; + var next = state.tokenize(stream, state); + return next ? next + " tag error" : "tag error"; + } else if (/[\'\"]/.test(ch)) { + state.tokenize = inAttribute(ch); + state.stringStartCol = stream.column(); + return state.tokenize(stream, state); + } else { + stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/); + return "word"; + } + } + + function inAttribute(quote) { + var closure = function(stream, state) { + while (!stream.eol()) { + if (stream.next() == quote) { + state.tokenize = inTag; + break; + } + } + return "string"; + }; + closure.isInAttribute = true; + return closure; + } + + function inBlock(style, terminator) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + state.tokenize = inText; + break; + } + stream.next(); + } + return style; + }; + } + function doctype(depth) { + return function(stream, state) { + var ch; + while ((ch = stream.next()) != null) { + if (ch == "<") { + state.tokenize = doctype(depth + 1); + return state.tokenize(stream, state); + } else if (ch == ">") { + if (depth == 1) { + state.tokenize = inText; + break; + } else { + state.tokenize = doctype(depth - 1); + return state.tokenize(stream, state); + } + } + } + return "meta"; + }; + } + + function Context(state, tagName, startOfLine) { + this.prev = state.context; + this.tagName = tagName; + this.indent = state.indented; + this.startOfLine = startOfLine; + if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent)) + this.noIndent = true; + } + function popContext(state) { + if (state.context) state.context = state.context.prev; + } + function maybePopContext(state, nextTagName) { + var parentTagName; + while (true) { + if (!state.context) { + return; + } + parentTagName = state.context.tagName; + if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) || + !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { + return; + } + popContext(state); + } + } + + function baseState(type, stream, state) { + if (type == "openTag") { + state.tagStart = stream.column(); + return tagNameState; + } else if (type == "closeTag") { + return closeTagNameState; + } else { + return baseState; + } + } + function tagNameState(type, stream, state) { + if (type == "word") { + state.tagName = stream.current(); + setStyle = "tag"; + return attrState; + } else { + setStyle = "error"; + return tagNameState; + } + } + function closeTagNameState(type, stream, state) { + if (type == "word") { + var tagName = stream.current(); + if (state.context && state.context.tagName != tagName && + Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName)) + popContext(state); + if (state.context && state.context.tagName == tagName) { + setStyle = "tag"; + return closeState; + } else { + setStyle = "tag error"; + return closeStateErr; + } + } else { + setStyle = "error"; + return closeStateErr; + } + } + + function closeState(type, _stream, state) { + if (type != "endTag") { + setStyle = "error"; + return closeState; + } + popContext(state); + return baseState; + } + function closeStateErr(type, stream, state) { + setStyle = "error"; + return closeState(type, stream, state); + } + + function attrState(type, _stream, state) { + if (type == "word") { + setStyle = "attribute"; + return attrEqState; + } else if (type == "endTag" || type == "selfcloseTag") { + var tagName = state.tagName, tagStart = state.tagStart; + state.tagName = state.tagStart = null; + if (type == "selfcloseTag" || + Kludges.autoSelfClosers.hasOwnProperty(tagName)) { + maybePopContext(state, tagName); + } else { + maybePopContext(state, tagName); + state.context = new Context(state, tagName, tagStart == state.indented); + } + return baseState; + } + setStyle = "error"; + return attrState; + } + function attrEqState(type, stream, state) { + if (type == "equals") return attrValueState; + if (!Kludges.allowMissing) setStyle = "error"; + return attrState(type, stream, state); + } + function attrValueState(type, stream, state) { + if (type == "string") return attrContinuedState; + if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;} + setStyle = "error"; + return attrState(type, stream, state); + } + function attrContinuedState(type, stream, state) { + if (type == "string") return attrContinuedState; + return attrState(type, stream, state); + } + + return { + startState: function() { + return {tokenize: inText, + state: baseState, + indented: 0, + tagName: null, tagStart: null, + context: null}; + }, + + token: function(stream, state) { + if (!state.tagName && stream.sol()) + state.indented = stream.indentation(); + + if (stream.eatSpace()) return null; + type = null; + var style = state.tokenize(stream, state); + if ((style || type) && style != "comment") { + setStyle = null; + state.state = state.state(type || style, stream, state); + if (setStyle) + style = setStyle == "error" ? style + " error" : setStyle; + } + return style; + }, + + indent: function(state, textAfter, fullLine) { + var context = state.context; + // Indent multi-line strings (e.g. css). + if (state.tokenize.isInAttribute) { + if (state.tagStart == state.indented) + return state.stringStartCol + 1; + else + return state.indented + indentUnit; + } + if (context && context.noIndent) return CodeMirror.Pass; + if (state.tokenize != inTag && state.tokenize != inText) + return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; + // Indent the starts of attribute names. + if (state.tagName) { + if (multilineTagIndentPastTag) + return state.tagStart + state.tagName.length + 2; + else + return state.tagStart + indentUnit * multilineTagIndentFactor; + } + if (alignCDATA && /$/, + blockCommentStart: "", + + configuration: parserConfig.htmlMode ? "html" : "xml", + helperType: parserConfig.htmlMode ? "html" : "xml" + }; +}); + +CodeMirror.defineMIME("text/xml", "xml"); +CodeMirror.defineMIME("application/xml", "xml"); +if (!CodeMirror.mimeModes.hasOwnProperty("text/html")) + CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true}); + +}); diff --git a/Upload/admin/jscripts/codemirror/theme/3024-day.css b/Upload/admin/jscripts/codemirror/theme/3024-day.css new file mode 100644 index 0000000..ebf46fb --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/3024-day.css @@ -0,0 +1,38 @@ +/* + + Name: 3024 day + Author: Jan T. Sott (http://github.com/idleberg) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-3024-day.CodeMirror {background: #f7f7f7; color: #3a3432;} +.cm-s-3024-day div.CodeMirror-selected {background: #d6d5d4 !important;} + +.cm-s-3024-day .CodeMirror-gutters {background: #f7f7f7; border-right: 0px;} +.cm-s-3024-day .CodeMirror-guttermarker { color: #db2d20; } +.cm-s-3024-day .CodeMirror-guttermarker-subtle { color: #807d7c; } +.cm-s-3024-day .CodeMirror-linenumber {color: #807d7c;} + +.cm-s-3024-day .CodeMirror-cursor {border-left: 1px solid #5c5855 !important;} + +.cm-s-3024-day span.cm-comment {color: #cdab53;} +.cm-s-3024-day span.cm-atom {color: #a16a94;} +.cm-s-3024-day span.cm-number {color: #a16a94;} + +.cm-s-3024-day span.cm-property, .cm-s-3024-day span.cm-attribute {color: #01a252;} +.cm-s-3024-day span.cm-keyword {color: #db2d20;} +.cm-s-3024-day span.cm-string {color: #fded02;} + +.cm-s-3024-day span.cm-variable {color: #01a252;} +.cm-s-3024-day span.cm-variable-2 {color: #01a0e4;} +.cm-s-3024-day span.cm-def {color: #e8bbd0;} +.cm-s-3024-day span.cm-bracket {color: #3a3432;} +.cm-s-3024-day span.cm-tag {color: #db2d20;} +.cm-s-3024-day span.cm-link {color: #a16a94;} +.cm-s-3024-day span.cm-error {background: #db2d20; color: #5c5855;} + +.cm-s-3024-day .CodeMirror-activeline-background {background: #e8f2ff !important;} +.cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/3024-night.css b/Upload/admin/jscripts/codemirror/theme/3024-night.css new file mode 100644 index 0000000..631757f --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/3024-night.css @@ -0,0 +1,37 @@ +/* + + Name: 3024 night + Author: Jan T. Sott (http://github.com/idleberg) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-3024-night.CodeMirror {background: #090300; color: #d6d5d4;} +.cm-s-3024-night div.CodeMirror-selected {background: #3a3432 !important;} +.cm-s-3024-night .CodeMirror-gutters {background: #090300; border-right: 0px;} +.cm-s-3024-night .CodeMirror-guttermarker { color: #db2d20; } +.cm-s-3024-night .CodeMirror-guttermarker-subtle { color: #5c5855; } +.cm-s-3024-night .CodeMirror-linenumber {color: #5c5855;} + +.cm-s-3024-night .CodeMirror-cursor {border-left: 1px solid #807d7c !important;} + +.cm-s-3024-night span.cm-comment {color: #cdab53;} +.cm-s-3024-night span.cm-atom {color: #a16a94;} +.cm-s-3024-night span.cm-number {color: #a16a94;} + +.cm-s-3024-night span.cm-property, .cm-s-3024-night span.cm-attribute {color: #01a252;} +.cm-s-3024-night span.cm-keyword {color: #db2d20;} +.cm-s-3024-night span.cm-string {color: #fded02;} + +.cm-s-3024-night span.cm-variable {color: #01a252;} +.cm-s-3024-night span.cm-variable-2 {color: #01a0e4;} +.cm-s-3024-night span.cm-def {color: #e8bbd0;} +.cm-s-3024-night span.cm-bracket {color: #d6d5d4;} +.cm-s-3024-night span.cm-tag {color: #db2d20;} +.cm-s-3024-night span.cm-link {color: #a16a94;} +.cm-s-3024-night span.cm-error {background: #db2d20; color: #807d7c;} + +.cm-s-3024-night .CodeMirror-activeline-background {background: #2F2F2F !important;} +.cm-s-3024-night .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/ambiance-mobile.css b/Upload/admin/jscripts/codemirror/theme/ambiance-mobile.css new file mode 100644 index 0000000..88d332e --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/ambiance-mobile.css @@ -0,0 +1,5 @@ +.cm-s-ambiance.CodeMirror { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} diff --git a/Upload/admin/jscripts/codemirror/theme/ambiance.css b/Upload/admin/jscripts/codemirror/theme/ambiance.css new file mode 100644 index 0000000..c844566 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/ambiance.css @@ -0,0 +1,77 @@ +/* ambiance theme for codemirror */ + +/* Color scheme */ + +.cm-s-ambiance .cm-keyword { color: #cda869; } +.cm-s-ambiance .cm-atom { color: #CF7EA9; } +.cm-s-ambiance .cm-number { color: #78CF8A; } +.cm-s-ambiance .cm-def { color: #aac6e3; } +.cm-s-ambiance .cm-variable { color: #ffb795; } +.cm-s-ambiance .cm-variable-2 { color: #eed1b3; } +.cm-s-ambiance .cm-variable-3 { color: #faded3; } +.cm-s-ambiance .cm-property { color: #eed1b3; } +.cm-s-ambiance .cm-operator {color: #fa8d6a;} +.cm-s-ambiance .cm-comment { color: #555; font-style:italic; } +.cm-s-ambiance .cm-string { color: #8f9d6a; } +.cm-s-ambiance .cm-string-2 { color: #9d937c; } +.cm-s-ambiance .cm-meta { color: #D2A8A1; } +.cm-s-ambiance .cm-qualifier { color: yellow; } +.cm-s-ambiance .cm-builtin { color: #9999cc; } +.cm-s-ambiance .cm-bracket { color: #24C2C7; } +.cm-s-ambiance .cm-tag { color: #fee4ff } +.cm-s-ambiance .cm-attribute { color: #9B859D; } +.cm-s-ambiance .cm-header {color: blue;} +.cm-s-ambiance .cm-quote { color: #24C2C7; } +.cm-s-ambiance .cm-hr { color: pink; } +.cm-s-ambiance .cm-link { color: #F4C20B; } +.cm-s-ambiance .cm-special { color: #FF9D00; } +.cm-s-ambiance .cm-error { color: #AF2018; } + +.cm-s-ambiance .CodeMirror-matchingbracket { color: #0f0; } +.cm-s-ambiance .CodeMirror-nonmatchingbracket { color: #f22; } + +.cm-s-ambiance .CodeMirror-selected { + background: rgba(255, 255, 255, 0.15); +} +.cm-s-ambiance.CodeMirror-focused .CodeMirror-selected { + background: rgba(255, 255, 255, 0.10); +} + +/* Editor styling */ + +.cm-s-ambiance.CodeMirror { + line-height: 1.40em; + color: #E6E1DC; + background-color: #202020; + -webkit-box-shadow: inset 0 0 10px black; + -moz-box-shadow: inset 0 0 10px black; + box-shadow: inset 0 0 10px black; +} + +.cm-s-ambiance .CodeMirror-gutters { + background: #3D3D3D; + border-right: 1px solid #4D4D4D; + box-shadow: 0 10px 20px black; +} + +.cm-s-ambiance .CodeMirror-linenumber { + text-shadow: 0px 1px 1px #4d4d4d; + color: #111; + padding: 0 5px; +} + +.cm-s-ambiance .CodeMirror-guttermarker { color: #aaa; } +.cm-s-ambiance .CodeMirror-guttermarker-subtle { color: #111; } + +.cm-s-ambiance .CodeMirror-lines .CodeMirror-cursor { + border-left: 1px solid #7991E8; +} + +.cm-s-ambiance .CodeMirror-activeline-background { + background: none repeat scroll 0% 0% rgba(255, 255, 255, 0.031); +} + +.cm-s-ambiance.CodeMirror, +.cm-s-ambiance .CodeMirror-gutters { + background-image: url("data:image/png;base64,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"); +} diff --git a/Upload/admin/jscripts/codemirror/theme/base16-dark.css b/Upload/admin/jscripts/codemirror/theme/base16-dark.css new file mode 100644 index 0000000..199997a --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/base16-dark.css @@ -0,0 +1,36 @@ +/* + + Name: Base16 Default Dark + Author: Chris Kempson (http://chriskempson.com) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-base16-dark.CodeMirror {background: #151515; color: #e0e0e0;} +.cm-s-base16-dark div.CodeMirror-selected {background: #202020 !important;} +.cm-s-base16-dark .CodeMirror-gutters {background: #151515; border-right: 0px;} +.cm-s-base16-dark .CodeMirror-guttermarker { color: #ac4142; } +.cm-s-base16-dark .CodeMirror-guttermarker-subtle { color: #505050; } +.cm-s-base16-dark .CodeMirror-linenumber {color: #505050;} +.cm-s-base16-dark .CodeMirror-cursor {border-left: 1px solid #b0b0b0 !important;} + +.cm-s-base16-dark span.cm-comment {color: #8f5536;} +.cm-s-base16-dark span.cm-atom {color: #aa759f;} +.cm-s-base16-dark span.cm-number {color: #aa759f;} + +.cm-s-base16-dark span.cm-property, .cm-s-base16-dark span.cm-attribute {color: #90a959;} +.cm-s-base16-dark span.cm-keyword {color: #ac4142;} +.cm-s-base16-dark span.cm-string {color: #f4bf75;} + +.cm-s-base16-dark span.cm-variable {color: #90a959;} +.cm-s-base16-dark span.cm-variable-2 {color: #6a9fb5;} +.cm-s-base16-dark span.cm-def {color: #d28445;} +.cm-s-base16-dark span.cm-bracket {color: #e0e0e0;} +.cm-s-base16-dark span.cm-tag {color: #ac4142;} +.cm-s-base16-dark span.cm-link {color: #aa759f;} +.cm-s-base16-dark span.cm-error {background: #ac4142; color: #b0b0b0;} + +.cm-s-base16-dark .CodeMirror-activeline-background {background: #2F2F2F !important;} +.cm-s-base16-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/base16-light.css b/Upload/admin/jscripts/codemirror/theme/base16-light.css new file mode 100644 index 0000000..12ff2eb --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/base16-light.css @@ -0,0 +1,36 @@ +/* + + Name: Base16 Default Light + Author: Chris Kempson (http://chriskempson.com) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-base16-light.CodeMirror {background: #f5f5f5; color: #202020;} +.cm-s-base16-light div.CodeMirror-selected {background: #e0e0e0 !important;} +.cm-s-base16-light .CodeMirror-gutters {background: #f5f5f5; border-right: 0px;} +.cm-s-base16-light .CodeMirror-guttermarker { color: #ac4142; } +.cm-s-base16-light .CodeMirror-guttermarker-subtle { color: #b0b0b0; } +.cm-s-base16-light .CodeMirror-linenumber {color: #b0b0b0;} +.cm-s-base16-light .CodeMirror-cursor {border-left: 1px solid #505050 !important;} + +.cm-s-base16-light span.cm-comment {color: #8f5536;} +.cm-s-base16-light span.cm-atom {color: #aa759f;} +.cm-s-base16-light span.cm-number {color: #aa759f;} + +.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute {color: #90a959;} +.cm-s-base16-light span.cm-keyword {color: #ac4142;} +.cm-s-base16-light span.cm-string {color: #f4bf75;} + +.cm-s-base16-light span.cm-variable {color: #90a959;} +.cm-s-base16-light span.cm-variable-2 {color: #6a9fb5;} +.cm-s-base16-light span.cm-def {color: #d28445;} +.cm-s-base16-light span.cm-bracket {color: #202020;} +.cm-s-base16-light span.cm-tag {color: #ac4142;} +.cm-s-base16-light span.cm-link {color: #aa759f;} +.cm-s-base16-light span.cm-error {background: #ac4142; color: #505050;} + +.cm-s-base16-light .CodeMirror-activeline-background {background: #DDDCDC !important;} +.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/blackboard.css b/Upload/admin/jscripts/codemirror/theme/blackboard.css new file mode 100644 index 0000000..d7a2dc9 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/blackboard.css @@ -0,0 +1,30 @@ +/* Port of TextMate's Blackboard theme */ + +.cm-s-blackboard.CodeMirror { background: #0C1021; color: #F8F8F8; } +.cm-s-blackboard .CodeMirror-selected { background: #253B76 !important; } +.cm-s-blackboard .CodeMirror-gutters { background: #0C1021; border-right: 0; } +.cm-s-blackboard .CodeMirror-guttermarker { color: #FBDE2D; } +.cm-s-blackboard .CodeMirror-guttermarker-subtle { color: #888; } +.cm-s-blackboard .CodeMirror-linenumber { color: #888; } +.cm-s-blackboard .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; } + +.cm-s-blackboard .cm-keyword { color: #FBDE2D; } +.cm-s-blackboard .cm-atom { color: #D8FA3C; } +.cm-s-blackboard .cm-number { color: #D8FA3C; } +.cm-s-blackboard .cm-def { color: #8DA6CE; } +.cm-s-blackboard .cm-variable { color: #FF6400; } +.cm-s-blackboard .cm-operator { color: #FBDE2D;} +.cm-s-blackboard .cm-comment { color: #AEAEAE; } +.cm-s-blackboard .cm-string { color: #61CE3C; } +.cm-s-blackboard .cm-string-2 { color: #61CE3C; } +.cm-s-blackboard .cm-meta { color: #D8FA3C; } +.cm-s-blackboard .cm-builtin { color: #8DA6CE; } +.cm-s-blackboard .cm-tag { color: #8DA6CE; } +.cm-s-blackboard .cm-attribute { color: #8DA6CE; } +.cm-s-blackboard .cm-header { color: #FF6400; } +.cm-s-blackboard .cm-hr { color: #AEAEAE; } +.cm-s-blackboard .cm-link { color: #8DA6CE; } +.cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; } + +.cm-s-blackboard .CodeMirror-activeline-background {background: #3C3636 !important;} +.cm-s-blackboard .CodeMirror-matchingbracket {outline:1px solid grey;color:white !important} \ No newline at end of file diff --git a/Upload/admin/jscripts/codemirror/theme/cobalt.css b/Upload/admin/jscripts/codemirror/theme/cobalt.css new file mode 100644 index 0000000..4744053 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/cobalt.css @@ -0,0 +1,23 @@ +.cm-s-cobalt.CodeMirror { background: #002240; color: white; } +.cm-s-cobalt div.CodeMirror-selected { background: #b36539 !important; } +.cm-s-cobalt .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; } +.cm-s-cobalt .CodeMirror-guttermarker { color: #ffee80; } +.cm-s-cobalt .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-cobalt .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-cobalt .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-cobalt span.cm-comment { color: #08f; } +.cm-s-cobalt span.cm-atom { color: #845dc4; } +.cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { color: #ff80e1; } +.cm-s-cobalt span.cm-keyword { color: #ffee80; } +.cm-s-cobalt span.cm-string { color: #3ad900; } +.cm-s-cobalt span.cm-meta { color: #ff9d00; } +.cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; } +.cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def { color: white; } +.cm-s-cobalt span.cm-bracket { color: #d8d8d8; } +.cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; } +.cm-s-cobalt span.cm-link { color: #845dc4; } +.cm-s-cobalt span.cm-error { color: #9d1e15; } + +.cm-s-cobalt .CodeMirror-activeline-background {background: #002D57 !important;} +.cm-s-cobalt .CodeMirror-matchingbracket {outline:1px solid grey;color:white !important} diff --git a/Upload/admin/jscripts/codemirror/theme/eclipse.css b/Upload/admin/jscripts/codemirror/theme/eclipse.css new file mode 100644 index 0000000..317218e --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/eclipse.css @@ -0,0 +1,23 @@ +.cm-s-eclipse span.cm-meta {color: #FF1717;} +.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; } +.cm-s-eclipse span.cm-atom {color: #219;} +.cm-s-eclipse span.cm-number {color: #164;} +.cm-s-eclipse span.cm-def {color: #00f;} +.cm-s-eclipse span.cm-variable {color: black;} +.cm-s-eclipse span.cm-variable-2 {color: #0000C0;} +.cm-s-eclipse span.cm-variable-3 {color: #0000C0;} +.cm-s-eclipse span.cm-property {color: black;} +.cm-s-eclipse span.cm-operator {color: black;} +.cm-s-eclipse span.cm-comment {color: #3F7F5F;} +.cm-s-eclipse span.cm-string {color: #2A00FF;} +.cm-s-eclipse span.cm-string-2 {color: #f50;} +.cm-s-eclipse span.cm-qualifier {color: #555;} +.cm-s-eclipse span.cm-builtin {color: #30a;} +.cm-s-eclipse span.cm-bracket {color: #cc7;} +.cm-s-eclipse span.cm-tag {color: #170;} +.cm-s-eclipse span.cm-attribute {color: #00c;} +.cm-s-eclipse span.cm-link {color: #219;} +.cm-s-eclipse span.cm-error {color: #f00;} + +.cm-s-eclipse .CodeMirror-activeline-background {background: #e8f2ff !important;} +.cm-s-eclipse .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/elegant.css b/Upload/admin/jscripts/codemirror/theme/elegant.css new file mode 100644 index 0000000..dd7df7b --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/elegant.css @@ -0,0 +1,13 @@ +.cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom {color: #762;} +.cm-s-elegant span.cm-comment {color: #262; font-style: italic; line-height: 1em;} +.cm-s-elegant span.cm-meta {color: #555; font-style: italic; line-height: 1em;} +.cm-s-elegant span.cm-variable {color: black;} +.cm-s-elegant span.cm-variable-2 {color: #b11;} +.cm-s-elegant span.cm-qualifier {color: #555;} +.cm-s-elegant span.cm-keyword {color: #730;} +.cm-s-elegant span.cm-builtin {color: #30a;} +.cm-s-elegant span.cm-link {color: #762;} +.cm-s-elegant span.cm-error {background-color: #fdd;} + +.cm-s-elegant .CodeMirror-activeline-background {background: #e8f2ff !important;} +.cm-s-elegant .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/erlang-dark.css b/Upload/admin/jscripts/codemirror/theme/erlang-dark.css new file mode 100644 index 0000000..ff47d7f --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/erlang-dark.css @@ -0,0 +1,32 @@ +.cm-s-erlang-dark.CodeMirror { background: #002240; color: white; } +.cm-s-erlang-dark div.CodeMirror-selected { background: #b36539 !important; } +.cm-s-erlang-dark .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; } +.cm-s-erlang-dark .CodeMirror-guttermarker { color: white; } +.cm-s-erlang-dark .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-erlang-dark .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-erlang-dark .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-erlang-dark span.cm-atom { color: #f133f1; } +.cm-s-erlang-dark span.cm-attribute { color: #ff80e1; } +.cm-s-erlang-dark span.cm-bracket { color: #ff9d00; } +.cm-s-erlang-dark span.cm-builtin { color: #eaa; } +.cm-s-erlang-dark span.cm-comment { color: #77f; } +.cm-s-erlang-dark span.cm-def { color: #e7a; } +.cm-s-erlang-dark span.cm-keyword { color: #ffee80; } +.cm-s-erlang-dark span.cm-meta { color: #50fefe; } +.cm-s-erlang-dark span.cm-number { color: #ffd0d0; } +.cm-s-erlang-dark span.cm-operator { color: #d55; } +.cm-s-erlang-dark span.cm-property { color: #ccc; } +.cm-s-erlang-dark span.cm-qualifier { color: #ccc; } +.cm-s-erlang-dark span.cm-quote { color: #ccc; } +.cm-s-erlang-dark span.cm-special { color: #ffbbbb; } +.cm-s-erlang-dark span.cm-string { color: #3ad900; } +.cm-s-erlang-dark span.cm-string-2 { color: #ccc; } +.cm-s-erlang-dark span.cm-tag { color: #9effff; } +.cm-s-erlang-dark span.cm-variable { color: #50fe50; } +.cm-s-erlang-dark span.cm-variable-2 { color: #e0e; } +.cm-s-erlang-dark span.cm-variable-3 { color: #ccc; } +.cm-s-erlang-dark span.cm-error { color: #9d1e15; } + +.cm-s-erlang-dark .CodeMirror-activeline-background {background: #013461 !important;} +.cm-s-erlang-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/index.html b/Upload/admin/jscripts/codemirror/theme/index.html new file mode 100644 index 0000000..063e69b --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/index.html @@ -0,0 +1,110 @@ + + +CodeMirror: Language Modes + + + + + +
+ +

Language modes

+ +

This is a list of every mode in the distribution. Each mode lives +in a subdirectory of the mode/ directory, and typically +defines a single JavaScript file that implements the mode. Loading +such file will make the language available to CodeMirror, through +the mode +option.

+ + + +
diff --git a/Upload/admin/jscripts/codemirror/theme/lesser-dark.css b/Upload/admin/jscripts/codemirror/theme/lesser-dark.css new file mode 100644 index 0000000..a782474 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/lesser-dark.css @@ -0,0 +1,45 @@ +/* +http://lesscss.org/ dark theme +Ported to CodeMirror by Peter Kroon +*/ +.cm-s-lesser-dark { + line-height: 1.3em; +} +.cm-s-lesser-dark.CodeMirror { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; } +.cm-s-lesser-dark div.CodeMirror-selected {background: #45443B !important;} /* 33322B*/ +.cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white !important; } +.cm-s-lesser-dark pre { padding: 0 8px; }/*editable code holder*/ + +.cm-s-lesser-dark.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/ + +.cm-s-lesser-dark .CodeMirror-gutters { background: #262626; border-right:1px solid #aaa; } +.cm-s-lesser-dark .CodeMirror-guttermarker { color: #599eff; } +.cm-s-lesser-dark .CodeMirror-guttermarker-subtle { color: #777; } +.cm-s-lesser-dark .CodeMirror-linenumber { color: #777; } + +.cm-s-lesser-dark span.cm-keyword { color: #599eff; } +.cm-s-lesser-dark span.cm-atom { color: #C2B470; } +.cm-s-lesser-dark span.cm-number { color: #B35E4D; } +.cm-s-lesser-dark span.cm-def {color: white;} +.cm-s-lesser-dark span.cm-variable { color:#D9BF8C; } +.cm-s-lesser-dark span.cm-variable-2 { color: #669199; } +.cm-s-lesser-dark span.cm-variable-3 { color: white; } +.cm-s-lesser-dark span.cm-property {color: #92A75C;} +.cm-s-lesser-dark span.cm-operator {color: #92A75C;} +.cm-s-lesser-dark span.cm-comment { color: #666; } +.cm-s-lesser-dark span.cm-string { color: #BCD279; } +.cm-s-lesser-dark span.cm-string-2 {color: #f50;} +.cm-s-lesser-dark span.cm-meta { color: #738C73; } +.cm-s-lesser-dark span.cm-qualifier {color: #555;} +.cm-s-lesser-dark span.cm-builtin { color: #ff9e59; } +.cm-s-lesser-dark span.cm-bracket { color: #EBEFE7; } +.cm-s-lesser-dark span.cm-tag { color: #669199; } +.cm-s-lesser-dark span.cm-attribute {color: #00c;} +.cm-s-lesser-dark span.cm-header {color: #a0a;} +.cm-s-lesser-dark span.cm-quote {color: #090;} +.cm-s-lesser-dark span.cm-hr {color: #999;} +.cm-s-lesser-dark span.cm-link {color: #00c;} +.cm-s-lesser-dark span.cm-error { color: #9d1e15; } + +.cm-s-lesser-dark .CodeMirror-activeline-background {background: #3C3A3A !important;} +.cm-s-lesser-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/mbo.css b/Upload/admin/jscripts/codemirror/theme/mbo.css new file mode 100644 index 0000000..6cb2b18 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/mbo.css @@ -0,0 +1,39 @@ +/* Based on mbonaci's Brackets mbo theme */ + +.cm-s-mbo.CodeMirror {background: #2c2c2c; color: #ffffe9;} +.cm-s-mbo div.CodeMirror-selected {background: #716C62 !important;} +.cm-s-mbo .CodeMirror-gutters {background: #4e4e4e; border-right: 0px;} +.cm-s-mbo .CodeMirror-guttermarker { color: white; } +.cm-s-mbo .CodeMirror-guttermarker-subtle { color: grey; } +.cm-s-mbo .CodeMirror-linenumber {color: #dadada;} +.cm-s-mbo .CodeMirror-cursor {border-left: 1px solid #ffffec !important;} + +.cm-s-mbo span.cm-comment {color: #95958a;} +.cm-s-mbo span.cm-atom {color: #00a8c6;} +.cm-s-mbo span.cm-number {color: #00a8c6;} + +.cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute {color: #9ddfe9;} +.cm-s-mbo span.cm-keyword {color: #ffb928;} +.cm-s-mbo span.cm-string {color: #ffcf6c;} + +.cm-s-mbo span.cm-variable {color: #ffffec;} +.cm-s-mbo span.cm-variable-2 {color: #00a8c6;} +.cm-s-mbo span.cm-def {color: #ffffec;} +.cm-s-mbo span.cm-bracket {color: #fffffc; font-weight: bold;} +.cm-s-mbo span.cm-tag {color: #9ddfe9;} +.cm-s-mbo span.cm-link {color: #f54b07;} +.cm-s-mbo span.cm-error {border-bottom: #636363; color: #ffffec;} + +.cm-s-mbo .CodeMirror-activeline-background {background: #494b41 !important;} +.cm-s-mbo .CodeMirror-matchingbracket { + text-decoration: underline; + color: #f5e107 !important; + } + +.cm-s-mbo .CodeMirror-matchingtag { background: rgba(255, 255, 255, .37); } + +.cm-s-mbo span.cm-searching { + background-color: none; + background: none; + box-shadow: 0 0 0 1px #ffffec; +} diff --git a/Upload/admin/jscripts/codemirror/theme/mdn-like.css b/Upload/admin/jscripts/codemirror/theme/mdn-like.css new file mode 100644 index 0000000..1e20b9e --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/mdn-like.css @@ -0,0 +1,44 @@ +/* + MDN-LIKE Theme - Mozilla + Ported to CodeMirror by Peter Kroon + Report bugs/issues here: https://github.com/marijnh/CodeMirror/issues + GitHub: @peterkroon + + The mdn-like theme is inspired on the displayed code examples at: https://developer.mozilla.org/en-US/docs/Web/CSS/animation + +*/ +.cm-s-mdn-like.CodeMirror { color: #999; background-color: #fff; } +.cm-s-mdn-like .CodeMirror-selected { background: #cfc !important; } + +.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 6px solid rgba(0,83,159,0.65); color: #333; } +.cm-s-mdn-like .CodeMirror-linenumber { color: #aaa; margin-left: 3px; } +div.cm-s-mdn-like .CodeMirror-cursor { border-left: 2px solid #222; } + +.cm-s-mdn-like .cm-keyword { color: #6262FF; } +.cm-s-mdn-like .cm-atom { color: #F90; } +.cm-s-mdn-like .cm-number { color: #ca7841; } +.cm-s-mdn-like .cm-def { color: #8DA6CE; } +.cm-s-mdn-like span.cm-variable-2, .cm-s-mdn-like span.cm-tag { color: #690; } +.cm-s-mdn-like span.cm-variable-3, .cm-s-mdn-like span.cm-def { color: #07a; } + +.cm-s-mdn-like .cm-variable { color: #07a; } +.cm-s-mdn-like .cm-property { color: #905; } +.cm-s-mdn-like .cm-qualifier { color: #690; } + +.cm-s-mdn-like .cm-operator { color: #cda869; } +.cm-s-mdn-like .cm-comment { color:#777; font-weight:normal; } +.cm-s-mdn-like .cm-string { color:#07a; font-style:italic; } +.cm-s-mdn-like .cm-string-2 { color:#bd6b18; } /*?*/ +.cm-s-mdn-like .cm-meta { color: #000; } /*?*/ +.cm-s-mdn-like .cm-builtin { color: #9B7536; } /*?*/ +.cm-s-mdn-like .cm-tag { color: #997643; } +.cm-s-mdn-like .cm-attribute { color: #d6bb6d; } /*?*/ +.cm-s-mdn-like .cm-header { color: #FF6400; } +.cm-s-mdn-like .cm-hr { color: #AEAEAE; } +.cm-s-mdn-like .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } +.cm-s-mdn-like .cm-error { border-bottom: 1px solid red; } + +div.cm-s-mdn-like .CodeMirror-activeline-background {background: #efefff;} +div.cm-s-mdn-like span.CodeMirror-matchingbracket {outline:1px solid grey; color: inherit;} + +.cm-s-mdn-like.CodeMirror { background-image: url(data:image/png;base64,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); } diff --git a/Upload/admin/jscripts/codemirror/theme/midnight.css b/Upload/admin/jscripts/codemirror/theme/midnight.css new file mode 100644 index 0000000..4567d29 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/midnight.css @@ -0,0 +1,45 @@ +/* Based on the theme at http://bonsaiden.github.com/JavaScript-Garden */ + +/**/ +.cm-s-midnight span.CodeMirror-matchhighlight { background: #494949; } +.cm-s-midnight.CodeMirror-focused span.CodeMirror-matchhighlight { background: #314D67 !important; } + +/**/ +.cm-s-midnight .CodeMirror-activeline-background {background: #253540 !important;} + +.cm-s-midnight.CodeMirror { + background: #0F192A; + color: #D1EDFF; +} + +.cm-s-midnight.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} + +.cm-s-midnight div.CodeMirror-selected {background: #314D67 !important;} +.cm-s-midnight .CodeMirror-gutters {background: #0F192A; border-right: 1px solid;} +.cm-s-midnight .CodeMirror-guttermarker { color: white; } +.cm-s-midnight .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-midnight .CodeMirror-linenumber {color: #D0D0D0;} +.cm-s-midnight .CodeMirror-cursor { + border-left: 1px solid #F8F8F0 !important; +} + +.cm-s-midnight span.cm-comment {color: #428BDD;} +.cm-s-midnight span.cm-atom {color: #AE81FF;} +.cm-s-midnight span.cm-number {color: #D1EDFF;} + +.cm-s-midnight span.cm-property, .cm-s-midnight span.cm-attribute {color: #A6E22E;} +.cm-s-midnight span.cm-keyword {color: #E83737;} +.cm-s-midnight span.cm-string {color: #1DC116;} + +.cm-s-midnight span.cm-variable {color: #FFAA3E;} +.cm-s-midnight span.cm-variable-2 {color: #FFAA3E;} +.cm-s-midnight span.cm-def {color: #4DD;} +.cm-s-midnight span.cm-bracket {color: #D1EDFF;} +.cm-s-midnight span.cm-tag {color: #449;} +.cm-s-midnight span.cm-link {color: #AE81FF;} +.cm-s-midnight span.cm-error {background: #F92672; color: #F8F8F0;} + +.cm-s-midnight .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} diff --git a/Upload/admin/jscripts/codemirror/theme/monokai.css b/Upload/admin/jscripts/codemirror/theme/monokai.css new file mode 100644 index 0000000..548d2df --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/monokai.css @@ -0,0 +1,31 @@ +/* Based on Sublime Text's Monokai theme */ + +.cm-s-monokai.CodeMirror {background: #272822; color: #f8f8f2;} +.cm-s-monokai div.CodeMirror-selected {background: #49483E !important;} +.cm-s-monokai .CodeMirror-gutters {background: #272822; border-right: 0px;} +.cm-s-monokai .CodeMirror-guttermarker { color: white; } +.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-monokai .CodeMirror-linenumber {color: #d0d0d0;} +.cm-s-monokai .CodeMirror-cursor {border-left: 1px solid #f8f8f0 !important;} + +.cm-s-monokai span.cm-comment {color: #75715e;} +.cm-s-monokai span.cm-atom {color: #ae81ff;} +.cm-s-monokai span.cm-number {color: #ae81ff;} + +.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {color: #a6e22e;} +.cm-s-monokai span.cm-keyword {color: #f92672;} +.cm-s-monokai span.cm-string {color: #e6db74;} + +.cm-s-monokai span.cm-variable {color: #a6e22e;} +.cm-s-monokai span.cm-variable-2 {color: #9effff;} +.cm-s-monokai span.cm-def {color: #fd971f;} +.cm-s-monokai span.cm-bracket {color: #f8f8f2;} +.cm-s-monokai span.cm-tag {color: #f92672;} +.cm-s-monokai span.cm-link {color: #ae81ff;} +.cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;} + +.cm-s-monokai .CodeMirror-activeline-background {background: #373831 !important;} +.cm-s-monokai .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} diff --git a/Upload/admin/jscripts/codemirror/theme/mybb.css b/Upload/admin/jscripts/codemirror/theme/mybb.css new file mode 100644 index 0000000..61f9009 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/mybb.css @@ -0,0 +1,41 @@ +.cm-s-mybb { font:13px/1.4em Trebuchet, Verdana, sans-serif; } /* - customized editor font - */ + +.cm-s-mybb.CodeMirror { background: #fafafa; color: black; height: 500px; } +.cm-s-mybb div.CodeMirror-selected { background: #b3c6d3 !important; } +.cm-s-mybb .CodeMirror-gutters { background: #1F4661; border-right: 7px solid #3E7087; } +.cm-s-mybb .CodeMirror-linenumber { color: white; } +.cm-s-mybb .CodeMirror-cursor { border-left: 1px solid black !important; } +.cm-s-mybb .CodeMirror-scroll { overflow-x: auto; } + +.cm-s-mybb .cm-keyword {color: #708;} +.cm-s-mybb .cm-atom {color: #219;} +.cm-s-mybb .cm-number {color: #164;} +.cm-s-mybb .cm-def {color: #00f;} +.cm-s-mybb .cm-variable {color: black;} +.cm-s-mybb .cm-variable-2 {color: #05a;} +.cm-s-mybb .cm-variable-3 {color: #085;} +.cm-s-mybb .cm-property {color: black;} +.cm-s-mybb .cm-operator {color: black;} +.cm-s-mybb .cm-comment {color: #a50;} +.cm-s-mybb .cm-string {color: #a11;} +.cm-s-mybb .cm-string-2 {color: #f50;} +.cm-s-mybb .cm-meta {color: #555;} +.cm-s-mybb .cm-error {color: #f00;} +.cm-s-mybb .cm-qualifier {color: #555;} +.cm-s-mybb .cm-builtin {color: #30a;} +.cm-s-mybb .cm-bracket {color: #997;} +.cm-s-mybb .cm-tag {color: #170;} +.cm-s-mybb .cm-attribute {color: #00c;} +.cm-s-mybb .cm-header {color: blue;} +.cm-s-mybb .cm-quote {color: #090;} +.cm-s-mybb .cm-hr {color: #999;} +.cm-s-mybb .cm-link {color: #00c;} + +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-emstrong {font-style: italic; font-weight: bold;} +.cm-link {text-decoration: underline;} + +.cm-invalidchar {color: #f00;} diff --git a/Upload/admin/jscripts/codemirror/theme/neat.css b/Upload/admin/jscripts/codemirror/theme/neat.css new file mode 100644 index 0000000..115083b --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/neat.css @@ -0,0 +1,12 @@ +.cm-s-neat span.cm-comment { color: #a86; } +.cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; } +.cm-s-neat span.cm-string { color: #a22; } +.cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; } +.cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; } +.cm-s-neat span.cm-variable { color: black; } +.cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; } +.cm-s-neat span.cm-meta {color: #555;} +.cm-s-neat span.cm-link { color: #3a3; } + +.cm-s-neat .CodeMirror-activeline-background {background: #e8f2ff !important;} +.cm-s-neat .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/neo.css b/Upload/admin/jscripts/codemirror/theme/neo.css new file mode 100644 index 0000000..cecaaf2 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/neo.css @@ -0,0 +1,43 @@ +/* neo theme for codemirror */ + +/* Color scheme */ + +.cm-s-neo.CodeMirror { + background-color:#ffffff; + color:#2e383c; + line-height:1.4375; +} +.cm-s-neo .cm-comment {color:#75787b} +.cm-s-neo .cm-keyword, .cm-s-neo .cm-property {color:#1d75b3} +.cm-s-neo .cm-atom,.cm-s-neo .cm-number {color:#75438a} +.cm-s-neo .cm-node,.cm-s-neo .cm-tag {color:#9c3328} +.cm-s-neo .cm-string {color:#b35e14} +.cm-s-neo .cm-variable,.cm-s-neo .cm-qualifier {color:#047d65} + + +/* Editor styling */ + +.cm-s-neo pre { + padding:0; +} + +.cm-s-neo .CodeMirror-gutters { + border:none; + border-right:10px solid transparent; + background-color:transparent; +} + +.cm-s-neo .CodeMirror-linenumber { + padding:0; + color:#e0e2e5; +} + +.cm-s-neo .CodeMirror-guttermarker { color: #1d75b3; } +.cm-s-neo .CodeMirror-guttermarker-subtle { color: #e0e2e5; } + +.cm-s-neo div.CodeMirror-cursor { + width: auto; + border: 0; + background: rgba(155,157,162,0.37); + z-index: 1; +} diff --git a/Upload/admin/jscripts/codemirror/theme/night.css b/Upload/admin/jscripts/codemirror/theme/night.css new file mode 100644 index 0000000..a0bf8cf --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/night.css @@ -0,0 +1,26 @@ +/* Loosely based on the Midnight Textmate theme */ + +.cm-s-night.CodeMirror { background: #0a001f; color: #f8f8f8; } +.cm-s-night div.CodeMirror-selected { background: #447 !important; } +.cm-s-night .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; } +.cm-s-night .CodeMirror-guttermarker { color: white; } +.cm-s-night .CodeMirror-guttermarker-subtle { color: #bbb; } +.cm-s-night .CodeMirror-linenumber { color: #f8f8f8; } +.cm-s-night .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-night span.cm-comment { color: #6900a1; } +.cm-s-night span.cm-atom { color: #845dc4; } +.cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; } +.cm-s-night span.cm-keyword { color: #599eff; } +.cm-s-night span.cm-string { color: #37f14a; } +.cm-s-night span.cm-meta { color: #7678e2; } +.cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; } +.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; } +.cm-s-night span.cm-bracket { color: #8da6ce; } +.cm-s-night span.cm-comment { color: #6900a1; } +.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; } +.cm-s-night span.cm-link { color: #845dc4; } +.cm-s-night span.cm-error { color: #9d1e15; } + +.cm-s-night .CodeMirror-activeline-background {background: #1C005A !important;} +.cm-s-night .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/paraiso-dark.css b/Upload/admin/jscripts/codemirror/theme/paraiso-dark.css new file mode 100644 index 0000000..53dcdf7 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/paraiso-dark.css @@ -0,0 +1,36 @@ +/* + + Name: Paraíso (Dark) + Author: Jan T. Sott + + Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror) + Inspired by the art of Rubens LP (http://www.rubenslp.com.br) + +*/ + +.cm-s-paraiso-dark.CodeMirror {background: #2f1e2e; color: #b9b6b0;} +.cm-s-paraiso-dark div.CodeMirror-selected {background: #41323f !important;} +.cm-s-paraiso-dark .CodeMirror-gutters {background: #2f1e2e; border-right: 0px;} +.cm-s-paraiso-dark .CodeMirror-guttermarker { color: #ef6155; } +.cm-s-paraiso-dark .CodeMirror-guttermarker-subtle { color: #776e71; } +.cm-s-paraiso-dark .CodeMirror-linenumber {color: #776e71;} +.cm-s-paraiso-dark .CodeMirror-cursor {border-left: 1px solid #8d8687 !important;} + +.cm-s-paraiso-dark span.cm-comment {color: #e96ba8;} +.cm-s-paraiso-dark span.cm-atom {color: #815ba4;} +.cm-s-paraiso-dark span.cm-number {color: #815ba4;} + +.cm-s-paraiso-dark span.cm-property, .cm-s-paraiso-dark span.cm-attribute {color: #48b685;} +.cm-s-paraiso-dark span.cm-keyword {color: #ef6155;} +.cm-s-paraiso-dark span.cm-string {color: #fec418;} + +.cm-s-paraiso-dark span.cm-variable {color: #48b685;} +.cm-s-paraiso-dark span.cm-variable-2 {color: #06b6ef;} +.cm-s-paraiso-dark span.cm-def {color: #f99b15;} +.cm-s-paraiso-dark span.cm-bracket {color: #b9b6b0;} +.cm-s-paraiso-dark span.cm-tag {color: #ef6155;} +.cm-s-paraiso-dark span.cm-link {color: #815ba4;} +.cm-s-paraiso-dark span.cm-error {background: #ef6155; color: #8d8687;} + +.cm-s-paraiso-dark .CodeMirror-activeline-background {background: #4D344A !important;} +.cm-s-paraiso-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/paraiso-light.css b/Upload/admin/jscripts/codemirror/theme/paraiso-light.css new file mode 100644 index 0000000..07ca325 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/paraiso-light.css @@ -0,0 +1,36 @@ +/* + + Name: Paraíso (Light) + Author: Jan T. Sott + + Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror) + Inspired by the art of Rubens LP (http://www.rubenslp.com.br) + +*/ + +.cm-s-paraiso-light.CodeMirror {background: #e7e9db; color: #41323f;} +.cm-s-paraiso-light div.CodeMirror-selected {background: #b9b6b0 !important;} +.cm-s-paraiso-light .CodeMirror-gutters {background: #e7e9db; border-right: 0px;} +.cm-s-paraiso-light .CodeMirror-guttermarker { color: black; } +.cm-s-paraiso-light .CodeMirror-guttermarker-subtle { color: #8d8687; } +.cm-s-paraiso-light .CodeMirror-linenumber {color: #8d8687;} +.cm-s-paraiso-light .CodeMirror-cursor {border-left: 1px solid #776e71 !important;} + +.cm-s-paraiso-light span.cm-comment {color: #e96ba8;} +.cm-s-paraiso-light span.cm-atom {color: #815ba4;} +.cm-s-paraiso-light span.cm-number {color: #815ba4;} + +.cm-s-paraiso-light span.cm-property, .cm-s-paraiso-light span.cm-attribute {color: #48b685;} +.cm-s-paraiso-light span.cm-keyword {color: #ef6155;} +.cm-s-paraiso-light span.cm-string {color: #fec418;} + +.cm-s-paraiso-light span.cm-variable {color: #48b685;} +.cm-s-paraiso-light span.cm-variable-2 {color: #06b6ef;} +.cm-s-paraiso-light span.cm-def {color: #f99b15;} +.cm-s-paraiso-light span.cm-bracket {color: #41323f;} +.cm-s-paraiso-light span.cm-tag {color: #ef6155;} +.cm-s-paraiso-light span.cm-link {color: #815ba4;} +.cm-s-paraiso-light span.cm-error {background: #ef6155; color: #776e71;} + +.cm-s-paraiso-light .CodeMirror-activeline-background {background: #CFD1C4 !important;} +.cm-s-paraiso-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/pastel-on-dark.css b/Upload/admin/jscripts/codemirror/theme/pastel-on-dark.css new file mode 100644 index 0000000..7992ac7 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/pastel-on-dark.css @@ -0,0 +1,50 @@ +/** + * Pastel On Dark theme ported from ACE editor + * @license MIT + * @copyright AtomicPages LLC 2014 + * @author Dennis Thompson, AtomicPages LLC + * @version 1.1 + * @source https://github.com/atomicpages/codemirror-pastel-on-dark-theme + */ + +.cm-s-pastel-on-dark.CodeMirror { + background: #2c2827; + color: #8F938F; + line-height: 1.5; + font-size: 14px; +} +.cm-s-pastel-on-dark div.CodeMirror-selected { background: rgba(221,240,255,0.2) !important; } +.cm-s-pastel-on-dark .CodeMirror-gutters { + background: #34302f; + border-right: 0px; + padding: 0 3px; +} +.cm-s-pastel-on-dark .CodeMirror-guttermarker { color: white; } +.cm-s-pastel-on-dark .CodeMirror-guttermarker-subtle { color: #8F938F; } +.cm-s-pastel-on-dark .CodeMirror-linenumber { color: #8F938F; } +.cm-s-pastel-on-dark .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; } +.cm-s-pastel-on-dark span.cm-comment { color: #A6C6FF; } +.cm-s-pastel-on-dark span.cm-atom { color: #DE8E30; } +.cm-s-pastel-on-dark span.cm-number { color: #CCCCCC; } +.cm-s-pastel-on-dark span.cm-property { color: #8F938F; } +.cm-s-pastel-on-dark span.cm-attribute { color: #a6e22e; } +.cm-s-pastel-on-dark span.cm-keyword { color: #AEB2F8; } +.cm-s-pastel-on-dark span.cm-string { color: #66A968; } +.cm-s-pastel-on-dark span.cm-variable { color: #AEB2F8; } +.cm-s-pastel-on-dark span.cm-variable-2 { color: #BEBF55; } +.cm-s-pastel-on-dark span.cm-variable-3 { color: #DE8E30; } +.cm-s-pastel-on-dark span.cm-def { color: #757aD8; } +.cm-s-pastel-on-dark span.cm-bracket { color: #f8f8f2; } +.cm-s-pastel-on-dark span.cm-tag { color: #C1C144; } +.cm-s-pastel-on-dark span.cm-link { color: #ae81ff; } +.cm-s-pastel-on-dark span.cm-qualifier,.cm-s-pastel-on-dark span.cm-builtin { color: #C1C144; } +.cm-s-pastel-on-dark span.cm-error { + background: #757aD8; + color: #f8f8f0; +} +.cm-s-pastel-on-dark .CodeMirror-activeline-background { background: rgba(255, 255, 255, 0.031) !important; } +.cm-s-pastel-on-dark .CodeMirror-matchingbracket { + border: 1px solid rgba(255,255,255,0.25); + color: #8F938F !important; + margin: -1px -1px 0 -1px; +} diff --git a/Upload/admin/jscripts/codemirror/theme/rubyblue.css b/Upload/admin/jscripts/codemirror/theme/rubyblue.css new file mode 100644 index 0000000..5349838 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/rubyblue.css @@ -0,0 +1,23 @@ +.cm-s-rubyblue.CodeMirror { background: #112435; color: white; } +.cm-s-rubyblue div.CodeMirror-selected { background: #38566F !important; } +.cm-s-rubyblue .CodeMirror-gutters { background: #1F4661; border-right: 7px solid #3E7087; } +.cm-s-rubyblue .CodeMirror-guttermarker { color: white; } +.cm-s-rubyblue .CodeMirror-guttermarker-subtle { color: #3E7087; } +.cm-s-rubyblue .CodeMirror-linenumber { color: white; } +.cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; } +.cm-s-rubyblue span.cm-atom { color: #F4C20B; } +.cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; } +.cm-s-rubyblue span.cm-keyword { color: #F0F; } +.cm-s-rubyblue span.cm-string { color: #F08047; } +.cm-s-rubyblue span.cm-meta { color: #F0F; } +.cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; } +.cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def { color: white; } +.cm-s-rubyblue span.cm-bracket { color: #F0F; } +.cm-s-rubyblue span.cm-link { color: #F4C20B; } +.cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; } +.cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; } +.cm-s-rubyblue span.cm-error { color: #AF2018; } + +.cm-s-rubyblue .CodeMirror-activeline-background {background: #173047 !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/solarized.css b/Upload/admin/jscripts/codemirror/theme/solarized.css new file mode 100644 index 0000000..36d5f79 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/solarized.css @@ -0,0 +1,170 @@ +/* +Solarized theme for code-mirror +http://ethanschoonover.com/solarized +*/ + +/* +Solarized color pallet +http://ethanschoonover.com/solarized/img/solarized-palette.png +*/ + +.solarized.base03 { color: #002b36; } +.solarized.base02 { color: #073642; } +.solarized.base01 { color: #586e75; } +.solarized.base00 { color: #657b83; } +.solarized.base0 { color: #839496; } +.solarized.base1 { color: #93a1a1; } +.solarized.base2 { color: #eee8d5; } +.solarized.base3 { color: #fdf6e3; } +.solarized.solar-yellow { color: #b58900; } +.solarized.solar-orange { color: #cb4b16; } +.solarized.solar-red { color: #dc322f; } +.solarized.solar-magenta { color: #d33682; } +.solarized.solar-violet { color: #6c71c4; } +.solarized.solar-blue { color: #268bd2; } +.solarized.solar-cyan { color: #2aa198; } +.solarized.solar-green { color: #859900; } + +/* Color scheme for code-mirror */ + +.cm-s-solarized { + line-height: 1.45em; + color-profile: sRGB; + rendering-intent: auto; +} +.cm-s-solarized.cm-s-dark { + color: #839496; + background-color: #002b36; + text-shadow: #002b36 0 1px; +} +.cm-s-solarized.cm-s-light { + background-color: #fdf6e3; + color: #657b83; + text-shadow: #eee8d5 0 1px; +} + +.cm-s-solarized .CodeMirror-widget { + text-shadow: none; +} + + +.cm-s-solarized .cm-keyword { color: #cb4b16 } +.cm-s-solarized .cm-atom { color: #d33682; } +.cm-s-solarized .cm-number { color: #d33682; } +.cm-s-solarized .cm-def { color: #2aa198; } + +.cm-s-solarized .cm-variable { color: #268bd2; } +.cm-s-solarized .cm-variable-2 { color: #b58900; } +.cm-s-solarized .cm-variable-3 { color: #6c71c4; } + +.cm-s-solarized .cm-property { color: #2aa198; } +.cm-s-solarized .cm-operator {color: #6c71c4;} + +.cm-s-solarized .cm-comment { color: #586e75; font-style:italic; } + +.cm-s-solarized .cm-string { color: #859900; } +.cm-s-solarized .cm-string-2 { color: #b58900; } + +.cm-s-solarized .cm-meta { color: #859900; } +.cm-s-solarized .cm-qualifier { color: #b58900; } +.cm-s-solarized .cm-builtin { color: #d33682; } +.cm-s-solarized .cm-bracket { color: #cb4b16; } +.cm-s-solarized .CodeMirror-matchingbracket { color: #859900; } +.cm-s-solarized .CodeMirror-nonmatchingbracket { color: #dc322f; } +.cm-s-solarized .cm-tag { color: #93a1a1 } +.cm-s-solarized .cm-attribute { color: #2aa198; } +.cm-s-solarized .cm-header { color: #586e75; } +.cm-s-solarized .cm-quote { color: #93a1a1; } +.cm-s-solarized .cm-hr { + color: transparent; + border-top: 1px solid #586e75; + display: block; +} +.cm-s-solarized .cm-link { color: #93a1a1; cursor: pointer; } +.cm-s-solarized .cm-special { color: #6c71c4; } +.cm-s-solarized .cm-em { + color: #999; + text-decoration: underline; + text-decoration-style: dotted; +} +.cm-s-solarized .cm-strong { color: #eee; } +.cm-s-solarized .cm-tab:before { + content: "➤"; /*visualize tab character*/ + color: #586e75; + position:absolute; +} +.cm-s-solarized .cm-error, +.cm-s-solarized .cm-invalidchar { + color: #586e75; + border-bottom: 1px dotted #dc322f; +} + +.cm-s-solarized.cm-s-dark .CodeMirror-selected { + background: #073642; +} + +.cm-s-solarized.cm-s-light .CodeMirror-selected { + background: #eee8d5; +} + +/* Editor styling */ + + + +/* Little shadow on the view-port of the buffer view */ +.cm-s-solarized.CodeMirror { + -moz-box-shadow: inset 7px 0 12px -6px #000; + -webkit-box-shadow: inset 7px 0 12px -6px #000; + box-shadow: inset 7px 0 12px -6px #000; +} + +/* Gutter border and some shadow from it */ +.cm-s-solarized .CodeMirror-gutters { + border-right: 1px solid; +} + +/* Gutter colors and line number styling based of color scheme (dark / light) */ + +/* Dark */ +.cm-s-solarized.cm-s-dark .CodeMirror-gutters { + background-color: #002b36; + border-color: #00232c; +} + +.cm-s-solarized.cm-s-dark .CodeMirror-linenumber { + text-shadow: #021014 0 -1px; +} + +/* Light */ +.cm-s-solarized.cm-s-light .CodeMirror-gutters { + background-color: #fdf6e3; + border-color: #eee8d5; +} + +/* Common */ +.cm-s-solarized .CodeMirror-linenumber { + color: #586e75; + padding: 0 5px; +} +.cm-s-solarized .CodeMirror-guttermarker-subtle { color: #586e75; } +.cm-s-solarized.cm-s-dark .CodeMirror-guttermarker { color: #ddd; } +.cm-s-solarized.cm-s-light .CodeMirror-guttermarker { color: #cb4b16; } + +.cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text { + color: #586e75; +} + +.cm-s-solarized .CodeMirror-lines .CodeMirror-cursor { + border-left: 1px solid #819090; +} + +/* +Active line. Negative margin compensates left padding of the text in the +view-port +*/ +.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background { + background: rgba(255, 255, 255, 0.10); +} +.cm-s-solarized.cm-s-light .CodeMirror-activeline-background { + background: rgba(0, 0, 0, 0.10); +} diff --git a/Upload/admin/jscripts/codemirror/theme/the-matrix.css b/Upload/admin/jscripts/codemirror/theme/the-matrix.css new file mode 100644 index 0000000..01474ca --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/the-matrix.css @@ -0,0 +1,28 @@ +.cm-s-the-matrix.CodeMirror { background: #000000; color: #00FF00; } +.cm-s-the-matrix div.CodeMirror-selected { background: #2D2D2D !important; } +.cm-s-the-matrix .CodeMirror-gutters { background: #060; border-right: 2px solid #00FF00; } +.cm-s-the-matrix .CodeMirror-guttermarker { color: #0f0; } +.cm-s-the-matrix .CodeMirror-guttermarker-subtle { color: white; } +.cm-s-the-matrix .CodeMirror-linenumber { color: #FFFFFF; } +.cm-s-the-matrix .CodeMirror-cursor { border-left: 1px solid #00FF00 !important; } + +.cm-s-the-matrix span.cm-keyword {color: #008803; font-weight: bold;} +.cm-s-the-matrix span.cm-atom {color: #3FF;} +.cm-s-the-matrix span.cm-number {color: #FFB94F;} +.cm-s-the-matrix span.cm-def {color: #99C;} +.cm-s-the-matrix span.cm-variable {color: #F6C;} +.cm-s-the-matrix span.cm-variable-2 {color: #C6F;} +.cm-s-the-matrix span.cm-variable-3 {color: #96F;} +.cm-s-the-matrix span.cm-property {color: #62FFA0;} +.cm-s-the-matrix span.cm-operator {color: #999} +.cm-s-the-matrix span.cm-comment {color: #CCCCCC;} +.cm-s-the-matrix span.cm-string {color: #39C;} +.cm-s-the-matrix span.cm-meta {color: #C9F;} +.cm-s-the-matrix span.cm-qualifier {color: #FFF700;} +.cm-s-the-matrix span.cm-builtin {color: #30a;} +.cm-s-the-matrix span.cm-bracket {color: #cc7;} +.cm-s-the-matrix span.cm-tag {color: #FFBD40;} +.cm-s-the-matrix span.cm-attribute {color: #FFF700;} +.cm-s-the-matrix span.cm-error {color: #FF0000;} + +.cm-s-the-matrix .CodeMirror-activeline-background {background: #040;} diff --git a/Upload/admin/jscripts/codemirror/theme/tomorrow-night-eighties.css b/Upload/admin/jscripts/codemirror/theme/tomorrow-night-eighties.css new file mode 100644 index 0000000..8414135 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/tomorrow-night-eighties.css @@ -0,0 +1,36 @@ +/* + + Name: Tomorrow Night - Eighties + Author: Chris Kempson + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-tomorrow-night-eighties.CodeMirror {background: #000000; color: #CCCCCC;} +.cm-s-tomorrow-night-eighties div.CodeMirror-selected {background: #2D2D2D !important;} +.cm-s-tomorrow-night-eighties .CodeMirror-gutters {background: #000000; border-right: 0px;} +.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker { color: #f2777a; } +.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker-subtle { color: #777; } +.cm-s-tomorrow-night-eighties .CodeMirror-linenumber {color: #515151;} +.cm-s-tomorrow-night-eighties .CodeMirror-cursor {border-left: 1px solid #6A6A6A !important;} + +.cm-s-tomorrow-night-eighties span.cm-comment {color: #d27b53;} +.cm-s-tomorrow-night-eighties span.cm-atom {color: #a16a94;} +.cm-s-tomorrow-night-eighties span.cm-number {color: #a16a94;} + +.cm-s-tomorrow-night-eighties span.cm-property, .cm-s-tomorrow-night-eighties span.cm-attribute {color: #99cc99;} +.cm-s-tomorrow-night-eighties span.cm-keyword {color: #f2777a;} +.cm-s-tomorrow-night-eighties span.cm-string {color: #ffcc66;} + +.cm-s-tomorrow-night-eighties span.cm-variable {color: #99cc99;} +.cm-s-tomorrow-night-eighties span.cm-variable-2 {color: #6699cc;} +.cm-s-tomorrow-night-eighties span.cm-def {color: #f99157;} +.cm-s-tomorrow-night-eighties span.cm-bracket {color: #CCCCCC;} +.cm-s-tomorrow-night-eighties span.cm-tag {color: #f2777a;} +.cm-s-tomorrow-night-eighties span.cm-link {color: #a16a94;} +.cm-s-tomorrow-night-eighties span.cm-error {background: #f2777a; color: #6A6A6A;} + +.cm-s-tomorrow-night-eighties .CodeMirror-activeline-background {background: #343600 !important;} +.cm-s-tomorrow-night-eighties .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/twilight.css b/Upload/admin/jscripts/codemirror/theme/twilight.css new file mode 100644 index 0000000..9ca5057 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/twilight.css @@ -0,0 +1,30 @@ +.cm-s-twilight.CodeMirror { background: #141414; color: #f7f7f7; } /**/ +.cm-s-twilight .CodeMirror-selected { background: #323232 !important; } /**/ + +.cm-s-twilight .CodeMirror-gutters { background: #222; border-right: 1px solid #aaa; } +.cm-s-twilight .CodeMirror-guttermarker { color: white; } +.cm-s-twilight .CodeMirror-guttermarker-subtle { color: #aaa; } +.cm-s-twilight .CodeMirror-linenumber { color: #aaa; } +.cm-s-twilight .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-twilight .cm-keyword { color: #f9ee98; } /**/ +.cm-s-twilight .cm-atom { color: #FC0; } +.cm-s-twilight .cm-number { color: #ca7841; } /**/ +.cm-s-twilight .cm-def { color: #8DA6CE; } +.cm-s-twilight span.cm-variable-2, .cm-s-twilight span.cm-tag { color: #607392; } /**/ +.cm-s-twilight span.cm-variable-3, .cm-s-twilight span.cm-def { color: #607392; } /**/ +.cm-s-twilight .cm-operator { color: #cda869; } /**/ +.cm-s-twilight .cm-comment { color:#777; font-style:italic; font-weight:normal; } /**/ +.cm-s-twilight .cm-string { color:#8f9d6a; font-style:italic; } /**/ +.cm-s-twilight .cm-string-2 { color:#bd6b18 } /*?*/ +.cm-s-twilight .cm-meta { background-color:#141414; color:#f7f7f7; } /*?*/ +.cm-s-twilight .cm-builtin { color: #cda869; } /*?*/ +.cm-s-twilight .cm-tag { color: #997643; } /**/ +.cm-s-twilight .cm-attribute { color: #d6bb6d; } /*?*/ +.cm-s-twilight .cm-header { color: #FF6400; } +.cm-s-twilight .cm-hr { color: #AEAEAE; } +.cm-s-twilight .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } /**/ +.cm-s-twilight .cm-error { border-bottom: 1px solid red; } + +.cm-s-twilight .CodeMirror-activeline-background {background: #27282E !important;} +.cm-s-twilight .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/vibrant-ink.css b/Upload/admin/jscripts/codemirror/theme/vibrant-ink.css new file mode 100644 index 0000000..5177282 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/vibrant-ink.css @@ -0,0 +1,32 @@ +/* Taken from the popular Visual Studio Vibrant Ink Schema */ + +.cm-s-vibrant-ink.CodeMirror { background: black; color: white; } +.cm-s-vibrant-ink .CodeMirror-selected { background: #35493c !important; } + +.cm-s-vibrant-ink .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; } +.cm-s-vibrant-ink .CodeMirror-guttermarker { color: white; } +.cm-s-vibrant-ink .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-vibrant-ink .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-vibrant-ink .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-vibrant-ink .cm-keyword { color: #CC7832; } +.cm-s-vibrant-ink .cm-atom { color: #FC0; } +.cm-s-vibrant-ink .cm-number { color: #FFEE98; } +.cm-s-vibrant-ink .cm-def { color: #8DA6CE; } +.cm-s-vibrant-ink span.cm-variable-2, .cm-s-vibrant span.cm-tag { color: #FFC66D } +.cm-s-vibrant-ink span.cm-variable-3, .cm-s-vibrant span.cm-def { color: #FFC66D } +.cm-s-vibrant-ink .cm-operator { color: #888; } +.cm-s-vibrant-ink .cm-comment { color: gray; font-weight: bold; } +.cm-s-vibrant-ink .cm-string { color: #A5C25C } +.cm-s-vibrant-ink .cm-string-2 { color: red } +.cm-s-vibrant-ink .cm-meta { color: #D8FA3C; } +.cm-s-vibrant-ink .cm-builtin { color: #8DA6CE; } +.cm-s-vibrant-ink .cm-tag { color: #8DA6CE; } +.cm-s-vibrant-ink .cm-attribute { color: #8DA6CE; } +.cm-s-vibrant-ink .cm-header { color: #FF6400; } +.cm-s-vibrant-ink .cm-hr { color: #AEAEAE; } +.cm-s-vibrant-ink .cm-link { color: blue; } +.cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; } + +.cm-s-vibrant-ink .CodeMirror-activeline-background {background: #27282E !important;} +.cm-s-vibrant-ink .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;} diff --git a/Upload/admin/jscripts/codemirror/theme/xq-dark.css b/Upload/admin/jscripts/codemirror/theme/xq-dark.css new file mode 100644 index 0000000..116eccf --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/xq-dark.css @@ -0,0 +1,51 @@ +/* +Copyright (C) 2011 by MarkLogic Corporation +Author: Mike Brevoort + +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. +*/ +.cm-s-xq-dark.CodeMirror { background: #0a001f; color: #f8f8f8; } +.cm-s-xq-dark .CodeMirror-selected { background: #27007A !important; } +.cm-s-xq-dark .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; } +.cm-s-xq-dark .CodeMirror-guttermarker { color: #FFBD40; } +.cm-s-xq-dark .CodeMirror-guttermarker-subtle { color: #f8f8f8; } +.cm-s-xq-dark .CodeMirror-linenumber { color: #f8f8f8; } +.cm-s-xq-dark .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-xq-dark span.cm-keyword {color: #FFBD40;} +.cm-s-xq-dark span.cm-atom {color: #6C8CD5;} +.cm-s-xq-dark span.cm-number {color: #164;} +.cm-s-xq-dark span.cm-def {color: #FFF; text-decoration:underline;} +.cm-s-xq-dark span.cm-variable {color: #FFF;} +.cm-s-xq-dark span.cm-variable-2 {color: #EEE;} +.cm-s-xq-dark span.cm-variable-3 {color: #DDD;} +.cm-s-xq-dark span.cm-property {} +.cm-s-xq-dark span.cm-operator {} +.cm-s-xq-dark span.cm-comment {color: gray;} +.cm-s-xq-dark span.cm-string {color: #9FEE00;} +.cm-s-xq-dark span.cm-meta {color: yellow;} +.cm-s-xq-dark span.cm-qualifier {color: #FFF700;} +.cm-s-xq-dark span.cm-builtin {color: #30a;} +.cm-s-xq-dark span.cm-bracket {color: #cc7;} +.cm-s-xq-dark span.cm-tag {color: #FFBD40;} +.cm-s-xq-dark span.cm-attribute {color: #FFF700;} +.cm-s-xq-dark span.cm-error {color: #f00;} + +.cm-s-xq-dark .CodeMirror-activeline-background {background: #27282E !important;} +.cm-s-xq-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;} \ No newline at end of file diff --git a/Upload/admin/jscripts/codemirror/theme/xq-light.css b/Upload/admin/jscripts/codemirror/theme/xq-light.css new file mode 100644 index 0000000..20b5c79 --- /dev/null +++ b/Upload/admin/jscripts/codemirror/theme/xq-light.css @@ -0,0 +1,43 @@ +/* +Copyright (C) 2011 by MarkLogic Corporation +Author: Mike Brevoort + +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. +*/ +.cm-s-xq-light span.cm-keyword {line-height: 1em; font-weight: bold; color: #5A5CAD; } +.cm-s-xq-light span.cm-atom {color: #6C8CD5;} +.cm-s-xq-light span.cm-number {color: #164;} +.cm-s-xq-light span.cm-def {text-decoration:underline;} +.cm-s-xq-light span.cm-variable {color: black; } +.cm-s-xq-light span.cm-variable-2 {color:black;} +.cm-s-xq-light span.cm-variable-3 {color: black; } +.cm-s-xq-light span.cm-property {} +.cm-s-xq-light span.cm-operator {} +.cm-s-xq-light span.cm-comment {color: #0080FF; font-style: italic;} +.cm-s-xq-light span.cm-string {color: red;} +.cm-s-xq-light span.cm-meta {color: yellow;} +.cm-s-xq-light span.cm-qualifier {color: grey} +.cm-s-xq-light span.cm-builtin {color: #7EA656;} +.cm-s-xq-light span.cm-bracket {color: #cc7;} +.cm-s-xq-light span.cm-tag {color: #3F7F7F;} +.cm-s-xq-light span.cm-attribute {color: #7F007F;} +.cm-s-xq-light span.cm-error {color: #f00;} + +.cm-s-xq-light .CodeMirror-activeline-background {background: #e8f2ff !important;} +.cm-s-xq-light .CodeMirror-matchingbracket {outline:1px solid grey;color:black !important;background:yellow;} \ No newline at end of file diff --git a/Upload/admin/jscripts/index.html b/Upload/admin/jscripts/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/jscripts/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/animated-overlay.gif b/Upload/admin/jscripts/jqueryui/css/redmond/images/animated-overlay.gif new file mode 100644 index 0000000000000000000000000000000000000000..d441f75ebfbdf26a265dfccd670120d25c0a341c GIT binary patch literal 1738 zcmZ|OX;ji_6b5ixNYt8>l?gOuO)6lU%W(mxn(`>1S(XO;u`D+P%xqBvMr|w-Vyr1s z7R|Cn0b8|Hu<=Zmv1mFqh9Fj!NuZfKB2MP$e75`XJ@>=!y!Ux9xR3x;EW!q1^V>X| znVFuRUN`NqJ2)ybXh%e__h!!pv(M|S3+?9F%(K}zyE40MGyhWF5-IDgL&=%2-9`Nk z!1@8uk4t%_{(K~>N;sK&dzJbwJ=$kYTlL=$%#0Pfh>U{%i@~wWbvYsD_K-D`&+u1( z#Ma`>%q<^UhzGvi(hyE`zCD{-=2|zL5>wnB=DE!U?(CZG%q4@lDnCq_%&3DCla#(X zmBhDD+RN$aMWWHm?ig*>1Onn6~r?Ma~N2JKAxN>H%UtRyRqS)6Um!-Tz%-r=& zQmTb^JFIe3W^-kAm`}`2P|niMh>RYyd)S^f(dbrx965?rzbhP|XeP}o&&DSZ4|oYQ z)I{f!SfycYw?3=9W;o-B%U5xs(pP267X~9-7L|4WzaYexC0GtG8wWygm63rF{llCEraxzkc=IxvFQ-y37=_;e5 zJLq^gsSO0Ayz?a>E_?{dmUc+t#qv$)XN8$<<}rQ#)lsiw+pmL&J>~+hgpo>i$m+;l zZIa_ZRIfSeT$~v5d`EBV&*k`apPgjv&B|+d`Q!nyu{L4rs%ZfoF0*Kq8I%ByOcFpL zK=>wzofZo<+0GZLCnWM3oQ^pb(gRSf02;~cEn@LJ>~XB9IkEX{$N#Z`m%>S!U{uPx zloI%bLdo$Adxlh(Uv^yX7s5G&C zLwNRG>~T?G{kzupp8EcyLGPoPf)@&9Wqfw_l&uU-6cexk%5;uQg%wb=0k_733{i#& z1a2p)gV3S2+QG1-K9tZ}E~I<(P0r2aFFY-c{o?TUOz3Xjod#TLE2A_c?*T7t z=1>~%YW450{Qqno4t`}gvLnuMrcu8+#xEBoY%2_+Mb#Z6S38+r*M4O`-+!zl(@m`D zQsi|GA2l3gEy}LFe<#Hv8?$_L#u8E|3-bP$*La*E>B{X!Sy4i6?TKam!49aXCAW4S*P_O^H4^*DpiA40o}Uqw~Eo&veh1`|8i zD2$x+>_b^bXE4N;AW=5>iYak2%!JAh0j1*k1{p#iRCjbB7!cSws~U{1IA@acLII$t z$>X#A+^s6iJ5~DFG!xa?>z{=lxtdi1rzbM-(nqAu3D8h-&64xo6|E!p?pK0xT;qoK z`6%+SpBk+~M?nO}>2mTw!A{yZ6O>Z@kwSd4;8aWU5z!P~tQl?u==^+R`{OmOS}oZh zOXQ3{6kuz?Is^n^L7;9ieB9C+8B{>t+pDrlq4xGDDn#T#3T5$l1g`FTQkU;b-981j zNm{zC`$wn7etklM#qHI4=3m5gwa6DNS{?Z!vSObi_od{4eUo=_S2BKNpkSdiqe(k9WtkeM79;2-%CFbb)aB=&H1?i1}uwFzoZQ(38Kn1zBP ORn*B%u*Wk|4g3!*Rv{Mv literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png b/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100644 index 0000000000000000000000000000000000000000..9aab30b1cca5c7cf780abc58c6c140475ffdc27c GIT binary patch literal 212 zcmeAS@N?(olHy`uVBq!ia0vp^8bF-F1SA+{?>A)!QcOwS?k)_>#w|r1Kptm-M`SUO z_5fqIli7AahM1>|V~EA+ zRdP`(kYX@0Ff`FMFw-?M3o$gZGBCF?Fwg~)87o%FqiD#@PsvQH#H~T{tI%Sg1_n=8 KKbLh*2~7Zh>N6w& literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_flat_55_fbec88_40x100.png b/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_flat_55_fbec88_40x100.png new file mode 100644 index 0000000000000000000000000000000000000000..f084cb4c04dac79b48416656b5450b8d5102afdb GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^8bF-F$P6UUt$JVyq?iMILR^2p>EL%3lLT@(3p^r= zfwTu0yPeFo12XtMT^vI+&L<~Gur6-+#lXN6!N6E*)>aObQY~?fC`m~yNwrEYN(E93 zMh1o^x&~&tMrI*~Mpg#qR)!Y3K+?cq`r9YZP&DM`r(~v8;@0qNLrfG<1B0ilpUXO@ GgeCw>2Q%OR literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png b/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..7b68dca7659bcbf99920653c1b46295ed35c1a78 GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^j6gI&fCnc6a#?2AmP!?*K(O3p^r= zfwTu0yPeFo12XzNT^vI^j=w#>kdKj3=J?0=@27v6%;IVMUg1JcliIElxdYl6axRlf zzjoc!(_FUE@@3iW-UpIBAN=Qk@QpurwKhJKtwDjK>A`E8?p60quDJ!5u2r;lD_g}Z zoV~Vb=3H*wH!=D_yF(V8(VMzqOVPpQnp?N;GJIZCld^S(TIzDS*}~dvVf|)n|IgrS zQura8|6q%H3BUHj1fa`QOI#yLQW8s2t&)pUffR$0fuV`6ftjw6S%{&Lm4UgHv4Jj- lG%$FkzV;7_hTQy=%(P0}8m3o?Isi2=c)I$ztaD0e0su4HcsKw6 literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_glass_85_dfeffc_1x400.png b/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_glass_85_dfeffc_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..0782cd63e68cb6c92dc2e5cb2e9869bffc7fb7b5 GIT binary patch literal 341 zcmeAS@N?(olHy`uVBq!ia0vp^j6gI&fCnc6a#?2AmP!?*K(O3p^r= zfwTu0yPeFo12QIix;Tb-9DjR7k?RnHg!{+uf13{~G&Ln=`oO=hJOs{);)V=83A}=O}g86Gs>w%OA6 z;^IdBdxdlMKWE!C8<`)MX5lF!N|bSMAyJf*T^iy(8$Wb p+{ysR1(F7Hp7-&fXvob^$xN%nt>Nu1vkgEE44$rjF6*2Ung9TWfK&hg literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_glass_95_fef1ec_1x400.png b/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_glass_95_fef1ec_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..83e61bc8a5591a7c3aa0a0c3677f49f42f8b792a GIT binary patch literal 332 zcmeAS@N?(olHy`uVBq!ia0vp^j6gI&fCnc6a#?2AmP!?*K(O3p^r= zfwTu0yPeFo12VciT^vI^j=w#>k(V)1qW$CZ|6)SVV-&*#dav<$DMuV&n0Dbpw@aw-vwNQVtg dC>nC}Q!>*kacj_!r-}imi^X%V#_WtcB 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 literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png b/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..4d338835f7228a291a6571c9b7d50eaf631c321d GIT binary patch literal 333 zcmeAS@N?(olHy`uVBq!ia0vp^j6j?szyu^`+!HJTQfx`y?k@kqfHUIz9iRwjfk$L9 zkoEv$x0Bg+Kt{Kxi(`n!`M2j4`56l(4m`ZSxACmnjSLe{^HyJjlgq5X-V)u{l&{P^ z%X3lxf?F&H&)xl9f8RLXagT!SPsP(+PN57B&g*}8mubDFWrn7*V&b_OH4DENDDH2Y zS*mhNaPyKKGj9m`>V8!FwPo{q&gl2Q=6(3kyMM#f`KJ`iKKRe%nw;SfpAoP;tTVUt zC)4+QGus1}jz56TQY~?fC`m~yNwrEYN(E93Mh1o^x&~&tMrI*~Mpg#qR)!Y3K+?cq i`r9YZP&DM`r(~v8;@0qNLrfG<1B0ilpUXO@geCxZynI~% literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png b/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..9649e3619c3aa7a04de3aeb604c0c2018324652d GIT binary patch literal 292 zcmeAS@N?(olHy`uVBq!ia0vp^j6j?szyu^`+!HJTQfx`y?k@kqfHUIz9iRwjfk$L9 zkoEv$x0Bg+Kt__Mi(`n!`M2i{xf%>aST3IIN|@;7+RWLZpi%Yz_RphE9=S6Qy%J^S zK3zIf{wT%f0?k z5vUk)i_@% literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_217bc0_256x240.png b/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_217bc0_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..8d2b7e57044465bac0008ff88d23cdebeab6a8b8 GIT binary patch literal 4549 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 E19GBNuK)l5 literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_2e83ff_256x240.png b/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..84b601bf0f726bf95801da487deaf2344a32e4b8 GIT binary patch literal 4549 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 F{{S81aohj^ literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_469bdd_256x240.png b/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_469bdd_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..5dff3f962cd744033b2aef575491451a8b2ce6a8 GIT binary patch literal 4549 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 F{{RRLc7^}| literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_6da8d5_256x240.png b/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_6da8d5_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..f7809f8566cd0aaef9af00e7caeca9d3720cf1b0 GIT binary patch literal 4549 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 DTfr$v literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_d8e7f3_256x240.png b/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_d8e7f3_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..9b46228fb1e80406b2a9a65b694e5674494c2775 GIT binary patch literal 4549 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 DwY1D= literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_f9bd01_256x240.png b/Upload/admin/jscripts/jqueryui/css/redmond/images/ui-icons_f9bd01_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..f1f0531ad5b02b7f891d84a6b6db6ce7290b65de GIT binary patch literal 4549 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 D=xKF{ literal 0 HcmV?d00001 diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/jquery-ui.min.css b/Upload/admin/jscripts/jqueryui/css/redmond/jquery-ui.min.css new file mode 100644 index 0000000..46c5e6d --- /dev/null +++ b/Upload/admin/jscripts/jqueryui/css/redmond/jquery-ui.min.css @@ -0,0 +1,7 @@ +/*! jQuery UI - v1.11.0 - 2014-07-18 +* http://jqueryui.com +* Includes: core.css, draggable.css, sortable.css, theme.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande%2CLucida%20Sans%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=5px&bgColorHeader=5c9ccc&bgTextureHeader=gloss_wave&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=inset_hard&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=glass&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=inset_hard&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=flat&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px +* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ + +.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-widget{font-family:Lucida Grande,Lucida Sans,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Lucida Grande,Lucida Sans,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #a6c9e2;background:#fcfdfd url("images/ui-bg_inset-hard_100_fcfdfd_1x100.png") 50% bottom repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #4297d7;background:#5c9ccc url("images/ui-bg_gloss-wave_55_5c9ccc_500x100.png") 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #c5dbec;background:#dfeffc url("images/ui-bg_glass_85_dfeffc_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#2e6e9e}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#2e6e9e;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #79b7e7;background:#d0e5f5 url("images/ui-bg_glass_75_d0e5f5_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#1d5987}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#1d5987;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #79b7e7;background:#f5f8f9 url("images/ui-bg_inset-hard_100_f5f8f9_1x100.png") 50% 50% repeat-x;font-weight:bold;color:#e17009}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#e17009;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fad42e;background:#fbec88 url("images/ui-bg_flat_55_fbec88_40x100.png") 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_469bdd_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_d8e7f3_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_6da8d5_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_217bc0_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_f9bd01_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_2e83ff_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cd0a0a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:5px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:5px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:5px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:5px}.ui-widget-overlay{background:#aaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px} \ No newline at end of file diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/jquery-ui.structure.min.css b/Upload/admin/jscripts/jqueryui/css/redmond/jquery-ui.structure.min.css new file mode 100644 index 0000000..fe94b63 --- /dev/null +++ b/Upload/admin/jscripts/jqueryui/css/redmond/jquery-ui.structure.min.css @@ -0,0 +1,5 @@ +/*! jQuery UI - v1.11.0 - 2014-07-18 +* http://jqueryui.com +* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ + +.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-sortable-handle{-ms-touch-action:none;touch-action:none} \ No newline at end of file diff --git a/Upload/admin/jscripts/jqueryui/css/redmond/jquery-ui.theme.min.css b/Upload/admin/jscripts/jqueryui/css/redmond/jquery-ui.theme.min.css new file mode 100644 index 0000000..9e95321 --- /dev/null +++ b/Upload/admin/jscripts/jqueryui/css/redmond/jquery-ui.theme.min.css @@ -0,0 +1,5 @@ +/*! jQuery UI - v1.11.0 - 2014-07-18 +* http://jqueryui.com +* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ + +.ui-widget{font-family:Lucida Grande,Lucida Sans,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Lucida Grande,Lucida Sans,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #a6c9e2;background:#fcfdfd url("images/ui-bg_inset-hard_100_fcfdfd_1x100.png") 50% bottom repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #4297d7;background:#5c9ccc url("images/ui-bg_gloss-wave_55_5c9ccc_500x100.png") 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #c5dbec;background:#dfeffc url("images/ui-bg_glass_85_dfeffc_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#2e6e9e}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#2e6e9e;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #79b7e7;background:#d0e5f5 url("images/ui-bg_glass_75_d0e5f5_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#1d5987}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#1d5987;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #79b7e7;background:#f5f8f9 url("images/ui-bg_inset-hard_100_f5f8f9_1x100.png") 50% 50% repeat-x;font-weight:bold;color:#e17009}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#e17009;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fad42e;background:#fbec88 url("images/ui-bg_flat_55_fbec88_40x100.png") 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_469bdd_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_d8e7f3_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_6da8d5_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_217bc0_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_f9bd01_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_2e83ff_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cd0a0a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:5px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:5px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:5px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:5px}.ui-widget-overlay{background:#aaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px} \ No newline at end of file diff --git a/Upload/admin/jscripts/jqueryui/js/jquery-ui.min.js b/Upload/admin/jscripts/jqueryui/js/jquery-ui.min.js new file mode 100644 index 0000000..b528a13 --- /dev/null +++ b/Upload/admin/jscripts/jqueryui/js/jquery-ui.min.js @@ -0,0 +1,7 @@ +/*! jQuery UI - v1.11.0 - 2014-07-18 +* http://jqueryui.com +* Includes: core.js, widget.js, mouse.js, draggable.js, droppable.js, sortable.js +* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ + +(function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e(jQuery)})(function(e){function t(t,s){var a,n,o,r=t.nodeName.toLowerCase();return"area"===r?(a=t.parentNode,n=a.name,t.href&&n&&"map"===a.nodeName.toLowerCase()?(o=e("img[usemap=#"+n+"]")[0],!!o&&i(o)):!1):(/input|select|textarea|button|object/.test(r)?!t.disabled:"a"===r?t.href||s:s)&&i(t)}function i(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}e.ui=e.ui||{},e.extend(e.ui,{version:"1.11.0",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({scrollParent:function(){var t=this.css("position"),i="absolute"===t,s=this.parents().filter(function(){var t=e(this);return i&&"static"===t.css("position")?!1:/(auto|scroll)/.test(t.css("overflow")+t.css("overflow-y")+t.css("overflow-x"))}).eq(0);return"fixed"!==t&&s.length?s:e(this[0].ownerDocument||document)},uniqueId:function(){var e=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++e)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(i){return t(i,!isNaN(e.attr(i,"tabindex")))},tabbable:function(i){var s=e.attr(i,"tabindex"),a=isNaN(s);return(a||s>=0)&&t(i,!a)}}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(t,i){function s(t,i,s,n){return e.each(a,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),n&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var a="Width"===i?["Left","Right"]:["Top","Bottom"],n=i.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+i]=function(t){return void 0===t?o["inner"+i].call(this):this.each(function(){e(this).css(n,s(this,t)+"px")})},e.fn["outer"+i]=function(t,a){return"number"!=typeof t?o["outer"+i].call(this,t):this.each(function(){e(this).css(n,s(this,t,!0,a)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),disableSelection:function(){var e="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.bind(e+".ui-disableSelection",function(e){e.preventDefault()})}}(),enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(t){if(void 0!==t)return this.css("zIndex",t);if(this.length)for(var i,s,a=e(this[0]);a.length&&a[0]!==document;){if(i=a.css("position"),("absolute"===i||"relative"===i||"fixed"===i)&&(s=parseInt(a.css("zIndex"),10),!isNaN(s)&&0!==s))return s;a=a.parent()}return 0}}),e.ui.plugin={add:function(t,i,s){var a,n=e.ui[t].prototype;for(a in s)n.plugins[a]=n.plugins[a]||[],n.plugins[a].push([i,s[a]])},call:function(e,t,i,s){var a,n=e.plugins[t];if(n&&(s||e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType))for(a=0;n.length>a;a++)e.options[n[a][0]]&&n[a][1].apply(e.element,i)}};var s=0,a=Array.prototype.slice;e.cleanData=function(t){return function(i){for(var s,a=0;null!=(s=i[a]);a++)try{e(s).triggerHandler("remove")}catch(n){}t(i)}}(e.cleanData),e.widget=function(t,i,s){var a,n,o,r,h={},l=t.split(".")[0];return t=t.split(".")[1],a=l+"-"+t,s||(s=i,i=e.Widget),e.expr[":"][a.toLowerCase()]=function(t){return!!e.data(t,a)},e[l]=e[l]||{},n=e[l][t],o=e[l][t]=function(e,t){return this._createWidget?(arguments.length&&this._createWidget(e,t),void 0):new o(e,t)},e.extend(o,n,{version:s.version,_proto:e.extend({},s),_childConstructors:[]}),r=new i,r.options=e.widget.extend({},r.options),e.each(s,function(t,s){return e.isFunction(s)?(h[t]=function(){var e=function(){return i.prototype[t].apply(this,arguments)},a=function(e){return i.prototype[t].apply(this,e)};return function(){var t,i=this._super,n=this._superApply;return this._super=e,this._superApply=a,t=s.apply(this,arguments),this._super=i,this._superApply=n,t}}(),void 0):(h[t]=s,void 0)}),o.prototype=e.widget.extend(r,{widgetEventPrefix:n?r.widgetEventPrefix||t:t},h,{constructor:o,namespace:l,widgetName:t,widgetFullName:a}),n?(e.each(n._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete n._childConstructors):i._childConstructors.push(o),e.widget.bridge(t,o),o},e.widget.extend=function(t){for(var i,s,n=a.call(arguments,1),o=0,r=n.length;r>o;o++)for(i in n[o])s=n[o][i],n[o].hasOwnProperty(i)&&void 0!==s&&(t[i]=e.isPlainObject(s)?e.isPlainObject(t[i])?e.widget.extend({},t[i],s):e.widget.extend({},s):s);return t},e.widget.bridge=function(t,i){var s=i.prototype.widgetFullName||t;e.fn[t]=function(n){var o="string"==typeof n,r=a.call(arguments,1),h=this;return n=!o&&r.length?e.widget.extend.apply(null,[n].concat(r)):n,o?this.each(function(){var i,a=e.data(this,s);return"instance"===n?(h=a,!1):a?e.isFunction(a[n])&&"_"!==n.charAt(0)?(i=a[n].apply(a,r),i!==a&&void 0!==i?(h=i&&i.jquery?h.pushStack(i.get()):i,!1):void 0):e.error("no such method '"+n+"' for "+t+" widget instance"):e.error("cannot call methods on "+t+" prior to initialization; "+"attempted to call method '"+n+"'")}):this.each(function(){var t=e.data(this,s);t?(t.option(n||{}),t._init&&t._init()):e.data(this,s,new i(n,this))}),h}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{disabled:!1,create:null},_createWidget:function(t,i){i=e(i||this.defaultElement||this)[0],this.element=e(i),this.uuid=s++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),i!==this&&(e.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===i&&this.destroy()}}),this.document=e(i.style?i.ownerDocument:i.document||i),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(t,i){var s,a,n,o=t;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof t)if(o={},s=t.split("."),t=s.shift(),s.length){for(a=o[t]=e.widget.extend({},this.options[t]),n=0;s.length-1>n;n++)a[s[n]]=a[s[n]]||{},a=a[s[n]];if(t=s.pop(),1===arguments.length)return void 0===a[t]?null:a[t];a[t]=i}else{if(1===arguments.length)return void 0===this.options[t]?null:this.options[t];o[t]=i}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!t),t&&(this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus"))),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(t,i,s){var a,n=this;"boolean"!=typeof t&&(s=i,i=t,t=!1),s?(i=a=e(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,a=this.widget()),e.each(s,function(s,o){function r(){return t||n.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?n[o]:o).apply(n,arguments):void 0}"string"!=typeof o&&(r.guid=o.guid=o.guid||r.guid||e.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+n.eventNamespace,u=h[2];u?a.delegate(u,l,r):i.bind(l,r)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var a,n,o=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],n=i.originalEvent)for(a in n)a in i||(i[a]=n[a]);return this.element.trigger(i,s),!(e.isFunction(o)&&o.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,a,n){"string"==typeof a&&(a={effect:a});var o,r=a?a===!0||"number"==typeof a?i:a.effect||i:t;a=a||{},"number"==typeof a&&(a={duration:a}),o=!e.isEmptyObject(a),a.complete=n,a.delay&&s.delay(a.delay),o&&e.effects&&e.effects.effect[r]?s[t](a):r!==t&&s[r]?s[r](a.duration,a.easing,n):s.queue(function(i){e(this)[t](),n&&n.call(s[0]),i()})}}),e.widget;var n=!1;e(document).mouseup(function(){n=!1}),e.widget("ui.mouse",{version:"1.11.0",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(t){if(!n){this._mouseStarted&&this._mouseUp(t),this._mouseDownEvent=t;var i=this,s=1===t.which,a="string"==typeof this.options.cancel&&t.target.nodeName?e(t.target).closest(this.options.cancel).length:!1;return s&&!a&&this._mouseCapture(t)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(t)!==!1,!this._mouseStarted)?(t.preventDefault(),!0):(!0===e.data(t.target,this.widgetName+".preventClickEvent")&&e.removeData(t.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return i._mouseMove(e)},this._mouseUpDelegate=function(e){return i._mouseUp(e)},this.document.bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),t.preventDefault(),n=!0,!0)):!0}},_mouseMove:function(t){return e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button?this._mouseUp(t):t.which?this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted):this._mouseUp(t)},_mouseUp:function(t){return this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),n=!1,!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),e.widget("ui.draggable",e.ui.mouse,{version:"1.11.0",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"!==this.options.helper||/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._setHandleClassName(),this._mouseInit()},_setOption:function(e,t){this._super(e,t),"handle"===e&&this._setHandleClassName()},_destroy:function(){return(this.helper||this.element).is(".ui-draggable-dragging")?(this.destroyOnClear=!0,void 0):(this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._removeHandleClassName(),this._mouseDestroy(),void 0)},_mouseCapture:function(t){var i=this.document[0],s=this.options;try{i.activeElement&&"body"!==i.activeElement.nodeName.toLowerCase()&&e(i.activeElement).blur()}catch(a){}return this.helper||s.disabled||e(t.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(t),this.handle?(e(s.iframeFix===!0?"iframe":s.iframeFix).each(function(){e("
").css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(e(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(t){var i=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offsetParent=this.helper.offsetParent(),this.offsetParentCssPosition=this.offsetParent.css("position"),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},this.offset.scroll=!1,e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(t,!1),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_mouseDrag:function(t,i){if("fixed"===this.offsetParentCssPosition&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(t,!0),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",t,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.helper[0].style.left=this.position.left+"px",this.helper[0].style.top=this.position.top+"px",e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var i=this,s=!1;return e.ui.ddmanager&&!this.options.dropBehaviour&&(s=e.ui.ddmanager.drop(this,t)),this.dropped&&(s=this.dropped,this.dropped=!1),"invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",t)!==!1&&i._clear()}):this._trigger("stop",t)!==!1&&this._clear(),!1},_mouseUp:function(t){return e("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),this.element.focus(),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){return this.options.handle?!!e(t.target).closest(this.element.find(this.options.handle)).length:!0},_setHandleClassName:function(){this._removeHandleClassName(),e(this.options.handle||this.element).addClass("ui-draggable-handle")},_removeHandleClassName:function(){this.element.find(".ui-draggable-handle").addBack().removeClass("ui-draggable-handle")},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return s.parents("body").length||s.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s[0]===this.element[0]||/(fixed|absolute)/.test(s.css("position"))||s.css("position","absolute"),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_isRootNode:function(e){return/(html|body)/i.test(e.tagName)||e===this.document[0]},_getParentOffset:function(){var t=this.offsetParent.offset(),i=this.document[0];return"absolute"===this.cssPosition&&this.scrollParent[0]!==i&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),this._isRootNode(this.offsetParent[0])&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"!==this.cssPosition)return{top:0,left:0};var e=this.element.position(),t=this._isRootNode(this.scrollParent[0]);return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+(t?0:this.scrollParent.scrollTop()),left:e.left-(parseInt(this.helper.css("left"),10)||0)+(t?0:this.scrollParent.scrollLeft())}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,a=this.options,n=this.document[0];return this.relative_container=null,a.containment?"window"===a.containment?(this.containment=[e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,e(window).scrollLeft()+e(window).width()-this.helperProportions.width-this.margins.left,e(window).scrollTop()+(e(window).height()||n.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===a.containment?(this.containment=[0,0,e(n).width()-this.helperProportions.width-this.margins.left,(e(n).height()||n.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):a.containment.constructor===Array?(this.containment=a.containment,void 0):("parent"===a.containment&&(a.containment=this.helper[0].parentNode),i=e(a.containment),s=i[0],s&&(t="hidden"!==i.css("overflow"),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(t?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(t?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=i),void 0):(this.containment=null,void 0)},_convertPositionTo:function(e,t){t||(t=this.position);var i="absolute"===e?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:t.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:t.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(e,t){var i,s,a,n,o=this.options,r=this._isRootNode(this.scrollParent[0]),h=e.pageX,l=e.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),t&&(this.containment&&(this.relative_container?(s=this.relative_container.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,e.pageX-this.offset.click.lefti[2]&&(h=i[2]+this.offset.click.left),e.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),o.grid&&(a=o.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY,l=i?a-this.offset.click.top>=i[1]||a-this.offset.click.top>i[3]?a:a-this.offset.click.top>=i[1]?a-o.grid[1]:a+o.grid[1]:a,n=o.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX,h=i?n-this.offset.click.left>=i[0]||n-this.offset.click.left>i[2]?n:n-this.offset.click.left>=i[0]?n-o.grid[0]:n+o.grid[0]:n),"y"===o.axis&&(h=this.originalPageX),"x"===o.axis&&(l=this.originalPageY)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_trigger:function(t,i,s){return s=s||this._uiHash(),e.ui.plugin.call(this,t,[i,s,this],!0),"drag"===t&&(this.positionAbs=this._convertPositionTo("absolute")),e.Widget.prototype._trigger.call(this,t,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),e.ui.plugin.add("draggable","connectToSortable",{start:function(t,i,s){var a=s.options,n=e.extend({},i,{item:s.element});s.sortables=[],e(a.connectToSortable).each(function(){var i=e(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push({instance:i,shouldRevert:i.options.revert}),i.refreshPositions(),i._trigger("activate",t,n))})},stop:function(t,i,s){var a=e.extend({},i,{item:s.element});e.each(s.sortables,function(){this.instance.isOver?(this.instance.isOver=0,s.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=this.shouldRevert),this.instance._mouseStop(t),this.instance.options.helper=this.instance.options._helper,"original"===s.options.helper&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",t,a))})},drag:function(t,i,s){var a=this;e.each(s.sortables,function(){var n=!1,o=this;this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this.instance._intersectsWith(this.instance.containerCache)&&(n=!0,e.each(s.sortables,function(){return this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this!==o&&this.instance._intersectsWith(this.instance.containerCache)&&e.contains(o.instance.element[0],this.instance.element[0])&&(n=!1),n})),n?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=e(a).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return i.helper[0]},t.target=this.instance.currentItem[0],this.instance._mouseCapture(t,!0),this.instance._mouseStart(t,!0,!0),this.instance.offset.click.top=s.offset.click.top,this.instance.offset.click.left=s.offset.click.left,this.instance.offset.parent.left-=s.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=s.offset.parent.top-this.instance.offset.parent.top,s._trigger("toSortable",t),s.dropped=this.instance.element,s.currentItem=s.element,this.instance.fromOutside=s),this.instance.currentItem&&this.instance._mouseDrag(t)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",t,this.instance._uiHash(this.instance)),this.instance._mouseStop(t,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),s._trigger("fromSortable",t),s.dropped=!1)})}}),e.ui.plugin.add("draggable","cursor",{start:function(t,i,s){var a=e("body"),n=s.options;a.css("cursor")&&(n._cursor=a.css("cursor")),a.css("cursor",n.cursor)},stop:function(t,i,s){var a=s.options;a._cursor&&e("body").css("cursor",a._cursor)}}),e.ui.plugin.add("draggable","opacity",{start:function(t,i,s){var a=e(i.helper),n=s.options;a.css("opacity")&&(n._opacity=a.css("opacity")),a.css("opacity",n.opacity)},stop:function(t,i,s){var a=s.options;a._opacity&&e(i.helper).css("opacity",a._opacity)}}),e.ui.plugin.add("draggable","scroll",{start:function(e,t,i){i.scrollParent[0]!==i.document[0]&&"HTML"!==i.scrollParent[0].tagName&&(i.overflowOffset=i.scrollParent.offset())},drag:function(t,i,s){var a=s.options,n=!1,o=s.document[0];s.scrollParent[0]!==o&&"HTML"!==s.scrollParent[0].tagName?(a.axis&&"x"===a.axis||(s.overflowOffset.top+s.scrollParent[0].offsetHeight-t.pageY=0;c--)h=s.snapElements[c].left,l=h+s.snapElements[c].width,u=s.snapElements[c].top,d=u+s.snapElements[c].height,h-m>v||g>l+m||u-m>b||y>d+m||!e.contains(s.snapElements[c].item.ownerDocument,s.snapElements[c].item)?(s.snapElements[c].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,t,e.extend(s._uiHash(),{snapItem:s.snapElements[c].item})),s.snapElements[c].snapping=!1):("inner"!==f.snapMode&&(a=m>=Math.abs(u-b),n=m>=Math.abs(d-y),o=m>=Math.abs(h-v),r=m>=Math.abs(l-g),a&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top-s.margins.top),n&&(i.position.top=s._convertPositionTo("relative",{top:d,left:0}).top-s.margins.top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left-s.margins.left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left-s.margins.left)),p=a||n||o||r,"outer"!==f.snapMode&&(a=m>=Math.abs(u-y),n=m>=Math.abs(d-b),o=m>=Math.abs(h-g),r=m>=Math.abs(l-v),a&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top-s.margins.top),n&&(i.position.top=s._convertPositionTo("relative",{top:d-s.helperProportions.height,left:0}).top-s.margins.top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left-s.margins.left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left-s.margins.left)),!s.snapElements[c].snapping&&(a||n||o||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,t,e.extend(s._uiHash(),{snapItem:s.snapElements[c].item})),s.snapElements[c].snapping=a||n||o||r||p)}}),e.ui.plugin.add("draggable","stack",{start:function(t,i,s){var a,n=s.options,o=e.makeArray(e(n.stack)).sort(function(t,i){return(parseInt(e(t).css("zIndex"),10)||0)-(parseInt(e(i).css("zIndex"),10)||0)});o.length&&(a=parseInt(e(o[0]).css("zIndex"),10)||0,e(o).each(function(t){e(this).css("zIndex",a+t)}),this.css("zIndex",a+o.length))}}),e.ui.plugin.add("draggable","zIndex",{start:function(t,i,s){var a=e(i.helper),n=s.options;a.css("zIndex")&&(n._zIndex=a.css("zIndex")),a.css("zIndex",n.zIndex)},stop:function(t,i,s){var a=s.options;a._zIndex&&e(i.helper).css("zIndex",a._zIndex)}}),e.ui.draggable,e.widget("ui.droppable",{version:"1.11.0",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var t,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=e.isFunction(s)?s:function(e){return e.is(s)},this.proportions=function(){return arguments.length?(t=arguments[0],void 0):t?t:t={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},this._addToManager(i.scope),i.addClasses&&this.element.addClass("ui-droppable")},_addToManager:function(t){e.ui.ddmanager.droppables[t]=e.ui.ddmanager.droppables[t]||[],e.ui.ddmanager.droppables[t].push(this)},_splice:function(e){for(var t=0;e.length>t;t++)e[t]===this&&e.splice(t,1) +},_destroy:function(){var t=e.ui.ddmanager.droppables[this.options.scope];this._splice(t),this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(t,i){if("accept"===t)this.accept=e.isFunction(i)?i:function(e){return e.is(i)};else if("scope"===t){var s=e.ui.ddmanager.droppables[this.options.scope];this._splice(s),this._addToManager(i)}this._super(t,i)},_activate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",t,this.ui(i))},_deactivate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",t,this.ui(i))},_over:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",t,this.ui(i)))},_out:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",t,this.ui(i)))},_drop:function(t,i){var s=i||e.ui.ddmanager.current,a=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var t=e(this).droppable("instance");return t.options.greedy&&!t.options.disabled&&t.options.scope===s.options.scope&&t.accept.call(t.element[0],s.currentItem||s.element)&&e.ui.intersect(s,e.extend(t,{offset:t.element.offset()}),t.options.tolerance)?(a=!0,!1):void 0}),a?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",t,this.ui(s)),this.element):!1):!1},ui:function(e){return{draggable:e.currentItem||e.element,helper:e.helper,position:e.position,offset:e.positionAbs}}}),e.ui.intersect=function(){function e(e,t,i){return e>=t&&t+i>e}return function(t,i,s){if(!i.offset)return!1;var a,n,o=(t.positionAbs||t.position.absolute).left,r=(t.positionAbs||t.position.absolute).top,h=o+t.helperProportions.width,l=r+t.helperProportions.height,u=i.offset.left,d=i.offset.top,c=u+i.proportions().width,p=d+i.proportions().height;switch(s){case"fit":return o>=u&&c>=h&&r>=d&&p>=l;case"intersect":return o+t.helperProportions.width/2>u&&c>h-t.helperProportions.width/2&&r+t.helperProportions.height/2>d&&p>l-t.helperProportions.height/2;case"pointer":return a=(t.positionAbs||t.position.absolute).left+(t.clickOffset||t.offset.click).left,n=(t.positionAbs||t.position.absolute).top+(t.clickOffset||t.offset.click).top,e(n,d,i.proportions().height)&&e(a,u,i.proportions().width);case"touch":return(r>=d&&p>=r||l>=d&&p>=l||d>r&&l>p)&&(o>=u&&c>=o||h>=u&&c>=h||u>o&&h>c);default:return!1}}}(),e.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,i){var s,a,n=e.ui.ddmanager.droppables[t.options.scope]||[],o=i?i.type:null,r=(t.currentItem||t.element).find(":data(ui-droppable)").addBack();e:for(s=0;n.length>s;s++)if(!(n[s].options.disabled||t&&!n[s].accept.call(n[s].element[0],t.currentItem||t.element))){for(a=0;r.length>a;a++)if(r[a]===n[s].element[0]){n[s].proportions().height=0;continue e}n[s].visible="none"!==n[s].element.css("display"),n[s].visible&&("mousedown"===o&&n[s]._activate.call(n[s],i),n[s].offset=n[s].element.offset(),n[s].proportions({width:n[s].element[0].offsetWidth,height:n[s].element[0].offsetHeight}))}},drop:function(t,i){var s=!1;return e.each((e.ui.ddmanager.droppables[t.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&e.ui.intersect(t,this,this.options.tolerance)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],t.currentItem||t.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(t,i){t.element.parentsUntil("body").bind("scroll.droppable",function(){t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)})},drag:function(t,i){t.options.refreshPositions&&e.ui.ddmanager.prepareOffsets(t,i),e.each(e.ui.ddmanager.droppables[t.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,a,n,o=e.ui.intersect(t,this,this.options.tolerance),r=!o&&this.isover?"isout":o&&!this.isover?"isover":null;r&&(this.options.greedy&&(a=this.options.scope,n=this.element.parents(":data(ui-droppable)").filter(function(){return e(this).droppable("instance").options.scope===a}),n.length&&(s=e(n[0]).droppable("instance"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(t,i){t.element.parentsUntil("body").unbind("scroll.droppable"),t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)}},e.ui.droppable,e.widget("ui.sortable",e.ui.mouse,{version:"1.11.0",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(e,t,i){return e>=t&&t+i>e},_isFloating:function(e){return/left|right/.test(e.css("float"))||/inline|table-cell/.test(e.css("display"))},_create:function(){var e=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===e.axis||this._isFloating(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this._setHandleClassName(),this.ready=!0},_setOption:function(e,t){this._super(e,t),"handle"===e&&this._setHandleClassName()},_setHandleClassName:function(){this.element.find(".ui-sortable-handle").removeClass("ui-sortable-handle"),e.each(this.items,function(){(this.instance.options.handle?this.item.find(this.instance.options.handle):this.item).addClass("ui-sortable-handle")})},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").find(".ui-sortable-handle").removeClass("ui-sortable-handle"),this._mouseDestroy();for(var e=this.items.length-1;e>=0;e--)this.items[e].item.removeData(this.widgetName+"-item");return this},_mouseCapture:function(t,i){var s=null,a=!1,n=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(t),e(t.target).parents().each(function(){return e.data(this,n.widgetName+"-item")===n?(s=e(this),!1):void 0}),e.data(t.target,n.widgetName+"-item")===n&&(s=e(t.target)),s?!this.options.handle||i||(e(this.options.handle,s).find("*").addBack().each(function(){this===t.target&&(a=!0)}),a)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(t,i,s){var a,n,o=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(t),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,o.cursorAt&&this._adjustOffsetFromHelper(o.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),o.containment&&this._setContainment(),o.cursor&&"auto"!==o.cursor&&(n=this.document.find("body"),this.storedCursor=n.css("cursor"),n.css("cursor",o.cursor),this.storedStylesheet=e("").appendTo(n)),o.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",o.opacity)),o.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",o.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(a=this.containers.length-1;a>=0;a--)this.containers[a]._trigger("activate",t,this._uiHash(this));return e.ui.ddmanager&&(e.ui.ddmanager.current=this),e.ui.ddmanager&&!o.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(t),!0},_mouseDrag:function(t){var i,s,a,n,o=this.options,r=!1;for(this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageY=0;i--)if(s=this.items[i],a=s.item[0],n=this._intersectsWithPointer(s),n&&s.instance===this.currentContainer&&a!==this.currentItem[0]&&this.placeholder[1===n?"next":"prev"]()[0]!==a&&!e.contains(this.placeholder[0],a)&&("semi-dynamic"===this.options.type?!e.contains(this.element[0],a):!0)){if(this.direction=1===n?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(t,s),this._trigger("change",t,this._uiHash());break}return this._contactContainers(t),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),this._trigger("sort",t,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(t,i){if(t){if(e.ui.ddmanager&&!this.options.dropBehaviour&&e.ui.ddmanager.drop(this,t),this.options.revert){var s=this,a=this.placeholder.offset(),n=this.options.axis,o={};n&&"x"!==n||(o.left=a.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),n&&"y"!==n||(o.top=a.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,e(this.helper).animate(o,parseInt(this.options.revert,10)||500,function(){s._clear(t)})}else this._clear(t,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var t=this.containers.length-1;t>=0;t--)this.containers[t]._trigger("deactivate",null,this._uiHash(this)),this.containers[t].containerCache.over&&(this.containers[t]._trigger("out",null,this._uiHash(this)),this.containers[t].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),e.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?e(this.domPosition.prev).after(this.currentItem):e(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},e(i).each(function(){var i=(e(t.item||this).attr(t.attribute||"id")||"").match(t.expression||/(.+)[\-=_](.+)/);i&&s.push((t.key||i[1]+"[]")+"="+(t.key&&t.expression?i[1]:i[2]))}),!s.length&&t.key&&s.push(t.key+"="),s.join("&")},toArray:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},i.each(function(){s.push(e(t.item||this).attr(t.attribute||"id")||"")}),s},_intersectsWith:function(e){var t=this.positionAbs.left,i=t+this.helperProportions.width,s=this.positionAbs.top,a=s+this.helperProportions.height,n=e.left,o=n+e.width,r=e.top,h=r+e.height,l=this.offset.click.top,u=this.offset.click.left,d="x"===this.options.axis||s+l>r&&h>s+l,c="y"===this.options.axis||t+u>n&&o>t+u,p=d&&c;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>e[this.floating?"width":"height"]?p:t+this.helperProportions.width/2>n&&o>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>a-this.helperProportions.height/2},_intersectsWithPointer:function(e){var t="x"===this.options.axis||this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top,e.height),i="y"===this.options.axis||this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left,e.width),s=t&&i,a=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return s?this.floating?n&&"right"===n||"down"===a?2:1:a&&("down"===a?2:1):!1},_intersectsWithSides:function(e){var t=this._isOverAxis(this.positionAbs.top+this.offset.click.top,e.top+e.height/2,e.height),i=this._isOverAxis(this.positionAbs.left+this.offset.click.left,e.left+e.width/2,e.width),s=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return this.floating&&a?"right"===a&&i||"left"===a&&!i:s&&("down"===s&&t||"up"===s&&!t)},_getDragVerticalDirection:function(){var e=this.positionAbs.top-this.lastPositionAbs.top;return 0!==e&&(e>0?"down":"up")},_getDragHorizontalDirection:function(){var e=this.positionAbs.left-this.lastPositionAbs.left;return 0!==e&&(e>0?"right":"left")},refresh:function(e){return this._refreshItems(e),this._setHandleClassName(),this.refreshPositions(),this},_connectWith:function(){var e=this.options;return e.connectWith.constructor===String?[e.connectWith]:e.connectWith},_getItemsAsjQuery:function(t){function i(){r.push(this)}var s,a,n,o,r=[],h=[],l=this._connectWith();if(l&&t)for(s=l.length-1;s>=0;s--)for(n=e(l[s]),a=n.length-1;a>=0;a--)o=e.data(n[a],this.widgetFullName),o&&o!==this&&!o.options.disabled&&h.push([e.isFunction(o.options.items)?o.options.items.call(o.element):e(o.options.items,o.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),o]);for(h.push([e.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):e(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=h.length-1;s>=0;s--)h[s][0].each(i);return e(r)},_removeCurrentsFromItems:function(){var t=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=e.grep(this.items,function(e){for(var i=0;t.length>i;i++)if(t[i]===e.item[0])return!1;return!0})},_refreshItems:function(t){this.items=[],this.containers=[this];var i,s,a,n,o,r,h,l,u=this.items,d=[[e.isFunction(this.options.items)?this.options.items.call(this.element[0],t,{item:this.currentItem}):e(this.options.items,this.element),this]],c=this._connectWith();if(c&&this.ready)for(i=c.length-1;i>=0;i--)for(a=e(c[i]),s=a.length-1;s>=0;s--)n=e.data(a[s],this.widgetFullName),n&&n!==this&&!n.options.disabled&&(d.push([e.isFunction(n.options.items)?n.options.items.call(n.element[0],t,{item:this.currentItem}):e(n.options.items,n.element),n]),this.containers.push(n));for(i=d.length-1;i>=0;i--)for(o=d[i][1],r=d[i][0],s=0,l=r.length;l>s;s++)h=e(r[s]),h.data(this.widgetName+"-item",o),u.push({item:h,instance:o,width:0,height:0,left:0,top:0})},refreshPositions:function(t){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,a,n;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(a=this.options.toleranceElement?e(this.options.toleranceElement,s.item):s.item,t||(s.width=a.outerWidth(),s.height=a.outerHeight()),n=a.offset(),s.left=n.left,s.top=n.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)n=this.containers[i].element.offset(),this.containers[i].containerCache.left=n.left,this.containers[i].containerCache.top=n.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(t){t=t||this;var i,s=t.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=t.currentItem[0].nodeName.toLowerCase(),a=e("<"+s+">",t.document[0]).addClass(i||t.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?t.currentItem.children().each(function(){e(" ",t.document[0]).attr("colspan",e(this).attr("colspan")||1).appendTo(a)}):"img"===s&&a.attr("src",t.currentItem.attr("src")),i||a.css("visibility","hidden"),a},update:function(e,a){(!i||s.forcePlaceholderSize)&&(a.height()||a.height(t.currentItem.innerHeight()-parseInt(t.currentItem.css("paddingTop")||0,10)-parseInt(t.currentItem.css("paddingBottom")||0,10)),a.width()||a.width(t.currentItem.innerWidth()-parseInt(t.currentItem.css("paddingLeft")||0,10)-parseInt(t.currentItem.css("paddingRight")||0,10)))}}),t.placeholder=e(s.placeholder.element.call(t.element,t.currentItem)),t.currentItem.after(t.placeholder),s.placeholder.update(t,t.placeholder)},_contactContainers:function(t){var i,s,a,n,o,r,h,l,u,d,c=null,p=null;for(i=this.containers.length-1;i>=0;i--)if(!e.contains(this.currentItem[0],this.containers[i].element[0]))if(this._intersectsWith(this.containers[i].containerCache)){if(c&&e.contains(this.containers[i].element[0],c.element[0]))continue;c=this.containers[i],p=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",t,this._uiHash(this)),this.containers[i].containerCache.over=0);if(c)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(a=1e4,n=null,u=c.floating||this._isFloating(this.currentItem),o=u?"left":"top",r=u?"width":"height",d=u?"clientX":"clientY",s=this.items.length-1;s>=0;s--)e.contains(this.containers[p].element[0],this.items[s].item[0])&&this.items[s].item[0]!==this.currentItem[0]&&(h=this.items[s].item.offset()[o],l=!1,t[d]-h>this.items[s][r]/2&&(l=!0),a>Math.abs(t[d]-h)&&(a=Math.abs(t[d]-h),n=this.items[s],this.direction=l?"up":"down"));if(!n&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[p])return;n?this._rearrange(t,n,null,!0):this._rearrange(t,null,this.containers[p].element,!0),this._trigger("change",t,this._uiHash()),this.containers[p]._trigger("change",t,this._uiHash(this)),this.currentContainer=this.containers[p],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1}},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||e("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&e.ui.ie)&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var e=this.currentItem.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,a=this.options;"parent"===a.containment&&(a.containment=this.helper[0].parentNode),("document"===a.containment||"window"===a.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,e("document"===a.containment?document:window).width()-this.helperProportions.width-this.margins.left,(e("document"===a.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(a.containment)||(t=e(a.containment)[0],i=e(a.containment).offset(),s="hidden"!==e(t).css("overflow"),this.containment=[i.left+(parseInt(e(t).css("borderLeftWidth"),10)||0)+(parseInt(e(t).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(e(t).css("borderTopWidth"),10)||0)+(parseInt(e(t).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(t.scrollWidth,t.offsetWidth):t.offsetWidth)-(parseInt(e(t).css("borderLeftWidth"),10)||0)-(parseInt(e(t).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(t.scrollHeight,t.offsetHeight):t.offsetHeight)-(parseInt(e(t).css("borderTopWidth"),10)||0)-(parseInt(e(t).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(t,i){i||(i=this.position);var s="absolute"===t?1:-1,a="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,n=/(html|body)/i.test(a[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():n?0:a.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():n?0:a.scrollLeft())*s}},_generatePosition:function(t){var i,s,a=this.options,n=t.pageX,o=t.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(t.pageX-this.offset.click.leftthis.containment[2]&&(n=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top)),a.grid&&(i=this.originalPageY+Math.round((o-this.originalPageY)/a.grid[1])*a.grid[1],o=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-a.grid[1]:i+a.grid[1]:i,s=this.originalPageX+Math.round((n-this.originalPageX)/a.grid[0])*a.grid[0],n=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-a.grid[0]:s+a.grid[0]:s)),{top:o-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:n-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(e,t,i,s){i?i[0].appendChild(this.placeholder[0]):t.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?t.item[0]:t.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var a=this.counter;this._delay(function(){a===this.counter&&this.refreshPositions(!s)})},_clear:function(e,t){function i(e,t,i){return function(s){i._trigger(e,s,t._uiHash(t))}}this.reverting=!1;var s,a=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!t&&a.push(function(e){this._trigger("receive",e,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||t||a.push(function(e){this._trigger("update",e,this._uiHash())}),this!==this.currentContainer&&(t||(a.push(function(e){this._trigger("remove",e,this._uiHash())}),a.push(function(e){return function(t){e._trigger("receive",t,this._uiHash(this))}}.call(this,this.currentContainer)),a.push(function(e){return function(t){e._trigger("update",t,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)t||a.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(a.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!t){for(this._trigger("beforeStop",e,this._uiHash()),s=0;a.length>s;s++)a[s].call(this,e);this._trigger("stop",e,this._uiHash())}return this.fromOutside=!1,!1}if(t||this._trigger("beforeStop",e,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null,!t){for(s=0;a.length>s;s++)a[s].call(this,e);this._trigger("stop",e,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){e.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(t){var i=t||this;return{helper:i.helper,placeholder:i.placeholder||e([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:t?t.element:null}}})}); \ No newline at end of file diff --git a/Upload/admin/jscripts/mycode_sandbox.js b/Upload/admin/jscripts/mycode_sandbox.js new file mode 100644 index 0000000..775a949 --- /dev/null +++ b/Upload/admin/jscripts/mycode_sandbox.js @@ -0,0 +1,57 @@ +function MyCodeSandbox(url, button, regex_textbox, replacement_textbox, test_textbox, html_textbox, actual_div) +{ + if(button && regex_textbox && replacement_textbox && test_textbox && html_textbox && actual_div) + { + this.url = url; + this.button = button; + this.regex_textbox = regex_textbox; + this.replacement_textbox = replacement_textbox; + this.test_textbox = test_textbox; + this.html_textbox = html_textbox; + this.actual_div = actual_div; + + $(button).on('click', function(e) { + e.preventDefault(); + this.update(); + }.bind(this)); + } +} + +MyCodeSandbox.prototype.update = function(e) +{ + postData = "regex="+encodeURIComponent($(this.regex_textbox).val())+"&replacement="+encodeURIComponent($(this.replacement_textbox).val())+"&test_value="+encodeURIComponent($(this.test_textbox).val())+"&my_post_key="+encodeURIComponent(my_post_key); + + $.ajax( + { + url: this.url, + async: true, + method: 'post', + data: postData, + complete: function (request) + { + this.onComplete(request); + }.bind(this) + }); +}; + +MyCodeSandbox.prototype.onComplete = function(request) +{ + if(request.responseText.match(/(.*)<\/error>/)) + { + message = request.responseText.match(/(.*)<\/error>/); + + if(!message[1]) + { + message[1] = lang.unknown_error; + } + + alert(lang.mycode_sandbox_test_error + '\n\n' + message[1]); + } + else if(request.responseText) + { + $(this.actual_div).html(request.responseText); + $(this.html_textbox).val(request.responseText); + } + + return true; +}; \ No newline at end of file diff --git a/Upload/admin/jscripts/peeker.js b/Upload/admin/jscripts/peeker.js new file mode 100644 index 0000000..5d4cf04 --- /dev/null +++ b/Upload/admin/jscripts/peeker.js @@ -0,0 +1,101 @@ +/** + * Peeker controls the visibility of an element based on the value of an input + * + * @example + * + * var peeker = new Peeker($('#myController'), $('#myDomain'), /1/, false); + * var peeker = new Peeker($('.myControllerNode'), $('#myDomain'), /1/, true); + */ + +var Peeker = (function() { + /** + * Constructor + * + * @param string ID of the controlling select menu + * @param string ID of the thing to show/hide + * @param regexp If this regexp matches value of the select menu, then the 'thing' will be shown + * @param boolean Should be set to true for radio/checkboxes + */ + function Peeker(controller, domain, match, isNodelist) { + var fn; + + // verify input + if (!controller || + (isNodelist && controller.length <= 0) || + !domain) { + return; + } + this.controller = controller; + this.domain = domain; + this.match = match; + this.isNodelist = isNodelist; + + // create a context-bound copy of the function + fn = $.proxy(this.check, this); + + if (isNodelist) { + // attach event handlers to the inputs in the node list + this.controller.each(function(i, el) { + el = $(el); + if (el.attr('id') == null) { + return; + } + el.on('change', fn); + el.click(fn); + }); + } else { + this.controller.on('change', fn); + } + this.check(); + } + + /** + * Checks the controller and shows/hide + * + * @return void + */ + function check() { + var type = '', show = false, regex = this.match; + + if (this.isNodelist) { + this.controller.each(function(i, el) { + if (el.checked && + el.value.match(regex)) { + show = true; + return false; + } + }); + this.domain[show ? 'show' : 'hide'](); + } else { + type = this.controller.val() || ''; + this.domain[(type.match(regex)) ? 'show' : 'hide'](); + } + } + + Peeker.prototype = { + controller: null, + domain: null, + match: null, + isNodelist: null, + check: check, + }; + + return Peeker; +})(); + +/** + * Add a "required" asterisk to a FormContainer row + * @param string ID of the row + */ +function add_star(id) { + if (!$('#' + id)) { + return; + } + + cell = $('#' + id).children('td')[0]; + label = $(cell).children('label')[0]; + star = $(document.createElement('em')); + starText = $(document.createTextNode(' *')); + star.append(starText); + $(label).append(star); +} diff --git a/Upload/admin/jscripts/quick_perm_editor.js b/Upload/admin/jscripts/quick_perm_editor.js new file mode 100644 index 0000000..8a700e3 --- /dev/null +++ b/Upload/admin/jscripts/quick_perm_editor.js @@ -0,0 +1,63 @@ +var QuickPermEditor = { + + init: function(id) + { + if(!$('#fields_enabled_'+id) || !$('#fields_disabled_'+id)) + { + return; + } + if(!$('#fields_'+id)) + { + return; + } + + $("#fields_enabled_"+id).sortable({ + connectWith: "#fields_disabled_"+id, + dropOnEmpty: true, + update: function(event, ui) { + QuickPermEditor.buildFieldsList(id); + } + }).disableSelection(); + + $("#fields_disabled_"+id).sortable({ + connectWith: "#fields_enabled_"+id, + dropOnEmpty: true, + update: function(event, ui) { + QuickPermEditor.buildFieldsList(id); + } + }).disableSelection(); + }, + + buildFieldsList: function(id) + { + new_input = ''; + + $('#fields_enabled_'+id).children().each(function() { + var textid = $(this).attr('id').split("-"); + + if(textid[1]) + { + if(new_input) + { + new_input += ","; + } + new_input += textid[1]; + } + }); + + if($('#fields_'+id).val() != new_input) + { + if($('#default_permissions_'+id)) + { + $('#default_permissions_'+id).attr('checked', false); + } + } + + $('#fields_'+id).val(new_input); + + if($('#fields_inherit_'+id)) + { + $('#fields_inherit_'+id).val(0); + } + }, +}; \ No newline at end of file diff --git a/Upload/admin/jscripts/search.js b/Upload/admin/jscripts/search.js new file mode 100644 index 0000000..f7d7770 --- /dev/null +++ b/Upload/admin/jscripts/search.js @@ -0,0 +1,74 @@ +var SettingSearch = { + + error_unknown : "", + + init: function(settings_search, error_unknown) + { + this.error_unknown = error_unknown; + + $('#settings_search').bind("submit", this.onSubmit); + $('#search_results').css('display', 'none'); + + $('#search').focusin(function() { + if($('#search').val() == settings_search) + { + $('#search').removeClass('search_default'); + $('#search').val(''); + } + }); + + $('#search').focusout(function() { + if($('#search').val() == "") + { + $('#search').addClass('search_default'); + $('#search').val(settings_search); + $("#search_results").css('display', "none"); + $("#group_list").css('display', ""); + } + }); + }, + + onSubmit: function(e) + { + e.preventDefault(); + if($('#search').val() != "") + { + $.jGrowl(lang.searching); + pars = "module=config-settings&action=change&ajax_search=1&search="+encodeURIComponent($('#search').val()); + $.ajax({ + type: 'get', + url: "index.php", + data: pars, + complete: function (request, status) + { + try + { + var json = $.parseJSON(request.responseText); + if(typeof json == 'object') + { + if(json.hasOwnProperty("errors")) + { + $("div.jGrowl").jGrowl("close"); + + $.each(json.errors, function(i, message) + { + $.jGrowl(lang.search_error + ' ' + message); + }); + return false; + } + } + } + catch(error) + { + $('#search_results').css('display', ''); + $('#group_list').css('display', 'none'); + $('#search_results').html(request.responseText); + loadPeekers(); + $.jGrowl(lang.search_done); + return false; + } + } + }); + } + }, +}; \ No newline at end of file diff --git a/Upload/admin/jscripts/tabs.js b/Upload/admin/jscripts/tabs.js new file mode 100644 index 0000000..2001bfd --- /dev/null +++ b/Upload/admin/jscripts/tabs.js @@ -0,0 +1,36 @@ +$(function() +{ + $('ul.tabs').each(function() + { + var activeTab, activeContent, links = $(this).find('a'); + + activeTab = $(links.filter('[href="'+location.hash+'"]')[0] || links[0]); + activeTab.addClass('active'); + activeContent = $(activeTab.attr('href')); + + // Hide the remaining content + links.not(activeTab).each(function() + { + $($(this).attr('href')).hide(); + }); + + // Tab functionality + $(this).on('click', 'a', function(e) + { + activeTab.removeClass('active'); + activeContent.hide(); + + activeTab = $(this); + activeContent = $($(this).attr('href')); + + // update address bar + window.location.hash = $(this).attr('href'); + + activeTab.addClass('active'); + activeContent.show(); + + e.preventDefault(); + }); + }); + +}); \ No newline at end of file diff --git a/Upload/admin/jscripts/theme_properties.js b/Upload/admin/jscripts/theme_properties.js new file mode 100644 index 0000000..ffc486d --- /dev/null +++ b/Upload/admin/jscripts/theme_properties.js @@ -0,0 +1,87 @@ +/** + * functions for stylesheet file/color attachments + */ + +var themeProperties = (function() { + /** + * @var number the total attached files for this stylesheet + */ + var attachedCount = 0; + + /** + * attach event handlers + * + * @return void + */ + function init() { + for (var i = 0; i < attachedCount; ++i) { + $("#delete_img_" + i).click(removeAttachmentBox); + } + $("#new_specific_file").click(addAttachmentBox); + } + + /** + * allow external setup + * + * @param string the count at load time + * @return void + */ + function setup(count) { + attachedCount = count || 0; + } + + /** + * create a new blank attachment box + * + * @param object the event + * @return void + */ + function addAttachmentBox(e) { + e.preventDefault(); + + var next_count = Number(attachedCount) + 1, + contents = "
\n\n\n\n\n\n\n\n\n\n
\""" + file_lang_string + "  
\n
\n
\n
\n
\n" + specific_actions_desc_lang_string + "\n\n\n\n\n
\n
\n
\n
\n
\n"; + + // if this is the first attachment, create the first + if (!$("#attach_box_" + attachedCount).attr('id')) { + $("#attach_1").html(contents).show(); + } else { + $("#attach_box_" + attachedCount).html(contents).show(); + } + + checkAction('action_' + attachedCount); + + if ($("#attached_form_" + attachedCount)) { + $("#delete_img_" + attachedCount).click(removeAttachmentBox); + } + ++attachedCount; + } + + /** + * remove an entire attachment box + * + * @param object the event + * @return void + */ + function removeAttachmentBox(e) { + var idArray, id; + + idArray = e.currentTarget.id.split('_'); + if (!idArray.length) { + return; + } + id = idArray[idArray.length - 1]; + e.preventDefault(); + + if (confirm(delete_confirm_lang_string) == true) { + $("#attached_form_" + id).remove(); + } + } + + $(document).ready(init); + + // the only public method + return { + setup: setup, + }; +})(); diff --git a/Upload/admin/jscripts/themes.js b/Upload/admin/jscripts/themes.js new file mode 100644 index 0000000..57d36a6 --- /dev/null +++ b/Upload/admin/jscripts/themes.js @@ -0,0 +1,353 @@ +/** + * ThemeSelector loads various selectors' properties when they are select from + * a list + */ + +var ThemeSelector = (function() { + /** + * @var shortcut + */ + var fn = encodeURIComponent; + + /** + * Constructor + * + * @param string the address to the load script + * @param string the address to the save script + * @param object the select element + * @param object the stylesheet info div + * @param string the stylesheet file name + * @param object the form element + * @param number the theme id + * @return void + */ + function ThemeSelector(url, saveUrl, selector, styleSheet, file, selectorForm, tid) { + // verify input + if (!url || !saveUrl || !selector || !styleSheet || !file || !selectorForm || !tid) { + return; + } + + this.url = url; + this.saveUrl = saveUrl; + this.selector = selector; + this.selectorPrevOpt = this.selector.val(); + this.styleSheet = styleSheet; + this.file = file; + this.selectorForm = selectorForm; + this.tid = tid; + + this.background = $("#css_bits\\[background\\]").val(); + this.width = $("#css_bits\\[width\\]").val(); + this.color = $("#css_bits\\[color\\]").val(); + this.extra = $("#css_bits\\[extra\\]").val(); + this.text_decoration = $("#css_bits\\[text_decoration\\]").val(); + this.font_family = $("#css_bits\\[font_family\\]").val(); + this.font_size = $("#css_bits\\[font_size\\]").val(); + this.font_style = $("#css_bits\\[font_style\\]").val(); + this.font_weight = $("#css_bits\\[font_weight\\]").val(); + + $("#save").on('click', function(event) { $.proxy(this, 'save', event, true); } ); + $("#save_close").on('click', function(event) { $.proxy(this, 'saveClose', event); } ); + + ThemeSelector.that = this; // I know this is cheating :D + + window.onbeforeunload = function(event) { saveCheck(event, false, ThemeSelector.that); } + window.onunload = function(event) { save(false, false); } + + + this.selector.on("change", $.proxy(this, 'updateSelector')); + this.selectorForm.on("submit", $.proxy(this, 'updateSelector')); + } + + /** + * prevents no-save warning messaging when saving + * + * @return void + */ + function saveClose(e) { + this.isClosing = true; + } + + /** + * updates the stylesheet info to match the current selection, checking + * first that work isn't lost + * + * @param object the event + * @return void + */ + function updateSelector(e) { + var postData; + + e.preventDefault() + + this.saveCheck(e, true, null); + + postData = "file=" + fn(this.file) + "&tid=" + fn(this.tid) + "&selector=" + fn(this.selector.val()) + "&my_post_key=" + fn(my_post_key); + + this.selectorGoText = $("#mini_spinner").html(); + $("#mini_spinner").html(" \"\" "); + + $.ajax({ + type: 'post', + url: this.url, + data: postData, + complete: $.proxy(this, 'onComplete'), + }); + } + + /** + * handles the AJAX return data + * + * @param object the request + * @return true + */ + function onComplete(request) { + var message, saved; + + if (request.responseText.match(/(.*)<\/error>/)) { + message = request.responseText.match(/(.*)<\/error>/); + + if (!message[1]) { + message[1] = lang.unknown_error; + } + $.jGrowl(lang.theme_info_fetch_error + '\n\n' + message[1]); + } else if(request.responseText) { + if ($("#saved").html()) { + saved = $("#saved").html(); + } + this.styleSheet.html(request.responseText); + } + + this.background = $("#css_bits\\[background\\]").val(); + this.width = $("#css_bits\\[width\\]").val(); + this.color = $("#css_bits\\[color\\]").val(); + this.extra = $("#css_bits\\[extra\\]").val(); + this.text_decoration = $("#css_bits\\[text_decoration\\]").val(); + this.font_family = $("#css_bits\\[font_family\\]").val(); + this.font_size = $("#css_bits\\[font_size\\]").val(); + this.font_style = $("#css_bits\\[font_style\\]").val(); + this.font_weight = $("#css_bits\\[font_weight\\]").val(); + + if (saved) { + $("#saved").html(saved); + window.setTimeout(function() { + $("#saved").html(""); + }, 30000); + } + + $("#mini_spinner").html(this.selectorGoText); + this.selectorGoText = ''; + + return true; + } + + /** + * check if anything has changed + * + * @param object the event + * @param bool true if AJAX, false if not + * @return true + */ + function saveCheck(e, isAjax, that) { + + if(that == null) + that = this; + + if (that.isClosing == true) { + return true; + } + + if(e != null && isAjax == true) + e.preventDefault(); + + if (that.background != $("#css_bits\\[background\\]").val() || + that.width != $("#css_bits\\[width\\]").val() || + that.color != $("#css_bits\\[color\\]").val() || + that.extra != $("#css_bits\\[extra\\]").val() || + that.text_decoration != $("#css_bits\\[text_decoration\\]").val() || + that.font_family != $("#css_bits\\[font_family\\]").val() || + that.font_size != $("#css_bits\\[font_size\\]").val() || + that.font_style != $("#css_bits\\[font_style\\]").val() || + that.font_weight != $("#css_bits\\[font_weight\\]").val()) { + + e.preventDefault(); + + if(isAjax == false) + return save_changes_lang_string; + else + { + confirmReturn = confirm(save_changes_lang_string); + if (confirmReturn == true) { + that.save(false, isAjax); + $.jGrowl('Saved'); + } + } + } + else if(isAjax == true) + { + that.selectorPrevOpt = that.selector.val(); + return true; + } + } + + /** + * saves the selector info + * + * @param object the event + * @param bool true if AJAX, false if not + * @return true + */ + function save(e, isAjax) { + var cssBits, postData, completeMethod = 'onUnloadSaveComplete'; + + if (e) { + e.preventDefault(); + } + + cssBits = { + 'background': $('#css_bits\\[background\\]').val(), + 'width': $('#css_bits\\[width\\]').val(), + 'color': $('#css_bits\\[color\\]').val(), + 'extra': $('#css_bits\\[extra\\]').val(), + 'text_decoration': $('#css_bits\\[text_decoration\\]').val(), + 'font_family': $('#css_bits\\[font_family\\]').val(), + 'font_size': $('#css_bits\\[font_size\\]').val(), + 'font_style': $('#css_bits\\[font_style\\]').val(), + 'font_weight': $('#css_bits\\[font_weight\\]').val() + }; + + postData = "css_bits=" + fn(jsArrayToPhpArray(cssBits)) + "&selector=" + fn(this.selectorPrevOpt) + "&file=" + fn(this.file) + "&tid=" + fn(this.tid) + "&my_post_key=" + fn(my_post_key) + "&serialized=1"; + + if (isAjax == true) { + postData += "&ajax=1"; + } + + this.isAjax = isAjax; + + if (isAjax == true) { + completeMethod = 'onSaveComplete'; + $.jGrowl(lang.saving); + } + + $.ajax({ + type: 'post', + url: this.saveUrl, + data: postData, + complete: $.proxy(this, completeMethod), + }); + return !isAjax; + } + + /** + * handle errors, reset values and clean up + * + * @param object the request + * @return true + */ + function onSaveComplete(request) { + var message; + + if (request.responseText.match(/(.*)<\/error>/)) { + message = request.responseText.match(/(.*)<\/error>/); + + if (!message[1]) { + message[1] = lang.unkown_error; + } + $.jGrowl(lang.theme_info_save_error + '\n\n' + message[1]); + return false; + } else if(request.responseText) { + $("#saved").html(" (" + lang.saved + " @ "+ Date() + ")"); + if ($("#ajax_alert")) { + $("#ajax_alert").html('').hide(); + } + } + + this.background = $("#css_bits\\[background\\]").val(); + this.width = $("#css_bits\\[width\\]").val(); + this.color = $("#css_bits\\[color\\]").val(); + this.extra = $("#css_bits\\[extra\\]").val(); + this.text_decoration = $("#css_bits\\[text_decoration\\]").val(); + this.font_family = $("#css_bits\\[font_family\\]").val(); + this.font_size = $("#css_bits\\[font_size\\]").val(); + this.font_style = $("#css_bits\\[font_style\\]").val(); + this.font_weight = $("#css_bits\\[font_weight\\]").val(); + + return true; + } + + /** + * handle leaving page save + * + * @param object the request + * @return true + */ + function onUnloadSaveComplete(request) { + var message; + + if (request.responseText.match(/(.*)<\/error>/)) { + message = request.responseText.match(/(.*)<\/error>/); + + if (!message[1]) { + message[1] = lang.unkown_error; + } + $.jGrowl(lang.theme_info_save_error + '\n\n' + message[1]); + return false; + } + return true; + } + + ThemeSelector.prototype = { + url: null, + saveUrl: null, + selector: null, + styleSheet: null, + file: null, + selectorForm: null, + tid: null, + miniSpinnerImage: "../images/spinner.gif", + isAjax: false, + specific_count: 0, + selectorGoText: null, + selectorPrevOpt: null, + isClosing: false, + background: null, + width: null, + color: null, + extra: null, + text_decoration: null, + font_family: null, + font_size: null, + font_style: null, + font_weight: null, + saveClose: saveClose, + updateSelector: updateSelector, + onComplete: onComplete, + saveCheck: saveCheck, + save: save, + onSaveComplete: onSaveComplete, + onUnloadSaveComplete: onUnloadSaveComplete, + } + + return ThemeSelector; +})(); + +/** + * converts a JS object to a JSON of a PHP associative array + * + * @param array the JS array + * @return string the JSON + */ +function jsArrayToPhpArray(a) { + var a_php = "", total = 0; + + for (var key in a) { + ++total; + a_php += "s:" + + String(key).length + ":\"" + + String(key) + "\";s:" + + String(a[key]).length + + ":\"" + String(a[key]) + "\";"; + } + a_php = "a:" + total + ":{" + a_php + "}"; + return a_php; +} diff --git a/Upload/admin/jscripts/users.js b/Upload/admin/jscripts/users.js new file mode 100644 index 0000000..72a1b26 --- /dev/null +++ b/Upload/admin/jscripts/users.js @@ -0,0 +1,13 @@ +var Users = { + last_value: '', + cached_users: '', + + init: function() + { + } +}; + +$(function() +{ + Users.init(); +}); \ No newline at end of file diff --git a/Upload/admin/jscripts/view_manager.js b/Upload/admin/jscripts/view_manager.js new file mode 100644 index 0000000..a0da901 --- /dev/null +++ b/Upload/admin/jscripts/view_manager.js @@ -0,0 +1,53 @@ +var ViewManager = { + init: function() + { + if(!$('#fields_enabled') || !$('#fields_disabled')) + { + return; + } + + if(!$('#fields_js')) + { + return; + } + + $("#fields_enabled").sortable({ + connectWith: "#fields_disabled", + dropOnEmpty: true, + update: function(event, ui) { + ViewManager.buildFieldsList(); + } + }).disableSelection(); + + $("#fields_disabled").sortable({ + connectWith: "#fields_enabled", + dropOnEmpty: true, + update: function(event, ui) { + ViewManager.buildFieldsList(); + } + }).disableSelection(); + }, + + buildFieldsList: function() + { + new_input = ''; + $('#fields_enabled').children().each(function() { + id = $(this).attr('id').split("-"); + + if(id[1]) + { + if(new_input) + { + new_input += ","; + } + new_input += id[1]; + } + }); + $('#fields_js').val(new_input); + } +}; + +$(function() +{ + ViewManager.init(); +}); \ No newline at end of file diff --git a/Upload/admin/modules/config/attachment_types.php b/Upload/admin/modules/config/attachment_types.php new file mode 100644 index 0000000..95c0387 --- /dev/null +++ b/Upload/admin/modules/config/attachment_types.php @@ -0,0 +1,350 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->attachment_types, "index.php?module=config-attachment_types"); + +$plugins->run_hooks("admin_config_attachment_types_begin"); + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_config_attachment_types_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['mimetype']) && !trim($mybb->input['extension'])) + { + $errors[] = $lang->error_missing_mime_type; + } + + if(!trim($mybb->input['extension']) && !trim($mybb->input['mimetype'])) + { + $errors[] = $lang->error_missing_extension; + } + + if(!$errors) + { + if($mybb->input['mimetype'] == "images/attachtypes/") + { + $mybb->input['mimetype'] = ''; + } + + if(substr($mybb->input['extension'], 0, 1) == '.') + { + $mybb->input['extension'] = substr($mybb->input['extension'], 1); + } + + $maxsize = $mybb->get_input('maxsize', 1); + + if($maxsize == 0) + { + $maxsize = ""; + } + + $new_type = array( + "name" => $db->escape_string($mybb->input['name']), + "mimetype" => $db->escape_string($mybb->input['mimetype']), + "extension" => $db->escape_string($mybb->input['extension']), + "maxsize" => $maxsize, + "icon" => $db->escape_string($mybb->input['icon']) + ); + + $atid = $db->insert_query("attachtypes", $new_type); + + $plugins->run_hooks("admin_config_attachment_types_add_commit"); + + // Log admin action + log_admin_action($atid, $mybb->input['extension']); + + $cache->update_attachtypes(); + + flash_message($lang->success_attachment_type_created, 'success'); + admin_redirect("index.php?module=config-attachment_types"); + } + } + + $page->add_breadcrumb_item($lang->add_new_attachment_type); + $page->output_header($lang->attachment_types." - ".$lang->add_new_attachment_type); + + $sub_tabs['attachment_types'] = array( + 'title' => $lang->attachment_types, + 'link' => "index.php?module=config-attachment_types" + ); + + $sub_tabs['add_attachment_type'] = array( + 'title' => $lang->add_new_attachment_type, + 'link' => "index.php?module=config-attachment_types&action=add", + 'description' => $lang->add_attachment_type_desc + ); + + $page->output_nav_tabs($sub_tabs, 'add_attachment_type'); + + $form = new Form("index.php?module=config-attachment_types&action=add", "post", "add"); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['maxsize'] = '1024'; + $mybb->input['icon'] = "images/attachtypes/"; + } + + // PHP settings + $upload_max_filesize = @ini_get('upload_max_filesize'); + $post_max_size = @ini_get('post_max_size'); + $limit_string = ''; + if($upload_max_filesize || $post_max_size) + { + $limit_string = '

'.$lang->limit_intro; + if($upload_max_filesize) + { + $limit_string .= '
'.$lang->sprintf($lang->limit_upload_max_filesize, $upload_max_filesize); + } + if($post_max_size) + { + $limit_string .= '
'.$lang->sprintf($lang->limit_post_max_size, $post_max_size); + } + } + + $form_container = new FormContainer($lang->add_new_attachment_type); + $form_container->output_row($lang->name, $lang->name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->file_extension." *", $lang->file_extension_desc, $form->generate_text_box('extension', $mybb->input['extension'], array('id' => 'extension')), 'extension'); + $form_container->output_row($lang->mime_type." *", $lang->mime_type_desc, $form->generate_text_box('mimetype', $mybb->input['mimetype'], array('id' => 'mimetype')), 'mimetype'); + $form_container->output_row($lang->maximum_file_size, $lang->maximum_file_size_desc.$limit_string, $form->generate_numeric_field('maxsize', $mybb->input['maxsize'], array('id' => 'maxsize')), 'maxsize'); + $form_container->output_row($lang->attachment_icon, $lang->attachment_icon_desc, $form->generate_text_box('icon', $mybb->input['icon'], array('id' => 'icon')), 'icon'); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_attachment_type); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("attachtypes", "*", "atid='".$mybb->get_input('atid', 1)."'"); + $attachment_type = $db->fetch_array($query); + + if(!$attachment_type['atid']) + { + flash_message($lang->error_invalid_attachment_type, 'error'); + admin_redirect("index.php?module=config-attachment_types"); + } + + $plugins->run_hooks("admin_config_attachment_types_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['mimetype']) && !trim($mybb->input['extension'])) + { + $errors[] = $lang->error_missing_mime_type; + } + + if(!trim($mybb->input['extension']) && !trim($mybb->input['mimetype'])) + { + $errors[] = $lang->error_missing_extension; + } + + if(!$errors) + { + if($mybb->input['mimetype'] == "images/attachtypes/") + { + $mybb->input['mimetype'] = ''; + } + + if(substr($mybb->input['extension'], 0, 1) == '.') + { + $mybb->input['extension'] = substr($mybb->input['extension'], 1); + } + + $updated_type = array( + "name" => $db->escape_string($mybb->input['name']), + "mimetype" => $db->escape_string($mybb->input['mimetype']), + "extension" => $db->escape_string($mybb->input['extension']), + "maxsize" => $mybb->get_input('maxsize', 1), + "icon" => $db->escape_string($mybb->input['icon']) + ); + + $plugins->run_hooks("admin_config_attachment_types_edit_commit"); + + $db->update_query("attachtypes", $updated_type, "atid='{$attachment_type['atid']}'"); + + // Log admin action + log_admin_action($attachment_type['atid'], $mybb->input['extension']); + + $cache->update_attachtypes(); + + flash_message($lang->success_attachment_type_updated, 'success'); + admin_redirect("index.php?module=config-attachment_types"); + } + } + + $page->add_breadcrumb_item($lang->edit_attachment_type); + $page->output_header($lang->attachment_types." - ".$lang->edit_attachment_type); + + $sub_tabs['edit_attachment_type'] = array( + 'title' => $lang->edit_attachment_type, + 'link' => "index.php?module=config-attachment_types&action=edit&atid={$attachment_type['atid']}", + 'description' => $lang->edit_attachment_type_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_attachment_type'); + + $form = new Form("index.php?module=config-attachment_types&action=edit&atid={$attachment_type['atid']}", "post", "add"); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input = array_merge($mybb->input, $attachment_type); + } + + // PHP settings + $upload_max_filesize = @ini_get('upload_max_filesize'); + $post_max_size = @ini_get('post_max_size'); + $limit_string = ''; + if($upload_max_filesize || $post_max_size) + { + $limit_string = '

'.$lang->limit_intro; + if($upload_max_filesize) + { + $limit_string .= '
'.$lang->sprintf($lang->limit_upload_max_filesize, $upload_max_filesize); + } + if($post_max_size) + { + $limit_string .= '
'.$lang->sprintf($lang->limit_post_max_size, $post_max_size); + } + } + + $form_container = new FormContainer($lang->edit_attachment_type); + $form_container->output_row($lang->name, $lang->name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->file_extension." *", $lang->file_extension_desc, $form->generate_text_box('extension', $mybb->input['extension'], array('id' => 'extension')), 'extension'); + $form_container->output_row($lang->mime_type." *", $lang->mime_type_desc, $form->generate_text_box('mimetype', $mybb->input['mimetype'], array('id' => 'mimetype')), 'mimetype'); + $form_container->output_row($lang->maximum_file_size, $lang->maximum_file_size_desc.$limit_string, $form->generate_numeric_field('maxsize', $mybb->input['maxsize'], array('id' => 'maxsize')), 'maxsize'); + $form_container->output_row($lang->attachment_icon, $lang->attachment_icon_desc, $form->generate_text_box('icon', $mybb->input['icon'], array('id' => 'icon')), 'icon'); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_attachment_type); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete") +{ + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-attachment_types"); + } + + $query = $db->simple_select("attachtypes", "*", "atid='".$mybb->get_input('atid', 1)."'"); + $attachment_type = $db->fetch_array($query); + + if(!$attachment_type['atid']) + { + flash_message($lang->error_invalid_attachment_type, 'error'); + admin_redirect("index.php?module=config-attachment_types"); + } + + $plugins->run_hooks("admin_config_attachment_types_delete"); + + if($mybb->request_method == "post") + { + $db->delete_query("attachtypes", "atid='{$attachment_type['atid']}'"); + + $plugins->run_hooks("admin_config_attachment_types_delete_commit"); + + $cache->update_attachtypes(); + + // Log admin action + log_admin_action($attachment_type['atid'], $attachment_type['extension']); + + flash_message($lang->success_attachment_type_deleted, 'success'); + admin_redirect("index.php?module=config-attachment_types"); + } + else + { + $page->output_confirm_action("index.php?module=config-attachment_types&action=delete&atid={$attachment_type['atid']}", $lang->confirm_attachment_type_deletion); + } +} + +if(!$mybb->input['action']) +{ + $page->output_header($lang->attachment_types); + + $sub_tabs['attachment_types'] = array( + 'title' => $lang->attachment_types, + 'link' => "index.php?module=config-attachment_types", + 'description' => $lang->attachment_types_desc + ); + $sub_tabs['add_attachment_type'] = array( + 'title' => $lang->add_new_attachment_type, + 'link' => "index.php?module=config-attachment_types&action=add", + ); + + $plugins->run_hooks("admin_config_attachment_types_start"); + + $page->output_nav_tabs($sub_tabs, 'attachment_types'); + + $table = new Table; + $table->construct_header($lang->extension, array("colspan" => 2)); + $table->construct_header($lang->mime_type); + $table->construct_header($lang->maximum_size, array("class" => "align_center")); + $table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 2)); + + $query = $db->simple_select("attachtypes", "*", "", array('order_by' => 'extension')); + while($attachment_type = $db->fetch_array($query)) + { + // Just show default icons in ACP + $attachment_type['icon'] = str_replace("{theme}", "images", $attachment_type['icon']); + if(!$attachment_type['icon'] || $attachment_type['icon'] == "images/attachtypes/") + { + $attachment_type['icon'] = " "; + } + else + { + $attachment_type['icon'] = "\"\""; + } + + $table->construct_cell($attachment_type['icon'], array("width" => 1)); + $table->construct_cell(".{$attachment_type['extension']}"); + $table->construct_cell($attachment_type['mimetype']); + $table->construct_cell(get_friendly_size(($attachment_type['maxsize']*1024)), array("class" => "align_center")); + $table->construct_cell("
{$lang->edit}", array("class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_attachment_type_deletion}')\">{$lang->delete}", array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_attachment_types, array('colspan' => 6)); + $table->construct_row(); + } + + $table->output($lang->attachment_types); + + $page->output_footer(); +} + diff --git a/Upload/admin/modules/config/badwords.php b/Upload/admin/modules/config/badwords.php new file mode 100644 index 0000000..8d65917 --- /dev/null +++ b/Upload/admin/modules/config/badwords.php @@ -0,0 +1,269 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->bad_words, "index.php?module=config-badwords"); + +$plugins->run_hooks("admin_config_badwords_begin"); + +if($mybb->input['action'] == "add" && $mybb->request_method == "post") +{ + $plugins->run_hooks("admin_config_badwords_add"); + + if(!trim($mybb->input['badword'])) + { + $errors[] = $lang->error_missing_bad_word; + } + + if(strlen(trim($mybb->input['badword'])) > 100) + { + $errors[] = $lang->bad_word_max; + } + + if(strlen($mybb->input['replacement']) > 100) + { + $errors[] = $lang->replacement_word_max; + } + + if(!$errors) + { + $query = $db->simple_select("badwords", "bid", "badword = '".$db->escape_string($mybb->input['badword'])."'"); + + if($db->num_rows($query)) + { + $errors[] = $lang->error_bad_word_filtered; + } + } + + $badword = str_replace('\*', '([a-zA-Z0-9_]{1})', preg_quote($mybb->input['badword'], "#")); + + // Don't allow certain badword replacements to be added if it would cause an infinite recursive loop. + if(strlen($mybb->input['badword']) == strlen($mybb->input['replacement']) && preg_match("#(^|\W)".$badword."(\W|$)#i", $mybb->input['replacement'])) + { + $errors[] = $lang->error_replacement_word_invalid; + } + + if(!$errors) + { + $new_badword = array( + "badword" => $db->escape_string($mybb->input['badword']), + "replacement" => $db->escape_string($mybb->input['replacement']) + ); + + $bid = $db->insert_query("badwords", $new_badword); + + $plugins->run_hooks("admin_config_badwords_add_commit"); + + // Log admin action + log_admin_action($bid, $mybb->input['badword']); + + $cache->update_badwords(); + flash_message($lang->success_added_bad_word, 'success'); + admin_redirect("index.php?module=config-badwords"); + } + else + { + $mybb->input['action'] = ''; + } +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("badwords", "*", "bid='".$mybb->get_input('bid', 1)."'"); + $badword = $db->fetch_array($query); + + // Does the bad word not exist? + if(!$badword['bid']) + { + flash_message($lang->error_invalid_bid, 'error'); + admin_redirect("index.php?module=config-badwords"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-badwords"); + } + + $plugins->run_hooks("admin_config_badwords_delete"); + + if($mybb->request_method == "post") + { + // Delete the bad word + $db->delete_query("badwords", "bid='{$badword['bid']}'"); + + $plugins->run_hooks("admin_config_badwords_delete_commit"); + + // Log admin action + log_admin_action($badword['bid'], $badword['badword']); + + $cache->update_badwords(); + + flash_message($lang->success_deleted_bad_word, 'success'); + admin_redirect("index.php?module=config-badwords"); + } + else + { + $page->output_confirm_action("index.php?module=config-badwords&action=delete&bid={$badword['bid']}", $lang->confirm_bad_word_deletion); + } +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("badwords", "*", "bid='".$mybb->get_input('bid', 1)."'"); + $badword = $db->fetch_array($query); + + // Does the bad word not exist? + if(!$badword['bid']) + { + flash_message($lang->error_invalid_bid, 'error'); + admin_redirect("index.php?module=config-badwords"); + } + + $plugins->run_hooks("admin_config_badwords_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['badword'])) + { + $errors[] = $lang->error_missing_bad_word; + } + + if(strlen(trim($mybb->input['badword'])) > 100) + { + $errors[] = $lang->bad_word_max; + } + + if(strlen($mybb->input['replacement']) > 100) + { + $errors[] = $lang->replacement_word_max; + } + + if(!$errors) + { + $updated_badword = array( + "badword" => $db->escape_string($mybb->input['badword']), + "replacement" => $db->escape_string($mybb->input['replacement']) + ); + + $plugins->run_hooks("admin_config_badwords_edit_commit"); + + $db->update_query("badwords", $updated_badword, "bid='{$badword['bid']}'"); + + // Log admin action + log_admin_action($badword['bid'], $mybb->input['badword']); + + $cache->update_badwords(); + + flash_message($lang->success_updated_bad_word, 'success'); + admin_redirect("index.php?module=config-badwords"); + } + } + + $page->add_breadcrumb_item($lang->edit_bad_word); + $page->output_header($lang->bad_words." - ".$lang->edit_bad_word); + + $sub_tabs['editbadword'] = array( + 'title' => $lang->edit_bad_word, + 'description' => $lang->edit_bad_word_desc, + 'link' => "index.php?module=config-badwords" + ); + + $page->output_nav_tabs($sub_tabs, "editbadword"); + + $form = new Form("index.php?module=config-badwords&action=edit&bid={$badword['bid']}", "post"); + + if($errors) + { + $page->output_inline_error($errors); + $badword_data = $mybb->input; + } + else + { + $badword_data = $badword; + } + + $form_container = new FormContainer($lang->edit_bad_word); + $form_container->output_row($lang->bad_word." *", $lang->bad_word_desc, $form->generate_text_box('badword', $badword_data['badword'], array('id' => 'badword')), 'badword'); + $form_container->output_row($lang->replacement, $lang->replacement_desc, $form->generate_text_box('replacement', $badword_data['replacement'], array('id' => 'replacement')), 'replacement'); + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->save_bad_word); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $page->output_header($lang->bad_words); + + $sub_tabs['badwords'] = array( + 'title' => $lang->bad_word_filters, + 'description' => $lang->bad_word_filters_desc, + 'link' => "index.php?module=config-badwords" + ); + + $plugins->run_hooks("admin_config_badwords_start"); + + $page->output_nav_tabs($sub_tabs, "badwords"); + + if($errors) + { + $page->output_inline_error($errors); + } + + $table = new Table; + $table->construct_header($lang->bad_word); + $table->construct_header($lang->replacement, array("width" => "50%")); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 150, "colspan" => 2)); + + $query = $db->simple_select("badwords", "*", "", array("order_by" => "badword", "order_dir" => "asc")); + while($badword = $db->fetch_array($query)) + { + $badword['badword'] = htmlspecialchars_uni($badword['badword']); + $badword['replacement'] = htmlspecialchars_uni($badword['replacement']); + if(!$badword['replacement']) + { + $badword['replacement'] = '*****'; + } + $table->construct_cell($badword['badword']); + $table->construct_cell($badword['replacement']); + $table->construct_cell("{$lang->edit}", array("class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_bad_word_deletion}');\">{$lang->delete}", array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_bad_words, array("colspan" => 4)); + $table->construct_row(); + } + + $table->output($lang->bad_word_filters); + + $form = new Form("index.php?module=config-badwords&action=add", "post", "add"); + + $form_container = new FormContainer($lang->add_bad_word); + $form_container->output_row($lang->bad_word." *", $lang->bad_word_desc, $form->generate_text_box('badword', $mybb->input['badword'], array('id' => 'badword')), 'badword'); + $form_container->output_row($lang->replacement, $lang->replacement_desc, $form->generate_text_box('replacement', $mybb->input['replacement'], array('id' => 'replacement')), 'replacement'); + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->save_bad_word); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + diff --git a/Upload/admin/modules/config/banning.php b/Upload/admin/modules/config/banning.php new file mode 100644 index 0000000..91cc701 --- /dev/null +++ b/Upload/admin/modules/config/banning.php @@ -0,0 +1,294 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->banning, "index.php?module=config-banning"); + +$plugins->run_hooks("admin_config_banning_begin"); + +if($mybb->input['action'] == "add" && $mybb->request_method == "post") +{ + $plugins->run_hooks("admin_config_banning_add"); + + if(!trim($mybb->input['filter'])) + { + $errors[] = $lang->error_missing_ban_input; + } + + $query = $db->simple_select("banfilters", "fid", "filter = '".$db->escape_string($mybb->input['filter'])."' AND type = '".$mybb->get_input('type', 1)."'"); + if($db->num_rows($query)) + { + $errors[] = $lang->error_filter_already_banned; + } + + if(!$errors) + { + $new_filter = array( + "filter" => $db->escape_string($mybb->input['filter']), + "type" => $mybb->get_input('type', 1), + "dateline" => TIME_NOW + ); + $fid = $db->insert_query("banfilters", $new_filter); + + $plugins->run_hooks("admin_config_banning_add_commit"); + + if($mybb->input['type'] == 1) + { + $cache->update_bannedips(); + } + else if($mybb->input['type'] == 3) + { + $cache->update_bannedemails(); + } + + // Log admin action + log_admin_action($fid, $mybb->input['filter'], $mybb->input['type']); + + if($mybb->input['type'] == 1) + { + flash_message($lang->success_ip_banned, 'success'); + admin_redirect("index.php?module=config-banning"); + } + else if($mybb->input['type'] == 2) + { + flash_message($lang->success_username_disallowed, 'success'); + admin_redirect("index.php?module=config-banning&type=usernames"); + } + else if($mybb->input['type'] == 3) + { + flash_message($lang->success_email_disallowed, 'success'); + admin_redirect("index.php?module=config-banning&type=emails"); + } + } + else + { + if($mybb->input['type'] == 1) + { + $mybb->input['type'] = "ips"; + } + else if($mybb->input['type'] == 2) + { + $mybb->input['type'] = "usernames"; + } + else if($mybb->input['type'] == 3) + { + $mybb->input['type'] = "emails"; + } + $mybb->input['action'] = ''; + } +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("banfilters", "*", "fid='".$mybb->get_input('fid', 1)."'"); + $filter = $db->fetch_array($query); + + // Does the filter not exist? + if(!$filter['fid']) + { + flash_message($lang->error_invalid_filter, 'error'); + admin_redirect("index.php?module=config-banning"); + } + + $plugins->run_hooks("admin_config_banning_delete"); + + if($filter['type'] == 3) + { + $type = "emails"; + } + else if($filter['type'] == 2) + { + $type = "usernames"; + } + else + { + $type = "ips"; + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-banning&type={$type}"); + } + + if($mybb->request_method == "post") + { + // Delete the ban filter + $db->delete_query("banfilters", "fid='{$filter['fid']}'"); + + $plugins->run_hooks("admin_config_banning_delete_commit"); + + // Log admin action + log_admin_action($filter['fid'], $filter['filter'], $filter['type']); + + // Banned IP? Rebuild banned IP cache + if($filter['type'] == 1) + { + $cache->update_bannedips(); + } + else if($filter['type'] == 3) + { + $cache->update_bannedemails(); + } + + flash_message($lang->success_ban_deleted, 'success'); + admin_redirect("index.php?module=config-banning&type={$type}"); + } + else + { + $page->output_confirm_action("index.php?module=config-banning&action=delete&fid={$filter['fid']}", $lang->confirm_ban_deletion); + } +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_config_banning_start"); + + switch($mybb->input['type']) + { + case "emails": + $type = "3"; + $title = $lang->disallowed_email_addresses; + break; + case "usernames": + $type = "2"; + $title = $lang->disallowed_usernames; + break; + default: + $type = "1"; + $title = $lang->banned_ip_addresses; + $mybb->input['type'] = "ips"; + } + + $page->output_header($title); + + $sub_tabs['ips'] = array( + 'title' => $lang->banned_ips, + 'link' => "index.php?module=config-banning", + 'description' => $lang->banned_ips_desc + ); + + $sub_tabs['users'] = array( + 'title' => $lang->banned_accounts, + 'link' => "index.php?module=user-banning" + ); + + $sub_tabs['usernames'] = array( + 'title' => $lang->disallowed_usernames, + 'link' => "index.php?module=config-banning&type=usernames", + 'description' => $lang->disallowed_usernames_desc + ); + + $sub_tabs['emails'] = array( + 'title' => $lang->disallowed_email_addresses, + 'link' => "index.php?module=config-banning&type=emails", + 'description' => $lang->disallowed_email_addresses_desc + ); + + $page->output_nav_tabs($sub_tabs, $mybb->input['type']); + + if($errors) + { + $page->output_inline_error($errors); + } + + $table = new Table; + if($mybb->input['type'] == "usernames") + { + $table->construct_header($lang->username); + $table->construct_header($lang->date_disallowed, array("class" => "align_center", "width" => 200)); + $table->construct_header($lang->last_attempted_use, array("class" => "align_center", "width" => 200)); + } + else if($mybb->input['type'] == "emails") + { + $table->construct_header($lang->email_address); + $table->construct_header($lang->date_disallowed, array("class" => "align_center", "width" => 200)); + $table->construct_header($lang->last_attempted_use, array("class" => "align_center", "width" => 200)); + } + else + { + $table->construct_header($lang->ip_address); + $table->construct_header($lang->ban_date, array("class" => "align_center", "width" => 200)); + $table->construct_header($lang->last_access, array("class" => "align_center", "width" => 200)); + } + $table->construct_header($lang->controls, array("width" => 1)); + + $query = $db->simple_select("banfilters", "*", "type='{$type}'", array("order_by" => "filter", "order_dir" => "asc")); + while($filter = $db->fetch_array($query)) + { + $filter['filter'] = htmlspecialchars_uni($filter['filter']); + + if($filter['lastuse'] > 0) + { + $last_use = my_date('relative', $filter['lastuse']); + } + else + { + $last_use = $lang->never; + } + + if($filter['dateline'] > 0) + { + $date = my_date('relative', $filter['dateline']); + } + else + { + $date = $lang->na; + } + + $table->construct_cell($filter['filter']); + $table->construct_cell($date, array("class" => "align_center")); + $table->construct_cell($last_use, array("class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_ban_deletion}');\">style}/images/icons/delete.png\" title=\"{$lang->delete}\" alt=\"{$lang->delete}\" />", array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_bans, array("colspan" => 4)); + $table->construct_row(); + } + + $table->output($title); + + $form = new Form("index.php?module=config-banning&action=add", "post", "add"); + + if($mybb->input['type'] == "usernames") + { + $form_container = new FormContainer($lang->add_disallowed_username); + $form_container->output_row($lang->username." *", $lang->username_desc, $form->generate_text_box('filter', $mybb->input['filter'], array('id' => 'filter')), 'filter'); + $buttons[] = $form->generate_submit_button($lang->disallow_username); + } + else if($mybb->input['type'] == "emails") + { + $form_container = new FormContainer($lang->add_disallowed_email_address); + $form_container->output_row($lang->email_address." *", $lang->email_address_desc, $form->generate_text_box('filter', $mybb->input['filter'], array('id' => 'filter')), 'filter'); + $buttons[] = $form->generate_submit_button($lang->disallow_email_address); + } + else + { + $form_container = new FormContainer($lang->ban_an_ip_address); + $form_container->output_row($lang->ip_address." *", $lang->ip_address_desc, $form->generate_text_box('filter', $mybb->input['filter'], array('id' => 'filter')), 'filter'); + $buttons[] = $form->generate_submit_button($lang->ban_ip_address); + } + + $form_container->end(); + echo $form->generate_hidden_field("type", $type); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + diff --git a/Upload/admin/modules/config/calendars.php b/Upload/admin/modules/config/calendars.php new file mode 100644 index 0000000..81001ab --- /dev/null +++ b/Upload/admin/modules/config/calendars.php @@ -0,0 +1,486 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->calendars, "index.php?module=config-calendars"); + +if($mybb->input['action'] == "add" || $mybb->input['action'] == "permissions" || !$mybb->input['action']) +{ + $sub_tabs['manage_calendars'] = array( + 'title' => $lang->manage_calendars, + 'link' => "index.php?module=config-calendars", + 'description' => $lang->manage_calendars_desc + ); + $sub_tabs['add_calendar'] = array( + 'title' => $lang->add_calendar, + 'link' => "index.php?module=config-calendars&action=add", + ); +} + +$plugins->run_hooks("admin_config_calendars_begin"); + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_config_calendars_add"); + + if($mybb->request_method == "post") + { + $plugins->run_hooks("admin_config_calendars_add_commit"); + + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_name; + } + + if(!isset($mybb->input['disporder'])) + { + $errors[] = $lang->error_missing_order; + } + + if(!$errors) + { + $calendar = array( + "name" => $db->escape_string($mybb->input['name']), + "disporder" => (int)$mybb->input['disporder'], + "startofweek" => (int)$mybb->input['startofweek'], + "eventlimit" => (int)$mybb->input['eventlimit'], + "showbirthdays" => (int)$mybb->input['showbirthdays'], + "moderation" => (int)$mybb->input['moderation'], + "allowhtml" => $db->escape_string($mybb->input['allowhtml']), + "allowmycode" => $db->escape_string($mybb->input['allowmycode']), + "allowimgcode" => $db->escape_string($mybb->input['allowimgcode']), + "allowvideocode" => $db->escape_string($mybb->input['allowvideocode']), + "allowsmilies" => $db->escape_string($mybb->input['allowsmilies']) + ); + + $plugins->run_hooks("admin_config_calendars_add_commit_start"); + + $cid = $db->insert_query("calendars", $calendar); + + $plugins->run_hooks("admin_config_calendars_add_commit_end"); + + // Log admin action + log_admin_action($cid, $mybb->input['name']); + + flash_message($lang->success_calendar_created, 'success'); + admin_redirect("index.php?module=config-calendars"); + } + } + else + { + $mybb->input = array_merge($mybb->input, array( + "allowhtml" => 0, + "eventlimit" => 4, + "disporder" => 1, + "moderation" => 0 + ) + ); + } + + $page->add_breadcrumb_item($lang->add_calendar); + $page->output_header($lang->calendars." - ".$lang->add_calendar); + + $sub_tabs['add_calendar'] = array( + 'title' => $lang->add_calendar, + 'link' => "index.php?module=config-calendars&action=add", + 'description' => $lang->add_calendar_desc + ); + + $page->output_nav_tabs($sub_tabs, 'add_calendar'); + $form = new Form("index.php?module=config-calendars&action=add", "post"); + + + if($errors) + { + $page->output_inline_error($errors); + } + + $form_container = new FormContainer($lang->add_calendar); + $form_container->output_row($lang->name." *", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->display_order, $lang->display_order_desc, $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder')), 'disporder'); + $select_list = array($lang->sunday, $lang->monday, $lang->tuesday, $lang->wednesday, $lang->thursday, $lang->friday, $lang->saturday); + $form_container->output_row($lang->week_start, $lang->week_start_desc, $form->generate_select_box('startofweek', $select_list, $mybb->input['startofweek'], array('id' => 'startofweek')), 'startofweek'); + $form_container->output_row($lang->event_limit, $lang->event_limit_desc, $form->generate_numeric_field('eventlimit', $mybb->input['eventlimit'], array('id' => 'eventlimit')), 'eventlimit'); + $form_container->output_row($lang->show_birthdays, $lang->show_birthdays_desc, $form->generate_yes_no_radio('showbirthdays', $mybb->input['showbirthdays'], true)); + $form_container->output_row($lang->moderate_events, $lang->moderate_events_desc, $form->generate_yes_no_radio('moderation', $mybb->input['moderation'], true)); + $form_container->output_row($lang->allow_html, "", $form->generate_yes_no_radio('allowhtml', $mybb->input['allowhtml'])); + $form_container->output_row($lang->allow_mycode, "", $form->generate_yes_no_radio('allowmycode', $mybb->input['allowmycode'])); + $form_container->output_row($lang->allow_img, "", $form->generate_yes_no_radio('allowimgcode', $mybb->input['allowimgcode'])); + $form_container->output_row($lang->allow_video, "", $form->generate_yes_no_radio('allowvideocode', $mybb->input['allowvideocode'])); + $form_container->output_row($lang->allow_smilies, "", $form->generate_yes_no_radio('allowsmilies', $mybb->input['allowsmilies'])); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_calendar); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "permissions") +{ + $usergroups = array(); + + $query = $db->simple_select("calendars", "*", "cid='".$mybb->get_input('cid', 1)."'"); + $calendar = $db->fetch_array($query); + + // Does the calendar not exist? + if(!$calendar['cid']) + { + flash_message($lang->error_invalid_calendar, 'error'); + admin_redirect("index.php?module=config-calendars"); + } + + $plugins->run_hooks("admin_config_calendars_permissions"); + + $query = $db->simple_select("usergroups", "*", "", array("order" => "name")); + while($usergroup = $db->fetch_array($query)) + { + $usergroups[$usergroup['gid']] = $usergroup; + } + + $query = $db->simple_select("calendarpermissions", "*", "cid='{$calendar['cid']}'"); + while($existing = $db->fetch_array($query)) + { + $existing_permissions[$existing['gid']] = $existing; + } + + if($mybb->request_method == "post") + { + foreach(array_keys($usergroups) as $group_id) + { + $permissions = $mybb->input['permissions'][$group_id]; + $db->delete_query("calendarpermissions", "cid='{$calendar['cid']}' AND gid='".(int)$group_id."'"); + + if(!$mybb->input['default_permissions'][$group_id]) + { + foreach(array('canviewcalendar','canaddevents','canbypasseventmod','canmoderateevents') as $calendar_permission) + { + if($permissions[$calendar_permission] == 1) + { + $permissions_array[$calendar_permission] = 1; + } + else + { + $permissions_array[$calendar_permission] = 0; + } + } + $permissions_array['gid'] = (int)$group_id; + $permissions_array['cid'] = $calendar['cid']; + $db->insert_query("calendarpermissions", $permissions_array); + } + } + + $plugins->run_hooks("admin_config_calendars_permissions_commit"); + + // Log admin action + log_admin_action($calendar['cid'], $calendar['name']); + + flash_message($lang->success_calendar_permissions_updated, 'success'); + admin_redirect("index.php?module=config-calendars"); + } + + $calendar['name'] = htmlspecialchars_uni($calendar['name']); + $page->add_breadcrumb_item($calendar['name'], "index.php?module=config-calendars&action=edit&cid={$calendar['cid']}"); + $page->add_breadcrumb_item($lang->permissions); + $page->output_header($lang->calendars." - ".$lang->edit_permissions); + + $form = new Form("index.php?module=config-calendars&action=permissions", "post"); + echo $form->generate_hidden_field("cid", $calendar['cid']); + + $table = new Table; + $table->construct_header($lang->permissions_group); + $table->construct_header($lang->permissions_view, array("class" => "align_center", "width" => "10%")); + $table->construct_header($lang->permissions_post_events, array("class" => "align_center", "width" => "10%")); + $table->construct_header($lang->permissions_bypass_moderation, array("class" => "align_center", "width" => "10%")); + $table->construct_header($lang->permissions_moderator, array("class" => "align_center", "width" => "10%")); + $table->construct_header($lang->permissions_all, array("class" => "align_center", "width" => "10%")); + + foreach($usergroups as $usergroup) + { + if($existing_permissions[$usergroup['gid']]) + { + $perms = $existing_permissions[$usergroup['gid']]; + $default_checked = false; + } + else + { + $perms = $usergroup; + $default_checked = true; + } + $perm_check = $all_check = ""; + $all_checked = true; + foreach(array('canviewcalendar','canaddevents','canbypasseventmod','canmoderateevents') as $calendar_permission) + { + if($usergroup[$calendar_permission] == 1) + { + $value = "this.checked"; + } + else + { + $value = "false"; + } + if($perms[$calendar_permission] != 1) + { + $all_checked = false; + } + if($perms[$calendar_permission] == 1) + { + $perms_checked[$calendar_permission] = 1; + } + else + { + $perms_checked[$calendar_permission] = 0; + } + $all_check .= "\$('#permissions_{$usergroup['gid']}_{$calendar_permission}').prop('checked', this.checked);\n"; + $perm_check .= "\$('#permissions_{$usergroup['gid']}_{$calendar_permission}').prop('checked', $value);\n"; + } + $default_click = "if(\$(this).is(':checked')) { $perm_check }"; + $reset_default = "if(!\$(this).is(':checked')) { \$('#permissions_{$usergroup['gid']}_all').prop('checked', false); }\n"; + $usergroup['title'] = htmlspecialchars_uni($usergroup['title']); + $table->construct_cell("{$usergroup['title']}
".$form->generate_check_box("default_permissions[{$usergroup['gid']}];", 1, "", array("id" => "default_permissions_{$usergroup['gid']}", "checked" => $default_checked, "onclick" => $default_click))." "); + $table->construct_cell($form->generate_check_box("permissions[{$usergroup['gid']}][canviewcalendar]", 1, "", array("id" => "permissions_{$usergroup['gid']}_canviewcalendar", "checked" => $perms_checked['canviewcalendar'], "onclick" => $reset_default)), array('class' => 'align_center')); + $table->construct_cell($form->generate_check_box("permissions[{$usergroup['gid']}][canaddevents]", 1, "", array("id" => "permissions_{$usergroup['gid']}_canaddevents", "checked" => $perms_checked['canaddevents'], "onclick" => $reset_default)), array('class' => 'align_center')); + $table->construct_cell($form->generate_check_box("permissions[{$usergroup['gid']}][canbypasseventmod]", 1, "", array("id" => "permissions_{$usergroup['gid']}_canbypasseventmod", "checked" => $perms_checked['canbypasseventmod'], "onclick" => $reset_default)), array('class' => 'align_center')); + $table->construct_cell($form->generate_check_box("permissions[{$usergroup['gid']}][canmoderateevents]", 1, "", array("id" => "permissions_{$usergroup['gid']}_canmoderateevents", "checked" => $perms_checked['canmoderateevents'], "onclick" => $reset_default)), array('class' => 'align_center')); + $table->construct_cell($form->generate_check_box("permissions[{$usergroup['gid']}][all]", 1, "", array("id" => "permissions_{$usergroup['gid']}_all", "checked" => $all_checked, "onclick" => $all_check)), array('class' => 'align_center')); + $table->construct_row(); + } + $table->output("{$lang->calendar_permissions_for} {$calendar['name']}"); + + if(!$no_results) + { + $buttons[] = $form->generate_submit_button($lang->save_permissions); + $form->output_submit_wrapper($buttons); + } + + $form->end(); + + $page->output_footer(); + +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("calendars", "*", "cid='".$mybb->get_input('cid', 1)."'"); + $calendar = $db->fetch_array($query); + + // Does the calendar not exist? + if(!$calendar['cid']) + { + flash_message($lang->error_invalid_calendar, 'error'); + admin_redirect("index.php?module=config-calendars"); + } + + $plugins->run_hooks("admin_config_calendars_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_name; + } + + if(!isset($mybb->input['disporder'])) + { + $errors[] = $lang->error_missing_order; + } + + if(!$errors) + { + $updated_calendar = array( + "name" => $db->escape_string($mybb->input['name']), + "disporder" => (int)$mybb->input['disporder'], + "startofweek" => (int)$mybb->input['startofweek'], + "eventlimit" => (int)$mybb->input['eventlimit'], + "showbirthdays" => (int)$mybb->input['showbirthdays'], + "moderation" => (int)$mybb->input['moderation'], + "allowhtml" => $db->escape_string($mybb->input['allowhtml']), + "allowmycode" => $db->escape_string($mybb->input['allowmycode']), + "allowimgcode" => $db->escape_string($mybb->input['allowimgcode']), + "allowvideocode" => $db->escape_string($mybb->input['allowvideocode']), + "allowsmilies" => $db->escape_string($mybb->input['allowsmilies']) + ); + + $plugins->run_hooks("admin_config_calendars_edit_commit"); + + $db->update_query("calendars", $updated_calendar, "cid = '".$mybb->get_input('cid', 1)."'"); + + // Log admin action + log_admin_action($calendar['cid'], $mybb->input['name']); + + flash_message($lang->success_calendar_updated, 'success'); + admin_redirect("index.php?module=config-calendars"); + } + } + + $page->add_breadcrumb_item($lang->edit_calendar); + $page->output_header($lang->calendars." - ".$lang->edit_calendar); + + $sub_tabs['edit_calendar'] = array( + 'title' => $lang->edit_calendar, + 'link' => "index.php?module=config-calendars&action=edit", + 'description' => $lang->edit_calendar_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_calendar'); + $form = new Form("index.php?module=config-calendars&action=edit", "post"); + + echo $form->generate_hidden_field("cid", $calendar['cid']); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input = $calendar; + } + + $form_container = new FormContainer($lang->edit_calendar); + $form_container->output_row($lang->name." *", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->display_order." *", $lang->display_order_desc, $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder')), 'disporder'); + $select_list = array($lang->sunday, $lang->monday, $lang->tuesday, $lang->wednesday, $lang->thursday, $lang->friday, $lang->saturday); + $form_container->output_row($lang->week_start, $lang->week_start_desc, $form->generate_select_box('startofweek', $select_list, $mybb->input['startofweek'], array('id' => 'startofweek')), 'startofweek'); + $form_container->output_row($lang->event_limit, $lang->event_limit_desc, $form->generate_numeric_field('eventlimit', $mybb->input['eventlimit'], array('id' => 'eventlimit')), 'eventlimit'); + $form_container->output_row($lang->show_birthdays, $lang->show_birthdays_desc, $form->generate_yes_no_radio('showbirthdays', $mybb->input['showbirthdays'], true)); + $form_container->output_row($lang->moderate_events, $lang->moderate_events_desc, $form->generate_yes_no_radio('moderation', $mybb->input['moderation'], true)); + $form_container->output_row($lang->allow_html, "", $form->generate_yes_no_radio('allowhtml', $mybb->input['allowhtml'])); + $form_container->output_row($lang->allow_mycode, "", $form->generate_yes_no_radio('allowmycode', $mybb->input['allowmycode'])); + $form_container->output_row($lang->allow_img, "", $form->generate_yes_no_radio('allowimgcode', $mybb->input['allowimgcode'])); + $form_container->output_row($lang->allow_video, "", $form->generate_yes_no_radio('allowvideocode', $mybb->input['allowvideocode'])); + $form_container->output_row($lang->allow_smilies, "", $form->generate_yes_no_radio('allowsmilies', $mybb->input['allowsmilies'])); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_calendar); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("calendars", "*", "cid='".$mybb->get_input('cid', 1)."'"); + $calendar = $db->fetch_array($query); + + // Does the calendar not exist? + if(!$calendar['cid']) + { + flash_message($lang->error_invalid_calendar, 'error'); + admin_redirect("index.php?module=config-calendars"); + } + + $plugins->run_hooks("admin_config_calendars_delete"); + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-calendars"); + } + + if($mybb->request_method == "post") + { + // Delete the calendar + $db->delete_query("calendars", "cid='{$calendar['cid']}'"); + $db->delete_query("calendarpermissions", "cid='{$calendar['cid']}'"); + $db->delete_query("events", "cid='{$calendar['cid']}'"); + + $plugins->run_hooks("admin_config_calendars_delete_commit"); + + // Log admin action + log_admin_action($calendar['cid'], $calendar['name']); + + flash_message($lang->success_calendar_deleted, 'success'); + admin_redirect("index.php?module=config-calendars"); + } + else + { + $page->output_confirm_action("index.php?module=config-calendars&action=delete&cid={$calendar['cid']}", $lang->confirm_calendar_deletion); + } +} + +if($mybb->input['action'] == "update_order" && $mybb->request_method == "post") +{ + if(!is_array($mybb->input['disporder'])) + { + admin_redirect("index.php?module=config-calendars"); + } + + $plugins->run_hooks("admin_config_calendars_update_order"); + + foreach($mybb->input['disporder'] as $cid => $order) + { + $update_query = array( + "disporder" => (int)$order + ); + $db->update_query("calendars", $update_query, "cid='".(int)$cid."'"); + } + + $plugins->run_hooks("admin_config_calendars_update_order_commit"); + + // Log admin action + log_admin_action(); + + flash_message($lang->success_calendar_orders_updated, 'success'); + admin_redirect("index.php?module=config-calendars"); +} + +if(!$mybb->input['action']) +{ + $page->output_header($lang->manage_calendars); + + $page->output_nav_tabs($sub_tabs, 'manage_calendars'); + + $form = new Form("index.php?module=config-calendars&action=update_order", "post"); + $table = new Table; + $table->construct_header($lang->calendar); + $table->construct_header($lang->order, array('width' => '5%', 'class' => 'align_center')); + $table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 3, "width" => 300)); + + $query = $db->simple_select("calendars", "*", "", array('order_by' => 'disporder')); + while($calendar = $db->fetch_array($query)) + { + $calendar['name'] = htmlspecialchars_uni($calendar['name']); + $table->construct_cell("{$calendar['name']}"); + $table->construct_cell($form->generate_numeric_field("disporder[{$calendar['cid']}]", $calendar['disporder'], array('id' => 'disporder', 'style' => 'width: 80%', 'class' => 'align_center'))); + $table->construct_cell("{$lang->edit}", array("width" => 100, "class" => "align_center")); + $table->construct_cell("{$lang->permissions}", array("width" => 100, "class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_calendar_deletion}')\">{$lang->delete}", array("width" => 100, "class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_calendars, array('colspan' => 5)); + $table->construct_row(); + $no_results = true; + } + + $table->output($lang->manage_calendars); + + if(!$no_results) + { + $buttons[] = $form->generate_submit_button($lang->save_calendar_orders); + $form->output_submit_wrapper($buttons); + } + + $form->end(); + + $page->output_footer(); +} + diff --git a/Upload/admin/modules/config/help_documents.php b/Upload/admin/modules/config/help_documents.php new file mode 100644 index 0000000..ef058df --- /dev/null +++ b/Upload/admin/modules/config/help_documents.php @@ -0,0 +1,624 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->help_documents, "index.php?module=config-help_documents"); + +$plugins->run_hooks("admin_config_help_documents_begin"); + +// Add something +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_config_help_documents_add"); + + // Add section + if($mybb->input['type'] == "section") + { + $plugins->run_hooks("admin_config_help_documents_add_section"); + + // Do add? + if($mybb->request_method == "post") + { + if(empty($mybb->input['name'])) + { + $errors[] = $lang->error_section_missing_name; + } + + if(empty($mybb->input['description'])) + { + $errors[] = $lang->error_section_missing_description; + } + + if(!isset($mybb->input['enabled'])) + { + $errors[] = $lang->error_section_missing_enabled; + } + + if($mybb->input['enabled'] != 1) + { + $mybb->input['enabled'] = 0; + } + + if(!is_array($errors)) + { + $sql_array = array( + "name" => $db->escape_string($mybb->input['name']), + "description" => $db->escape_string($mybb->input['description']), + "usetranslation" => (int)$mybb->input['usetranslation'], + "enabled" => (int)$mybb->input['enabled'], + "disporder" => (int)$mybb->input['disporder'] + ); + + $sid = $db->insert_query("helpsections", $sql_array); + + $plugins->run_hooks("admin_config_help_documents_add_section_commit"); + + // Log admin action + log_admin_action($sid, $mybb->input['name'], 'section'); + + flash_message($lang->success_help_section_added, 'success'); + admin_redirect('index.php?module=config-help_documents'); + } + } + + $page->add_breadcrumb_item($lang->add_new_section); + $page->output_header($lang->help_documents." - ".$lang->add_new_section); + + $sub_tabs['manage_help_documents'] = array( + 'title' => $lang->manage_help_documents, + 'link' => "index.php?module=config-help_documents" + ); + + $sub_tabs['add_help_document'] = array( + 'title' => $lang->add_new_document, + 'link' => "index.php?module=config-help_documents&action=add&type=document" + ); + + $sub_tabs['add_help_section'] = array( + 'title' => $lang->add_new_section, + 'link' => "index.php?module=config-help_documents&action=add&type=section", + 'description' => $lang->add_new_section_desc + ); + + $page->output_nav_tabs($sub_tabs, 'add_help_section'); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $query = $db->simple_select("helpsections", "MAX(disporder) as maxdisp"); + $mybb->input['disporder'] = $db->fetch_field($query, "maxdisp")+1; + $mybb->input['enabled'] = 1; + $mybb->input['usetranslation'] = 1; + } + + $form = new Form("index.php?module=config-help_documents&action=add&type=section", "post", "add"); + echo $form->generate_hidden_field("usetranslation", $mybb->input['usetranslation']); + + $form_container = new FormContainer($lang->add_new_section); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->short_description." *", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + $form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder')), 'disporder'); + $form_container->output_row($lang->enabled." *", "", $form->generate_yes_no_radio('enabled', $mybb->input['enabled'])); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_section); + + $form->output_submit_wrapper($buttons); + $form->end(); + } + + // Add page + else + { + $plugins->run_hooks("admin_config_help_documents_add_page"); + + // Do add? + if($mybb->request_method == "post") + { + if(empty($mybb->input['sid'])) + { + $errors[] = $lang->error_missing_sid; + } + + if(empty($mybb->input['name'])) + { + $errors[] = $lang->error_document_missing_name; + } + + if(empty($mybb->input['description'])) + { + $errors[] = $lang->error_document_missing_description; + } + + if(empty($mybb->input['document'])) + { + $errors[] = $lang->error_document_missing_document; + } + + if(!isset($mybb->input['enabled'])) + { + $errors[] = $lang->error_document_missing_enabled; + } + + if($mybb->input['enabled'] != 1) + { + $mybb->input['enabled'] = 0; + } + + if(!is_array($errors)) + { + $sql_array = array( + "sid" => $mybb->get_input('sid', 1), + "name" => $db->escape_string($mybb->input['name']), + "description" => $db->escape_string($mybb->input['description']), + "document" => $db->escape_string($mybb->input['document']), + "usetranslation" => (int)$mybb->input['usetranslation'], + "enabled" => (int)$mybb->input['enabled'], + "disporder" => (int)$mybb->input['disporder'] + ); + + $hid = $db->insert_query("helpdocs", $sql_array); + + $plugins->run_hooks("admin_config_help_documents_add_page_commit"); + + // Log admin action + log_admin_action($hid, $mybb->input['name'], 'document'); + + flash_message($lang->success_help_document_added, 'success'); + admin_redirect('index.php?module=config-help_documents'); + } + } + + $page->add_breadcrumb_item($lang->add_new_document); + $page->output_header($lang->help_documents." - ".$lang->add_new_document); + + $sub_tabs['manage_help_documents'] = array( + 'title' => $lang->manage_help_documents, + 'link' => "index.php?module=config-help_documents" + ); + + $sub_tabs['add_help_document'] = array( + 'title' => $lang->add_new_document, + 'link' => "index.php?module=config-help_documents&action=add&type=document", + 'description' => $lang->add_new_document_desc + ); + + $sub_tabs['add_help_section'] = array( + 'title' => $lang->add_new_section, + 'link' => "index.php?module=config-help_documents&action=add&type=section" + ); + + $page->output_nav_tabs($sub_tabs, 'add_help_document'); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + // Select the largest existing display order + $query = $db->simple_select("helpdocs", "MAX(disporder) as maxdisp"); + $mybb->input['disporder'] = $db->fetch_field($query, "maxdisp")+1; + $mybb->input['enabled'] = 1; + $mybb->input['usetranslation'] = 1; + } + + $form = new Form("index.php?module=config-help_documents&action=add&type=document", "post", "add"); + echo $form->generate_hidden_field("usetranslation", $mybb->input['usetranslation']); + + $form_container = new FormContainer($lang->add_new_document); + $query = $db->simple_select("helpsections", "sid, name"); + + $sections = array(); + while($section = $db->fetch_array($query)) + { + $sections[$section['sid']] = $section['name']; + } + $form_container->output_row($lang->section." *", "", $form->generate_select_box("sid", $sections, $mybb->input['sid'], array('id' => 'sid')), 'sid'); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->short_description." *", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + $form_container->output_row($lang->document." *", "", $form->generate_text_area('document', $mybb->input['document'], array('id' => 'document')), 'document'); + $form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder')), 'disporder'); + $form_container->output_row($lang->enabled." *", "", $form->generate_yes_no_radio('enabled', $mybb->input['enabled'])); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_document); + + $form->output_submit_wrapper($buttons); + $form->end(); + } + + $page->output_footer(); +} + +// Edit something +if($mybb->input['action'] == "edit") +{ + $plugins->run_hooks("admin_config_help_documents_edit"); + + // Edit a section + if($mybb->input['sid'] && !$mybb->input['hid']) + { + $query = $db->simple_select("helpsections", "*", "sid = '".$mybb->get_input('sid', 1)."'"); + $section = $db->fetch_array($query); + + $plugins->run_hooks("admin_config_help_documents_edit_section"); + + // Do edit? + if($mybb->request_method == "post") + { + $sid = $mybb->get_input('sid', 1); + + if(empty($sid)) + { + $errors[] = $lang->error_invalid_sid; + } + + if(empty($mybb->input['name'])) + { + $errors[] = $lang->error_section_missing_name; + } + + if(empty($mybb->input['description'])) + { + $errors[] = $lang->error_section_missing_description; + } + + if(!isset($mybb->input['enabled'])) + { + $errors[] = $lang->error_section_missing_enabled; + } + + if($mybb->input['enabled'] != 1) + { + $mybb->input['enabled'] = 0; + } + + if(!is_array($errors)) + { + $sql_array = array( + "name" => $db->escape_string($mybb->input['name']), + "description" => $db->escape_string($mybb->input['description']), + "usetranslation" => (int)$mybb->input['usetranslation'], + "enabled" => (int)$mybb->input['enabled'], + "disporder" => (int)$mybb->input['disporder'] + ); + + $plugins->run_hooks("admin_config_help_documents_edit_section_commit"); + + $db->update_query("helpsections", $sql_array, "sid = '{$sid}'"); + + // Log admin action + log_admin_action($sid, $mybb->input['name'], 'section'); + + flash_message($lang->success_help_section_updated, 'success'); + admin_redirect('index.php?module=config-help_documents'); + } + } + + $page->add_breadcrumb_item($lang->edit_section); + $page->output_header($lang->help_documents." - ".$lang->edit_section); + + + $sub_tabs['edit_help_section'] = array( + 'title' => $lang->edit_section, + 'link' => "index.php?module=config-help_documents&action=edit&sid=".$mybb->get_input('sid', 1), + 'description' => $lang->edit_section_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_help_section'); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['sid'] = $section['sid']; + $mybb->input['name'] = $section['name']; + $mybb->input['description'] = $section['description']; + $mybb->input['disporder'] = $section['disporder']; + $mybb->input['enabled'] = $section['enabled']; + $mybb->input['usetranslation'] = $section['usetranslation']; + } + + $form = new Form("index.php?module=config-help_documents&action=edit", "post", "edit"); + + echo $form->generate_hidden_field("sid", $mybb->input['sid']); + echo $form->generate_hidden_field("usetranslation", $mybb->input['usetranslation']); + + $form_container = new FormContainer($lang->edit_section." ({$lang->id} ".$mybb->get_input('sid', 1).")"); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->short_description." *", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + $form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder')), 'disporder'); + $form_container->output_row($lang->enabled." *", "", $form->generate_yes_no_radio('enabled', $mybb->input['enabled'])); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->edit_section); + + $form->output_submit_wrapper($buttons); + $form->end(); + } + + // Edit document + else + { + $plugins->run_hooks("admin_config_help_documents_edit_page"); + + // Do edit? + if($mybb->request_method == "post") + { + $hid = (int)$mybb->input['hid']; + + if(empty($hid)) + { + $errors[] = $lang->error_invalid_sid; + } + + if(empty($mybb->input['name'])) + { + $errors[] = $lang->error_document_missing_name; + } + + if(empty($mybb->input['description'])) + { + $errors[] = $lang->error_document_missing_description; + } + + if(empty($mybb->input['document'])) + { + $errors[] = $lang->error_document_missing_document; + } + + if(!isset($mybb->input['enabled'])) + { + $errors[] = $lang->error_document_missing_enabled; + } + + if($mybb->input['enabled'] != 1) + { + $mybb->input['enabled'] = 0; + } + + if(!is_array($errors)) + { + $sql_array = array( + "sid" => $mybb->get_input('sid', 1), + "name" => $db->escape_string($mybb->input['name']), + "description" => $db->escape_string($mybb->input['description']), + "document" => $db->escape_string($mybb->input['document']), + "usetranslation" => (int)$mybb->input['usetranslation'], + "enabled" => (int)$mybb->input['enabled'], + "disporder" => (int)$mybb->input['disporder'] + ); + + $plugins->run_hooks("admin_config_help_documents_edit_page_commit"); + + $db->update_query("helpdocs", $sql_array, "hid = '{$hid}'"); + + // Log admin action + log_admin_action($hid, $mybb->input['name'], 'document'); + + flash_message($lang->success_help_document_updated, 'success'); + admin_redirect('index.php?module=config-help_documents'); + } + } + + $page->add_breadcrumb_item($lang->edit_document); + $page->output_header($lang->help_documents." - ".$lang->edit_document); + + + $sub_tabs['edit_help_document'] = array( + 'title' => $lang->edit_document, + 'link' => "index.php?module=config-help_documents&action=edit&hid=".(int)$mybb->input['hid'], + 'description' => $lang->edit_document_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_help_document'); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $query = $db->simple_select("helpdocs", "*", "hid = '".(int)$mybb->input['hid']."'"); + $doc = $db->fetch_array($query); + $mybb->input['hid'] = $doc['hid']; + $mybb->input['sid'] = $doc['sid']; + $mybb->input['name'] = $doc['name']; + $mybb->input['description'] = $doc['description']; + $mybb->input['document'] = $doc['document']; + $mybb->input['disporder'] = $doc['disporder']; + $mybb->input['enabled'] = $doc['enabled']; + $mybb->input['usetranslation'] = $doc['usetranslation']; + } + + $form = new Form("index.php?module=config-help_documents&action=edit", "post", "edit"); + + echo $form->generate_hidden_field("hid", $mybb->input['hid']); + echo $form->generate_hidden_field("usetranslation", $mybb->input['usetranslation']); + + $form_container = new FormContainer($lang->edit_document." ({$lang->id} ".(int)$mybb->input['hid'].")"); + + $sections = array(); + $query = $db->simple_select("helpsections", "sid, name"); + while($section = $db->fetch_array($query)) + { + $sections[$section['sid']] = $section['name']; + } + $form_container->output_row($lang->section." *", "", $form->generate_select_box("sid", $sections, $mybb->input['sid']), 'sid'); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->short_description." *", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + $form_container->output_row($lang->document." *", "", $form->generate_text_area('document', $mybb->input['document'], array('id' => 'document')), 'document'); + $form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder')), 'disporder'); + $form_container->output_row($lang->enabled." *", "", $form->generate_yes_no_radio('enabled', $mybb->input['enabled'])); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->edit_document); + + $form->output_submit_wrapper($buttons); + $form->end(); + } + + $page->output_footer(); +} + +// Delete something +if($mybb->input['action'] == "delete") +{ + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-help_documents"); + } + + $plugins->run_hooks("admin_config_help_documents_delete"); + + // Do delete something? + if($mybb->request_method == "post") + { + // Delete section + if(isset($mybb->input['sid'])) + { + $sid = $mybb->get_input('sid', 1); + + $query = $db->simple_select("helpsections", "*", "sid='{$sid}'"); + $section = $db->fetch_array($query); + + // Invalid section? + if(!$section['sid']) + { + flash_message($lang->error_missing_section_id, 'error'); + admin_redirect("index.php?module=config-help_documents"); + } + + // Delete section and its documents + $db->delete_query("helpsections", "sid = '{$sid}'", 1); + $db->delete_query("helpdocs", "sid = '{$sid}'"); + + $plugins->run_hooks("admin_config_help_documents_delete_section_commit"); + + // Log admin action + log_admin_action($section['sid'], $section['name'], 'section'); + + flash_message($lang->success_section_deleted, 'success'); + admin_redirect("index.php?module=config-help_documents"); + } + + // Delete document + else + { + $hid = (int)$mybb->input['hid']; + + $query = $db->simple_select("helpdocs", "*", "hid='{$hid}'"); + $doc = $db->fetch_array($query); + + // Invalid document? + if(!$doc['hid']) + { + flash_message($lang->error_missing_hid, 'error'); + admin_redirect("index.php?module=config-help_documents"); + } + + $db->delete_query("helpdocs", "hid = '{$hid}'", 1); + + $plugins->run_hooks("admin_config_help_documents_delete_page_commit"); + + // Log admin action + log_admin_action($doc['hid'], $doc['name'], 'document'); + + flash_message($lang->success_document_deleted, 'success'); + admin_redirect("index.php?module=config-help_documents"); + } + } + // Show form for deletion + else + { + // Section + if(isset($mybb->input['sid'])) + { + $sid = $mybb->get_input('sid', 1); + $page->output_confirm_action("index.php?module=config-help_documents&action=delete&sid={$sid}", $lang->confirm_section_deletion); + } + // Document + else + { + $hid = (int)$mybb->input['hid']; + $page->output_confirm_action("index.php?module=config-help_documents&action=delete&hid={$hid}", $lang->confirm_document_deletion); + } + } +} + +// List document and sections +if(!$mybb->input['action']) +{ + $page->output_header($lang->help_documents); + + $sub_tabs['manage_help_documents'] = array( + 'title' => $lang->manage_help_documents, + 'link' => "index.php?module=config-help_documents", + 'description'=> $lang->manage_help_documents_desc + ); + + $sub_tabs['add_help_document'] = array( + 'title' => $lang->add_new_document, + 'link' => "index.php?module=config-help_documents&action=add&type=document" + ); + + $sub_tabs['add_help_section'] = array( + 'title' => $lang->add_new_section, + 'link' => "index.php?module=config-help_documents&action=add&type=section" + ); + + $plugins->run_hooks("admin_config_help_documents_start"); + + $page->output_nav_tabs($sub_tabs, 'manage_help_documents'); + + $table = new Table; + $table->construct_header($lang->section_document); + $table->construct_header($lang->controls, array('class' => "align_center", 'colspan' => 2, "width" => "150")); + + $query = $db->simple_select("helpsections", "*", "", array('order_by' => "disporder")); + while($section = $db->fetch_array($query)) + { + $table->construct_cell("
{$section['name']}
{$section['description']}
"); + $table->construct_cell("{$lang->edit}", array("class" => "align_center", "width" => '60')); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_section_deletion}')\">{$lang->delete}", array("class" => "align_center", "width" => '90')); + $table->construct_row(); + + $query2 = $db->simple_select("helpdocs", "*", "sid='{$section['sid']}'", array('order_by' => "disporder")); + while($doc = $db->fetch_array($query2)) + { + $table->construct_cell("
{$doc['name']}
{$doc['description']}
"); + $table->construct_cell("{$lang->edit}", array("class" => "align_center", "width" => '60')); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_document_deletion}')\">{$lang->delete}", array("class" => "align_center", "width" => '90')); + $table->construct_row(); + } + } + + // No documents message + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_help_documents, array('colspan' => 3)); + $table->construct_row(); + } + + $table->output($lang->help_documents); + $page->output_footer(); +} diff --git a/Upload/admin/modules/config/index.html b/Upload/admin/modules/config/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/modules/config/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/modules/config/languages.php b/Upload/admin/modules/config/languages.php new file mode 100644 index 0000000..dd556c6 --- /dev/null +++ b/Upload/admin/modules/config/languages.php @@ -0,0 +1,1052 @@ +
Please make sure IN_MYBB is defined."); +} + +$languages = $lang->get_languages(); + +$page->add_breadcrumb_item($lang->languages, "index.php?module=config-languages"); + +$plugins->run_hooks("admin_config_languages_begin"); + +if($mybb->input['action'] == "edit_properties") +{ + $editlang = basename($mybb->input['lang']); + $file = MYBB_ROOT."inc/languages/".$editlang.".php"; + if(!file_exists($file)) + { + flash_message($lang->error_invalid_file, 'error'); + admin_redirect("index.php?module=config-languages"); + } + + $plugins->run_hooks("admin_config_languages_edit_properties"); + + if($mybb->request_method == "post") + { + if(!is_writable($file)) + { + flash_message($lang->error_cannot_write_to_file, 'error'); + admin_redirect("index.php?module=config-languages"); + } + + foreach($mybb->input['info'] as $key => $info) + { + $info = str_replace("\\", "\\\\", $info); + $info = str_replace('$', '\$', $info); + + if($key == 'admin' || $key == 'rtl') + { + $info = (int)$info; + } + + $newlanginfo[$key] = str_replace("\"", '\"', $info); + } + + // Get contents of existing file + require $file; + + // Make the contents of the new file + $newfile = " on all pages +\$langinfo['htmllang'] = \"{$newlanginfo['htmllang']}\"; + +// Sets the character set, blank uses the default. +\$langinfo['charset'] = \"{$newlanginfo['charset']}\";\n"; + + // Put it in! + if($file = fopen($file, "w")) + { + fwrite($file, $newfile); + fclose($file); + + $plugins->run_hooks("admin_config_languages_edit_properties_commit"); + + // Log admin action + log_admin_action($editlang); + + flash_message($lang->success_langprops_updated, 'success'); + admin_redirect("index.php?module=config-languages&action=edit&lang={$editlang}&editwith={$editwith}"); + } + else + { + $errors[] = $lang->error_cannot_write_to_file; + } + } + + $page->add_breadcrumb_item(preg_replace("<\?|\?>", "?", $languages[$editlang]), "index.php?module=config-languages&action=edit&lang={$editlang}"); + $page->add_breadcrumb_item($lang->nav_editing_set); + + $page->output_header($lang->languages); + + $sub_tabs['edit_properties'] = array( + "title" => $lang->edit_properties, + "link" => "index.php?module=config-languages", + "description" => $lang->edit_properties_desc + ); + $page->output_nav_tabs($sub_tabs, "edit_properties"); + + // Get language info + require $file; + + $form = new Form("index.php?module=config-languages&action=edit_properties", "post", "editset"); + echo $form->generate_hidden_field("lang", $editlang); + echo $form->generate_hidden_field("info[author]", $langinfo['author']); + echo $form->generate_hidden_field("info[website]", $langinfo['website']); + echo $form->generate_hidden_field("info[version]", $langinfo['version']); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + if($langinfo['admin']) + { + $mybb->input['info']['admin'] = 1; + } + else + { + $mybb->input['info']['admin'] = 0; + } + + if($langinfo['rtl']) + { + $mybb->input['info']['rtl'] = 1; + } + else + { + $mybb->input['info']['rtl'] = 0; + } + + $mybb->input['info']['name'] = $langinfo['name']; + $mybb->input['info']['htmllang'] = $langinfo['htmllang']; + $mybb->input['info']['charset'] = $langinfo['charset']; + } + + $form_container = new FormContainer($lang->edit_properties); + + $form_container->output_row($lang->friendly_name." *", "", $form->generate_text_box('info[name]', $mybb->input['info']['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->language_in_html." *", "", $form->generate_text_box('info[htmllang]', $mybb->input['info']['htmllang'], array('id' => 'htmllang')), 'htmllang'); + $form_container->output_row($lang->charset." *", "", $form->generate_text_box('info[charset]', $mybb->input['info']['charset'], array('id' => 'charset')), 'charset'); + $form_container->output_row($lang->rtl." *", "", $form->generate_yes_no_radio('info[rtl]', $mybb->input['info']['rtl'], array('id' => 'rtl')), 'rtl'); + $form_container->output_row($lang->admin." *", "", $form->generate_yes_no_radio('info[admin]', $mybb->input['info']['admin'], array('id' => 'admin')), 'admin'); + + // Check if file is writable, before allowing submission + if(!is_writable($file)) + { + $no_write = 1; + $page->output_alert($lang->alert_note_cannot_write); + } + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_language_file, array('disabled' => $no_write)); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "quick_phrases") +{ + // Validate input + $editlang = basename($mybb->input['lang']); + $folder = MYBB_ROOT."inc/languages/".$editlang."/"; + + $page->add_breadcrumb_item(preg_replace("<\?|\?>", "?", $languages[$editlang]), "index.php?module=config-languages&action=quick_edit&lang={$editlang}"); + + // Validate that this language pack really exists + if(file_exists(MYBB_ROOT."inc/languages/".$editlang.".php")) + { + // Then validate language pack folders (and try to fix them if missing) + @mkdir($folder); + @mkdir($folder."admin"); + } + + if(!file_exists($folder) || !file_exists($folder."admin")) + { + flash_message($lang->error_folders_fail, 'error'); + admin_redirect("index.php?module=config-languages"); + } + + $plugins->run_hooks("admin_config_languages_quick_phrases"); + + $quick_phrases = array( + 'member.lang.php' => array( + 'agreement' => $lang->quickphrases_agreement, + 'agreement_1' => $lang->quickphrases_agreement_1, + 'agreement_2' => $lang->quickphrases_agreement_2, + 'agreement_3' => $lang->quickphrases_agreement_3, + 'agreement_4' => $lang->quickphrases_agreement_4, + 'agreement_5' => $lang->quickphrases_agreement_5 + ), + 'messages.lang.php' => array( + 'error_nopermission_guest_1' => $lang->quickphrases_error_nopermission_guest_1, + 'error_nopermission_guest_2' => $lang->quickphrases_error_nopermission_guest_2, + 'error_nopermission_guest_3' => $lang->quickphrases_error_nopermission_guest_3, + 'error_nopermission_guest_4' => $lang->quickphrases_error_nopermission_guest_4 + ) + ); + + if($mybb->request_method == 'post') + { + if($mybb->request_method == 'post') + { + // We have more than one file to edit, lets set flag for all of them. + $editsuccess = true; + foreach($quick_phrases as $file => $phrases) + { + @include $folder.$file; + $contents_file = (array)$l; + unset($l); + + foreach($phrases as $key => $value) + { + // validation - we fetch from input only variables that are defined in $quick_phrases array + $contents_file[$key] = $mybb->input['edit'][$key]; + } + // Save edited language file + if($fp = @fopen($folder.$file, "w")) + { + // We need info about edited language files to generate credits for our file + require MYBB_ROOT."inc/languages/".$editlang.".php"; + + // Lets make nice credits header in language file + $lang_file_credits = "#i", " ", $langinfo['name'])."\n"; + $lang_file_credits .= "// Author of the language pack : ".preg_replace("#<\?|\?>#i", " ", $langinfo['author'])."\n"; + $lang_file_credits .= "// Language pack translators website : ".preg_replace("#<\?|\?>#i", " ", $langinfo['website'])."\n"; + $lang_file_credits .= "// Compatible version of MyBB : ".preg_replace("#<\?|\?>#i", " ", $langinfo['version'])."\n"; + $lang_file_credits .= "// Last edited in MyBB Editor by : ".preg_replace("#<\?|\?>#i", " ", $mybb->user['username'])."\n"; + $lang_file_credits .= "// Last edited date : ".gmdate("r")."\n"; + $lang_file_credits .= "// ".str_repeat('-',80)."\n\n"; + + $contents_wfile = $lang_file_credits; + foreach($contents_file as $key => $value) + { + $contents_wfile .= "\$l['".$key."'] = ".var_export($value, true).";\n"; + } + + flock($fp, LOCK_EX); + fwrite($fp, $contents_wfile); + flock($fp, LOCK_UN); + fclose($fp); + } + else + { + // One of files failed + $editsuccess = false; + } + } + + if($editsuccess == true) + { + // Log admin action + log_admin_action($editlang); + + flash_message($lang->success_quickphrases_updated, 'success'); + admin_redirect('index.php?module=config-languages&action=edit&lang='.$editlang); + } + } + } + + $page->output_header($lang->languages); + + $sub_tabs['language_files'] = array( + 'title' => $lang->language_files, + 'link' => "index.php?module=config-languages&action=edit&lang=".$editlang, + 'description' => $lang->language_files_desc + ); + + $sub_tabs['quick_phrases'] = array( + 'title' => $lang->quick_phrases, + 'link' => "index.php?module=config-languages&action=quick_phrases&lang=".$editlang, + 'description' => $lang->quick_phrases_desc + ); + + $page->output_nav_tabs($sub_tabs, 'quick_phrases'); + + $form = new Form('index.php?module=config-languages&action=quick_phrases&lang='.$editlang, 'post', 'quick_phrases'); + + if($errors) + { + $page->output_inline_error($errors); + } + + $table = new Table; + + // Check if files are writable, before allowing submission + $no_write = null; + foreach($quick_phrases as $file => $phrases) + { + if(file_exists($folder.$file) && !is_writable($folder.$file) || !is_writable($folder)) + { + $no_write = 1; + } + } + + if($no_write) + { + $page->output_alert($lang->alert_note_cannot_write); + } + + $form_container = new FormContainer($lang->quick_phrases); + + foreach($quick_phrases as $file => $phrases) + { + unset($langinfo); + @include MYBB_ROOT."inc/languages/".$editlang.".php"; + $quickphrases_dir_class = " langeditor_ltr"; + if((int)$langinfo['rtl'] > 0) + { + $quickphrases_dir_class = " langeditor_rtl"; + } + + @include $folder.$file; + foreach($phrases as $phrase => $description) + { + $value = $l[$phrase]; + if(my_strtolower($langinfo['charset']) == "utf-8") + { + $value = preg_replace_callback("#%u([0-9A-F]{1,4})#i", create_function('$matches', 'return dec_to_utf8(hexdec($matches[1]));'), $value); + } + else + { + $value = preg_replace_callback("#%u([0-9A-F]{1,4})#i", create_function('$matches', 'return "&#".hexdec($matches[1]).";";'), $value); + } + + $form_container->output_row($description, $phrase, $form->generate_text_area("edit[$phrase]", $value, array('id' => 'lang_'.$phrase, 'rows' => 2, 'class' => "langeditor_textarea_edit {$quickphrases_dir_class}")), 'lang_'.$phrase, array('width' => '50%')); + } + } + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_language_file, array('disabled' => $no_write)); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit") +{ + // Validate input + $editlang = basename($mybb->input['lang']); + $folder = MYBB_ROOT."inc/languages/".$editlang."/"; + + $page->add_breadcrumb_item(preg_replace("<\?|\?>", "?", $languages[$editlang]), "index.php?module=config-languages&action=edit&lang={$editlang}"); + + $editwith = basename($mybb->input['editwith']); + $editwithfolder = ''; + + if($editwith) + { + $editwithfolder = MYBB_ROOT."inc/languages/".$editwith."/"; + } + + // Validate that edited language pack really exists + if(file_exists(MYBB_ROOT."inc/languages/".$editlang.".php")) + { + // Then validate edited language pack folders (and try to fix them if missing) + @mkdir($folder); + @mkdir($folder."admin"); + } + + if(!file_exists($folder) || !file_exists($folder."admin")) + { + flash_message($lang->error_folders_fail, 'error'); + admin_redirect("index.php?module=config-languages"); + } + + // If we edit in compare mode, verify that at least folders of compared language exists + if($editwithfolder && (!file_exists($editwithfolder) || !file_exists($editwithfolder))) + { + flash_message($lang->error_invalid_set, 'error'); + admin_redirect("index.php?module=config-languages"); + } + + $plugins->run_hooks("admin_config_languages_edit"); + + if(isset($mybb->input['file'])) + { + // Validate input + $file = basename($mybb->input['file']); + if($mybb->input['inadmin'] == 1) + { + $file = 'admin/'.$file; + } + $page->add_breadcrumb_item($file); + + $editfile = $folder.$file; + $withfile = ''; + + $editwithfile = ''; + if($editwithfolder) + { + $editwithfile = $editwithfolder.$file; + } + + if($mybb->request_method == "post") + { + // Save edited phrases to language file + + // To validate input - build array of keys that allready exist in files + @include $editfile; + $valid_keys = (array)$l; + unset($l); + @include $editwithfile; + $valid_keys = array_merge($valid_keys, (array)$l); + unset($l); + + // Then fetch from input only valid keys + foreach($valid_keys as $key => $value) + { + $contents_wfile .= "\$l['".$key."'] = ".var_export($mybb->input['edit'][$key], true).";\n"; + } + + // Save edited language file + if($fp = @fopen($editfile, "w")) + { + // We need info about edited language files to generate credits for our file + require MYBB_ROOT."inc/languages/".$editlang.".php"; + + // Lets make nice credits header in language file + $lang_file_credits = "#i", " ", $langinfo['name'])."\n"; + $lang_file_credits .= "// Author of the language pack : ".preg_replace("#<\?|\?>#i", " ", $langinfo['author'])."\n"; + $lang_file_credits .= "// Language pack translators website : ".preg_replace("#<\?|\?>#i", " ", $langinfo['website'])."\n"; + $lang_file_credits .= "// Compatible version of MyBB : ".preg_replace("#<\?|\?>#i", " ", $langinfo['version'])."\n"; + $lang_file_credits .= "// Last edited in MyBB Editor by : ".preg_replace("#<\?|\?>#i", " ", $mybb->user['username'])."\n"; + $lang_file_credits .= "// Last edited date : ".gmdate("r")."\n"; + $lang_file_credits .= "// ".str_repeat('-',80)."\n\n"; + + $contents_wfile = $lang_file_credits.$contents_wfile; + + flock($fp, LOCK_EX); + fwrite($fp, $contents_wfile); + flock($fp, LOCK_UN); + fclose($fp); + + $plugins->run_hooks("admin_config_languages_edit_commit"); + + // Log admin action + log_admin_action($editlang, $editfile, (int)$mybb->input['inadmin']); + + flash_message($lang->success_langfile_updated, 'success'); + admin_redirect("index.php?module=config-languages&action=edit&lang={$editlang}&editwith={$editwith}"); + } + else + { + $errors[] = $lang->error_cannot_write_to_file; + } + } + + unset($langinfo); + @include MYBB_ROOT."inc/languages/".$editwith.".php"; + $editwith_dir_class = " langeditor_ltr"; + if((int)$langinfo['rtl'] > 0) + { + $editwith_dir_class = " langeditor_rtl"; + } + unset($langinfo); + @include MYBB_ROOT."inc/languages/".$editlang.".php"; + $editlang_dir_class = " langeditor_ltr"; + if((int)$langinfo['rtl'] > 0) + { + $editlang_dir_class = " langeditor_rtl"; + } + + // Build and output form with edited phrases + + // Get file being edited in an array + @include $editfile; + $editvars = (array)$l; + unset($l); + + $withvars = array(); + // Get edit with file in an array if exists + if($editwithfile) + { + // File we will compare to, may not exists, but dont worry we will auto switch to solo mode later if so + @include $editwithfile; + $withvars = (array)$l; + unset($l); + } + + // Start output + $page->output_header($lang->languages); + + $sub_tabs['edit_language_variables'] = array( + "title" => $lang->edit_language_variables, + "link" => "index.php?module=config-languages", + "description" => $lang->edit_language_variables_desc + ); + $page->output_nav_tabs($sub_tabs, "edit_language_variables"); + + $form = new Form("index.php?module=config-languages&action=edit", "post", "edit"); + echo $form->generate_hidden_field("file", htmlspecialchars_uni($file)); + echo $form->generate_hidden_field("lang", $editlang); + echo $form->generate_hidden_field("editwith", $editwith); + echo $form->generate_hidden_field("inadmin", (int)$mybb->input['inadmin']); + if($errors) + { + $page->output_inline_error($errors); + } + + // Check if file is writable, before allowing submission + $no_write = null; + if(file_exists($editfile) && !is_writable($editfile) || !is_writable($folder)) + { + $no_write = 1; + $page->output_alert($lang->alert_note_cannot_write); + } + + $form_container = new FormContainer(htmlspecialchars_uni($file)); + if($editwithfile && $withvars) + { + // Editing with another file + + $form_container->output_row_header(preg_replace("<\?|\?>", "?", $languages[$editwith])); + $form_container->output_row_header(preg_replace("<\?|\?>", "?", $languages[$editlang])); + + foreach($withvars as $key => $value) + { + if(my_strtolower($langinfo['charset']) == "utf-8") + { + $withvars[$key] = preg_replace_callback("#%u([0-9A-F]{1,4})#i", create_function('$matches', 'return dec_to_utf8(hexdec($matches[1]));'), $withvars[$key]); + $editvars[$key] = preg_replace_callback("#%u([0-9A-F]{1,4})#i", create_function('$matches', 'return dec_to_utf8(hexdec($matches[1]));'), $editvars[$key]); + } + else + { + $withvars[$key] = preg_replace_callback("#%u([0-9A-F]{1,4})#i", create_function('$matches', 'return dec_to_utf8(hexdec($matches[1]));'), $withvars[$key]); + $editvars[$key] = preg_replace_callback("#%u([0-9A-F]{1,4})#i", create_function('$matches', 'return "&#".hexdec($matches[1]).";";'), $editvars[$key]); + } + + // Find problems and differences in editfile in comparision to editwithfile + + // Count {x} in left and right variable + $withvars_value_cbvCount = preg_match_all("/{[ \t]*\d+[ \t]*}/", $withvars[$key], $matches); + $editvars_value_cbvCount = preg_match_all("/{[ \t]*\d+[ \t]*}/", $editvars[$key], $matches); + + // If left contain something but right is empty or only spaces || count of {x} are different betwin left and right + if($withvars[$key] && !$editvars[$key] || $withvars_value_cbvCount != $editvars_value_cbvCount) + { + $textarea_issue_class = " langeditor_textarea_issue"; + } + else + { + $textarea_issue_class = ""; + } + + $form_container->output_row($key, "", $form->generate_text_area("", $withvars[$key], array('readonly' => true, 'rows' => 2, 'class' => "langeditor_textarea_editwith {$editwith_dir_class}")), "", array('width' => '50%', 'skip_construct' => true)); + $form_container->output_row($key, "", $form->generate_text_area("edit[$key]", $editvars[$key], array('id' => 'lang_'.$key, 'rows' => 2, 'class' => "langeditor_textarea_edit {$textarea_issue_class} {$editlang_dir_class}")), 'lang_'.$key, array('width' => '50%')); + } + + // Create form fields for extra variables that are present only in edited file + $present_in_edit_vars_only = (array)array_diff_key($editvars, $withvars); + if($present_in_edit_vars_only) + { + foreach($present_in_edit_vars_only as $key => $value) + { + if(my_strtolower($langinfo['charset']) == "utf-8") + { + $editvars[$key] = preg_replace_callback("#%u([0-9A-F]{1,4})#i", create_function('$matches', 'return dec_to_utf8(hexdec($matches[1]));'), $editvars[$key]); + } + else + { + $editvars[$key] = preg_replace_callback("#%u([0-9A-F]{1,4})#i", create_function('$matches', 'return "&#".hexdec($matches[1]).";";'), $editvars[$key]); + } + + $form_container->output_row("", "", "", "", array('width' => '50%', 'skip_construct' => true)); + $form_container->output_row($key, "", $form->generate_text_area("edit[$key]", $editvars[$key], array('id' => 'lang_'.$key, 'rows' => 2, 'class' => "langeditor_textarea_edit {$editlang_dir_class}")), 'lang_'.$key, array('width' => '50%')); + } + } + + } + else + { + // Editing individually + $form_container->output_row_header(preg_replace("<\?|\?>", "?", $languages[$editlang])); + + // Make each editing row from current file that we edit + foreach($editvars as $key => $value) + { + if(my_strtolower($langinfo['charset']) == "utf-8") + { + $value = preg_replace_callback("#%u([0-9A-F]{1,4})#i", create_function('$matches', 'return dec_to_utf8(hexdec($matches[1]));'), $value); + } + else + { + $value = preg_replace_callback("#%u([0-9A-F]{1,4})#i", create_function('$matches', 'return "&#".hexdec($matches[1]).";";'), $value); + } + $form_container->output_row($key, "", $form->generate_text_area("edit[$key]", $value, array('id' => 'lang_'.$key, 'rows' => 2, 'class' => "langeditor_textarea_edit {$editlang_dir_class}")), 'lang_'.$key, array('width' => '50%')); + } + } + $form_container->end(); + + if(!count($editvars)) + { + $no_write = 1; + } + + $buttons[] = $form->generate_submit_button($lang->save_language_file, array('disabled' => $no_write)); + + $form->output_submit_wrapper($buttons); + $form->end(); + } + else + { + // Build and output list of available language files + + $page->output_header($lang->languages); + + $sub_tabs['language_files'] = array( + 'title' => $lang->language_files, + 'link' => "index.php?module=config-languages&action=edit&lang=".$editlang, + 'description' => $lang->language_files_desc + ); + + $sub_tabs['quick_phrases'] = array( + 'title' => $lang->quick_phrases, + 'link' => "index.php?module=config-languages&action=quick_phrases&lang=".$editlang, + 'description' => $lang->quick_phrases_desc + ); + + $page->output_nav_tabs($sub_tabs, 'language_files'); + + if(!file_exists(MYBB_ROOT."inc/languages/".$editlang.".php")) + { + flash_message($lang->error_invalid_set, 'error'); + admin_redirect("index.php?module=config-languages"); + } + require MYBB_ROOT."inc/languages/".$editlang.".php"; + + $table = new Table; + if($editwithfolder) + { + $table->construct_header(preg_replace("<\?|\?>", "?", $languages[$editwith])); + $table->construct_header($lang->phrases, array("class" => "align_center", "width" => 100)); + $table->construct_header(preg_replace("<\?|\?>", "?", $languages[$editlang])); + $table->construct_header($lang->issues, array("class" => "align_center", "width" => 100)); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 100)); + } + else + { + $table->construct_header(preg_replace("<\?|\?>", "?", $languages[$editlang])); + $table->construct_header($lang->phrases, array("class" => "align_center", "width" => 100)); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 100)); + } + + // Get files in main folder + $filenames = array(); + if($handle = opendir($folder)) + { + while(false !== ($file = readdir($handle))) + { + if(preg_match("#\.lang\.php$#", $file)) + { + $filenames[] = $file; + } + } + closedir($handle); + sort($filenames); + } + + $edit_colspan = 3; + // Get files from folder we want to peek at (if possible) + if($editwithfolder) + { + $edit_colspan = 5; + $filenameswith = array(); + if($handle = opendir($editwithfolder)) + { + while(false !== ($file = readdir($handle))) + { + if(preg_match("#\.lang\.php$#", $file)) + { + $filenameswith[] = $file; + } + } + closedir($handle); + sort($filenameswith); + } + } + + if($editwithfolder) + { + $files_left = array_diff($filenameswith, $filenames); + $files_right = array_diff($filenames, $filenameswith); + $files_both = array_intersect($filenameswith, $filenames); + + foreach($files_left as $key => $file) + { + @include $editwithfolder.$file; + $editvars_left = (array)$l; + unset($l); + + $icon_issues = ""; + if(count($editvars_left) >0) + { + $icon_issues = ""; + } + + $table->construct_cell($file, array("class" => "langeditor_editwithfile")); + $table->construct_cell(count($editvars_left), array("class" => "langeditor_phrases")); + $table->construct_cell("", array("class" => "langeditor_editfile")); + $table->construct_cell($icon_issues, array("class" => "langeditor_issues")); + $table->construct_cell("{$lang->edit}", array("class" => "langeditor_edit")); + $table->construct_row(); + } + foreach($files_right as $key => $file) + { + @include $folder.$file; + $editvars_right = (array)$l; + unset($l); + + $icon_issues = ""; + if(count($editvars_right >0)) + { + $icon_issues = ""; + } + + $table->construct_cell("", array("class" => "langeditor_editwithfile")); + $table->construct_cell("", array("class" => "langeditor_phrases")); + $table->construct_cell($file, array("class" => "langeditor_editfile")); + $table->construct_cell($icon_issues, array("class" => "langeditor_issues")); + $table->construct_cell("{$lang->edit}", array("class" => "langeditor_edit")); + $table->construct_row(); + } + foreach($files_both as $key => $file) + { + @include $editwithfolder.$file; + $editvars_left = (array)$l; + unset($l); + @include $folder.$file; + $editvars_right = (array)$l; + unset($l); + + $table->construct_cell($file, array("class" => "langeditor_editwithfile")); + $table->construct_cell(count($editvars_left), array("class" => "langeditor_phrases")); + $table->construct_cell($file, array("class" => "langeditor_editfile")); + + $icon_issues = ""; + + // Find problems and differences in editfile in comparision to editwithfile + foreach($editvars_left as $editvars_left_key => $editvars_left_value) + { + // Count {x} in left and right variable + $editvars_left_value_cbvCount = preg_match_all("/{[ \t]*\d+[ \t]*}/", $editvars_left_value, $matches); + $editvars_right_value_cbvCount = preg_match_all("/{[ \t]*\d+[ \t]*}/", $editvars_right[$editvars_left_key], $matches); + // If left contain something but right is empty || count of {x} are different betwin left and right + if($editvars_left_value && !$editvars_right[$editvars_left_key] || $editvars_left_value_cbvCount != $editvars_right_value_cbvCount) + { + $icon_issues = ""; + // One difference is enought, so lets abort checking for more. + break; + } + } + + $table->construct_cell($icon_issues, array("class" => "langeditor_issues")); + $table->construct_cell("{$lang->edit}", array("class" => "langeditor_edit")); + $table->construct_row(); + } + } + else + { + foreach($filenames as $key => $file) + { + @include $folder.$file; + $editvars_count = (array)$l; + unset($l); + + $table->construct_cell($file, array("class" => "langeditor_editfile")); + $table->construct_cell(count($editvars_count), array("class" => "langeditor_phrases")); + $table->construct_cell("{$lang->edit}", array("class" => "langeditor_edit")); + $table->construct_row(); + } + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_language_files_front_end, array('colspan' => $edit_colspan)); + $table->construct_row(); + } + + $table->output($lang->front_end); + + if($langinfo['admin'] != 0) + { + $table = new Table; + if($editwithfolder) + { + $table->construct_header(preg_replace("<\?|\?>", "?", $languages[$editwith])); + $table->construct_header($lang->phrases, array("class" => "align_center", "width" => 100)); + $table->construct_header(preg_replace("<\?|\?>", "?", $languages[$editlang])); + $table->construct_header($lang->issues, array("class" => "align_center", "width" => 100)); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 100)); + } + else + { + $table->construct_header(preg_replace("<\?|\?>", "?", $languages[$editlang])); + $table->construct_header($lang->phrases, array("class" => "align_center", "width" => 100)); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 100)); + } + + // Get files in admin folder + $adminfilenames = array(); + if($handle = opendir($folder."admin")) + { + while(false !== ($file = readdir($handle))) + { + if(preg_match("#\.lang\.php$#", $file)) + { + $adminfilenames[] = $file; + } + } + closedir($handle); + sort($adminfilenames); + } + + $edit_colspan = 3; + // Get files from admin folder we want to peek at (if possible) + if($editwithfolder) + { + $edit_colspan = 5; + $adminfilenameswith = array(); + if($handle = opendir($editwithfolder."admin")) + { + while(false !== ($file = readdir($handle))) + { + if(preg_match("#\.lang\.php$#", $file)) + { + $adminfilenameswith[] = $file; + } + } + closedir($handle); + sort($adminfilenameswith); + } + } + + if($editwithfolder) + { + $files_left = array_diff($adminfilenameswith, $adminfilenames); + $files_right = array_diff($adminfilenames, $adminfilenameswith); + $files_both = array_intersect($adminfilenameswith, $adminfilenames); + + foreach($files_left as $key => $file) + { + @include $editwithfolder."admin/".$file; + $editvars_left = (array)$l; + unset($l); + + $icon_issues = ""; + if(count($editvars_left) >0) + { + $icon_issues = ""; + } + + $table->construct_cell($file, array("class" => "langeditor_editwithfile")); + $table->construct_cell(count($editvars_left), array("class" => "langeditor_phrases")); + $table->construct_cell("", array("class" => "langeditor_editfile")); + $table->construct_cell($icon_issues, array("class" => "langeditor_issues")); + $table->construct_cell("{$lang->edit}", array("class" => "langeditor_edit")); + $table->construct_row(); + } + foreach($files_right as $key => $file) + { + @include $folder."admin/".$file; + $editvars_right = (array)$l; + unset($l); + + $icon_issues = ""; + if(count($editvars_right >0)) + { + $icon_issues = ""; + } + + $table->construct_cell("", array("class" => "langeditor_editwithfile")); + $table->construct_cell("", array("class" => "langeditor_phrases")); + $table->construct_cell($file, array("class" => "langeditor_editfile")); + $table->construct_cell($icon_issues, array("class" => "langeditor_issues")); + $table->construct_cell("{$lang->edit}", array("class" => "langeditor_edit")); + $table->construct_row(); + } + foreach($files_both as $key => $file) + { + @include $editwithfolder."admin/".$file; + $editvars_left = (array)$l; + unset($l); + @include $folder."admin/".$file; + $editvars_right = (array)$l; + unset($l); + + $table->construct_cell($file, array("class" => "langeditor_editwithfile")); + $table->construct_cell(count($editvars_left), array("class" => "langeditor_phrases")); + $table->construct_cell($file, array("class" => "langeditor_editfile")); + + $icon_issues = ""; + + // Find problems and differences in editfile in comparision to editwithfile + foreach($editvars_left as $editvars_left_key => $editvars_left_value) + { + // Count {x} in left and right variable + $editvars_left_value_cbvCount = preg_match_all("/{[ \t]*\d+[ \t]*}/", $editvars_left_value, $matches); + $editvars_right_value_cbvCount = preg_match_all("/{[ \t]*\d+[ \t]*}/", $editvars_right[$editvars_left_key], $matches); + // If left contain something but right is empty || count of {x} are different betwin left and right + if($editvars_left_value && !$editvars_right[$editvars_left_key] || $editvars_left_value_cbvCount != $editvars_right_value_cbvCount) + { + $icon_issues = ""; + // One difference is enought. + break; + } + } + + $table->construct_cell($icon_issues, array("class" => "langeditor_issues")); + $table->construct_cell("{$lang->edit}", array("class" => "langeditor_edit")); + $table->construct_row(); + } + } + else + { + foreach($adminfilenames as $key => $file) + { + @include $folder."admin/".$file; + $editvars_count = (array)$l; + unset($l); + + $table->construct_cell($file, array("class" => "langeditor_editfile")); + $table->construct_cell(count($editvars_count), array("class" => "langeditor_phrases")); + $table->construct_cell("{$lang->edit}", array("class" => "langeditor_edit")); + $table->construct_row(); + } + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_language_files_admin_cp, array('colspan' => $edit_colspan)); + $table->construct_row(); + } + + $table->output($lang->admin_cp); + } + } + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $page->output_header($lang->languages); + + $sub_tabs['languages'] = array( + 'title' => $lang->languages, + 'link' => "index.php?module=config-languages", + 'description' => $lang->languages_desc + ); + $sub_tabs['find_language'] = array( + 'title' => $lang->find_language_packs, + 'link' => "http://community.mybb.com/mods.php?action=browse&category=19", + 'target' => "_blank" + ); + + $plugins->run_hooks("admin_config_languages_start"); + + $page->output_nav_tabs($sub_tabs, 'languages'); + + $table = new Table; + $table->construct_header($lang->languagevar); + $table->construct_header($lang->version, array("class" => "align_center", "width" => 100)); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 155)); + + asort($languages); + + foreach($languages as $key1 => $langname1) + { + $langselectlangs[$key1] = $lang->sprintf($lang->edit_with, preg_replace("<\?|\?>", "?", $langname1)); + } + + foreach($languages as $key => $langname) + { + include MYBB_ROOT."inc/languages/".$key.".php"; + + if(!empty($langinfo['website'])) + { + $author = "{$langinfo['author']}"; + } + else + { + $author = $langinfo['author']; + } + + $table->construct_cell("".preg_replace("<\?|\?>", "?", $langinfo['name'])."
{$author}"); + $table->construct_cell($langinfo['version'], array("class" => "align_center")); + + $popup = new PopupMenu("language_{$key}", $lang->options); + $popup->add_item($lang->edit_language_variables, "index.php?module=config-languages&action=edit&lang={$key}"); + foreach($langselectlangs as $key1 => $langname1) + { + if($key != $key1) + { + $popup->add_item($langname1, "index.php?module=config-languages&action=edit&lang={$key}&editwith={$key1}"); + } + } + $popup->add_item($lang->edit_properties, "index.php?module=config-languages&action=edit_properties&lang={$key}"); + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_language, array('colspan' => 3)); + $table->construct_row(); + } + + $table->output($lang->installed_language_packs); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/config/mod_tools.php b/Upload/admin/modules/config/mod_tools.php new file mode 100644 index 0000000..e1728da --- /dev/null +++ b/Upload/admin/modules/config/mod_tools.php @@ -0,0 +1,2362 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->mod_tools, "index.php?module=config-mod_tools"); + +$plugins->run_hooks("admin_config_mod_tools_begin"); + +if($mybb->input['action'] == "delete_post_tool") +{ + $query = $db->simple_select("modtools", "*", "tid='{$mybb->input['tid']}'"); + $tool = $db->fetch_array($query); + + // Does the post tool not exist? + if(!$tool['tid']) + { + flash_message($lang->error_invalid_post_tool, 'error'); + admin_redirect("index.php?module=config-mod_tools&action=post_tools"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-mod_tools&action=post_tools"); + } + + $plugins->run_hooks("admin_config_mod_tools_delete_post_tool"); + + if($mybb->request_method == 'post') + { + // Delete the type + $db->delete_query('modtools', "tid='{$tool['tid']}'"); + + $plugins->run_hooks("admin_config_mod_tools_delete_post_tool_commit"); + + // Log admin action + log_admin_action($tool['tid'], $tool['name']); + $cache->update_forumsdisplay(); + + flash_message($lang->success_post_tool_deleted, 'success'); + admin_redirect("index.php?module=config-mod_tools&action=post_tools"); + } + else + { + $page->output_confirm_action("index.php?module=config-mod_tools&action=post_tools&tid={$type['tid']}", $lang->confirm_post_tool_deletion); + } +} + +if($mybb->input['action'] == "delete_thread_tool") +{ + $query = $db->simple_select("modtools", "*", "tid='{$mybb->input['tid']}'"); + $tool = $db->fetch_array($query); + + // Does the post tool not exist? + if(!$tool['tid']) + { + flash_message($lang->error_invalid_thread_tool, 'error'); + admin_redirect("index.php?module=config-mod_tools"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-mod_tools"); + } + + $plugins->run_hooks("admin_config_mod_tools_delete_thread_tool"); + + if($mybb->request_method == 'post') + { + // Delete the type + $db->delete_query('modtools', "tid='{$tool['tid']}'"); + + $plugins->run_hooks("admin_config_mod_tools_delete_thread_tool_commit"); + + // Log admin action + log_admin_action($tool['tid'], $tool['name']); + $cache->update_forumsdisplay(); + + flash_message($lang->success_thread_tool_deleted, 'success'); + admin_redirect("index.php?module=config-mod_tools"); + } + else + { + $page->output_confirm_action("index.php?module=config-mod_tools&action=delete_thread_tool&tid={$tool['tid']}", $lang->confirm_thread_tool_deletion); + } +} + +if($mybb->input['action'] == "post_tools") +{ + $plugins->run_hooks("admin_config_mod_tools_post_tools"); + + $page->add_breadcrumb_item($lang->post_tools); + $page->output_header($lang->mod_tools." - ".$lang->post_tools); + + $sub_tabs['thread_tools'] = array( + 'title' => $lang->thread_tools, + 'link' => "index.php?module=config-mod_tools" + ); + $sub_tabs['add_thread_tool'] = array( + 'title'=> $lang->add_thread_tool, + 'link' => "index.php?module=config-mod_tools&action=add_thread_tool" + ); + $sub_tabs['post_tools'] = array( + 'title' => $lang->post_tools, + 'link' => "index.php?module=config-mod_tools&action=post_tools", + 'description' => $lang->post_tools_desc + ); + $sub_tabs['add_post_tool'] = array( + 'title'=> $lang->add_post_tool, + 'link' => "index.php?module=config-mod_tools&action=add_post_tool" + ); + + $page->output_nav_tabs($sub_tabs, 'post_tools'); + + $table = new Table; + $table->construct_header($lang->title); + $table->construct_header($lang->controls, array('class' => "align_center", 'colspan' => 2)); + + $query = $db->simple_select('modtools', 'tid, name, description, type', "type='p'", array('order_by' => 'name')); + while($tool = $db->fetch_array($query)) + { + $table->construct_cell("".htmlspecialchars_uni($tool['name'])."
".htmlspecialchars_uni($tool['description']).""); + $table->construct_cell("{$lang->edit}", array('width' => 100, 'class' => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_post_tool_deletion}')\">{$lang->delete}", array('width' => 100, 'class' => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_post_tools, array('colspan' => 3)); + $table->construct_row(); + } + + $table->output($lang->post_tools); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit_thread_tool") +{ + $query = $db->simple_select("modtools", "COUNT(tid) as tools", "tid = '{$mybb->input['tid']}' AND type='t'"); + if($db->fetch_field($query, "tools") < 1) + { + flash_message($lang->error_invalid_thread_tool, 'error'); + admin_redirect("index.php?module=config-mod_tools"); + } + + $plugins->run_hooks("admin_config_mod_tools_edit_thread_tool"); + + if($mybb->request_method == 'post') + { + if(trim($mybb->input['title']) == "") + { + $errors[] = $lang->error_missing_title; + } + + if(trim($mybb->input['description']) == "") + { + $errors[] = $lang->error_missing_description; + } + + if($mybb->input['forum_type'] == 2) + { + $forum_checked[1] = ''; + $forum_checked[2] = "checked=\"checked\""; + + if(count($mybb->input['forum_1_forums']) < 1) + { + $errors[] = $lang->error_no_forums_selected; + } + } + else + { + $forum_checked[1] = "checked=\"checked\""; + $forum_checked[2] = ''; + + $mybb->input['forum_1_forums'] = ''; + } + + if($mybb->input['group_type'] == 2) + { + $group_checked[1] = ''; + $group_checked[2] = "checked=\"checked\""; + + if(count($mybb->input['group_1_groups']) < 1) + { + $errors[] = $lang->error_no_groups_selected; + } + } + else + { + $group_checked[1] = "checked=\"checked\""; + $group_checked[2] = ''; + + $mybb->input['group_1_groups'] = ''; + } + + if($mybb->input['approvethread'] != '' && $mybb->input['approvethread'] != 'approve' && $mybb->input['approvethread'] != 'unapprove' && $mybb->input['approvethread'] != 'toggle') + { + $mybb->input['approvethread'] = ''; + } + + if($mybb->input['softdeletethread'] != '' && $mybb->input['softdeletethread'] != 'softdelete' && $mybb->input['softdeletethread'] != 'restore' && $mybb->input['softdeletethread'] != 'toggle') + { + $mybb->input['softdeletethread'] = ''; + } + + if($mybb->input['openthread'] != '' && $mybb->input['openthread'] != 'open' && $mybb->input['openthread'] != 'close' && $mybb->input['openthread'] != 'toggle') + { + $mybb->input['openthread'] = ''; + } + + if($mybb->input['stickthread'] != '' && $mybb->input['stickthread'] != 'stick' && $mybb->input['stickthread'] != 'unstick' && $mybb->input['stickthread'] != 'toggle') + { + $mybb->input['stickthread'] = ''; + } + + if($mybb->input['move_type'] == 2) + { + $move_checked[1] = ''; + $move_checked[2] = "checked=\"checked\""; + + if(!$mybb->input['move_1_forum']) + { + $errors[] = $lang->error_no_move_forum_selected; + } + else + { + // Check that the destination forum is not a category + $query = $db->simple_select("forums", "type", "fid = '".(int)$mybb->input['move_1_forum']."'"); + if($db->fetch_field($query, "type") == "c") + { + $errors[] = $lang->error_forum_is_category; + } + } + + if($mybb->input['move_2_redirect'] != 1 && $mybb->input['move_2_redirect'] != 0) + { + $mybb->input['move_2_redirect'] = 0; + } + + if(!isset($mybb->input['move_3_redirecttime'])) + { + $mybb->input['move_3_redirecttime'] = ''; + } + } + else + { + $move_checked[1] = "checked=\"checked\""; + $move_checked[2] = ''; + + $mybb->input['move_1_forum'] = ''; + $mybb->input['move_2_redirect'] = 0; + $mybb->input['move_3_redirecttime'] = ''; + } + + if($mybb->input['copy_type'] == 2) + { + $copy_checked[1] = ''; + $copy_checked[2] = "checked=\"checked\""; + + if(!$mybb->input['copy_1_forum']) + { + $errors[] = $lang->error_no_copy_forum_selected; + } + else + { + $query = $db->simple_select("forums", "type", "fid = '".(int)$mybb->input['copy_1_forum']."'"); + if($db->fetch_field($query, "type") == "c") + { + $errors[] = $lang->error_forum_is_category; + } + } + } + else + { + $copy_checked[1] = "checked=\"checked\""; + $copy_checked[2] = ''; + + $mybb->input['copy_1_forum'] = ''; + } + + if(!$errors) + { + $thread_options = array( + 'confirmation' => $mybb->input['confirmation'], + 'deletethread' => $mybb->input['deletethread'], + 'mergethreads' => $mybb->input['mergethreads'], + 'deletepoll' => $mybb->input['deletepoll'], + 'removeredirects' => $mybb->input['removeredirects'], + 'removesubscriptions' => $mybb->input['removesubscriptions'], + 'recountrebuild' => $mybb->input['recountrebuild'], + 'approvethread' => $mybb->input['approvethread'], + 'softdeletethread' => $mybb->input['softdeletethread'], + 'openthread' => $mybb->input['openthread'], + 'stickthread' => $mybb->input['stickthread'], + 'movethread' => (int)$mybb->input['move_1_forum'], + 'movethreadredirect' => $mybb->input['move_2_redirect'], + 'movethreadredirectexpire' => (int)$mybb->input['move_3_redirecttime'], + 'copythread' => (int)$mybb->input['copy_1_forum'], + 'newsubject' => $mybb->input['newsubject'], + 'addreply' => $mybb->input['newreply'], + 'replysubject' => $mybb->input['newreplysubject'], + 'pm_subject' => $mybb->input['pm_subject'], + 'pm_message' => $mybb->input['pm_message'], + 'threadprefix' => (int)$mybb->input['threadprefix'] + ); + + $update_tool['type'] = 't'; + $update_tool['threadoptions'] = $db->escape_string(serialize($thread_options)); + $update_tool['name'] = $db->escape_string($mybb->input['title']); + $update_tool['description'] = $db->escape_string($mybb->input['description']); + $update_tool['forums'] = ''; + $update_tool['groups'] = ''; + + if($mybb->input['forum_type'] == 2) + { + if(is_array($mybb->input['forum_1_forums'])) + { + $checked = array(); + + foreach($mybb->input['forum_1_forums'] as $fid) + { + $checked[] = (int)$fid; + } + + $update_tool['forums'] = implode(',', $checked); + } + } + else + { + $update_tool['forums'] = "-1"; + } + + if($mybb->input['group_type'] == 2) + { + if(is_array($mybb->input['group_1_groups'])) + { + $checked = array(); + + foreach($mybb->input['group_1_groups'] as $gid) + { + $checked[] = (int)$gid; + } + + $update_tool['groups'] = implode(',', $checked); + } + } + else + { + $update_tool['groups'] = "-1"; + } + + $plugins->run_hooks("admin_config_mod_tools_edit_thread_tool_commit"); + + $db->update_query("modtools", $update_tool, "tid='{$mybb->input['tid']}'"); + + // Log admin action + log_admin_action($mybb->input['tid'], $mybb->input['title']); + $cache->update_forumsdisplay(); + + flash_message($lang->success_mod_tool_updated, 'success'); + admin_redirect("index.php?module=config-mod_tools"); + } + } + + $page->add_breadcrumb_item($lang->edit_thread_tool); + $page->output_header($lang->mod_tools." - ".$lang->edit_thread_tool); + + $sub_tabs['edit_thread_tool'] = array( + "title" => $lang->edit_thread_tool, + "description" => $lang->edit_thread_tool_desc, + "link" => "index.php?module=config-mod_tools" + ); + + $page->output_nav_tabs($sub_tabs, 'edit_thread_tool'); + + $form = new Form("index.php?module=config-mod_tools&action=edit_thread_tool", 'post'); + echo $form->generate_hidden_field("tid", $mybb->input['tid']); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $query = $db->simple_select("modtools", "*", "tid = '{$mybb->input['tid']}'"); + $modtool = $db->fetch_array($query); + $thread_options = my_unserialize($modtool['threadoptions']); + + $mybb->input['title'] = $modtool['name']; + $mybb->input['description'] = $modtool['description']; + $mybb->input['forum_1_forums'] = explode(",", $modtool['forums']); + $mybb->input['group_1_groups'] = explode(",", $modtool['groups']); + + if(!$modtool['forums'] || $modtool['forums'] == -1) + { + $forum_checked[1] = "checked=\"checked\""; + $forum_checked[2] = ''; + } + else + { + $forum_checked[1] = ''; + $forum_checked[2] = "checked=\"checked\""; + } + + if(!$modtool['groups'] || $modtool['groups'] == -1) + { + $group_checked[1] = "checked=\"checked\""; + $group_checked[2] = ''; + } + else + { + $group_checked[1] = ''; + $group_checked[2] = "checked=\"checked\""; + } + + $mybb->input['confirmation'] = $thread_options['confirmation']; + $mybb->input['approvethread'] = $thread_options['approvethread']; + $mybb->input['softdeletethread'] = $thread_options['softdeletethread']; + $mybb->input['openthread'] = $thread_options['openthread']; + $mybb->input['stickthread'] = $thread_options['stickthread']; + $mybb->input['move_1_forum'] = $thread_options['movethread']; + $mybb->input['move_2_redirect'] = $thread_options['movethreadredirect']; + $mybb->input['move_3_redirecttime'] = $thread_options['movethreadredirectexpire']; + + if(!$thread_options['movethread']) + { + $move_checked[1] = "checked=\"checked\""; + $move_checked[2] = ''; + } + else + { + $move_checked[1] = ''; + $move_checked[2] = "checked=\"checked\""; + } + + if(!$thread_options['copythread']) + { + $copy_checked[1] = "checked=\"checked\""; + $copy_checked[2] = ''; + } + else + { + $copy_checked[1] = ''; + $copy_checked[2] = "checked=\"checked\""; + } + + $mybb->input['copy_1_forum'] = $thread_options['copythread']; + $mybb->input['deletethread'] = $thread_options['deletethread']; + $mybb->input['mergethreads'] = $thread_options['mergethreads']; + $mybb->input['deletepoll'] = $thread_options['deletepoll']; + $mybb->input['removeredirects'] = $thread_options['removeredirects']; + $mybb->input['removesubscriptions'] = $thread_options['removesubscriptions']; + $mybb->input['recountrebuild'] = $thread_options['recountrebuild']; + $mybb->input['threadprefix'] = $thread_options['threadprefix']; + $mybb->input['newsubject'] = $thread_options['newsubject']; + $mybb->input['newreply'] = $thread_options['addreply']; + $mybb->input['newreplysubject'] = $thread_options['replysubject']; + $mybb->input['pm_subject'] = $thread_options['pm_subject']; + $mybb->input['pm_message'] = $thread_options['pm_message']; + } + + $form_container = new FormContainer($lang->general_options); + $form_container->output_row($lang->name." *", '', $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->short_description." *", '', $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + + $actions = " +
+
+
+
+ + + + + +
{$lang->forums_colon}".$form->generate_forum_select('forum_1_forums[]', $mybb->input['forum_1_forums'], array('multiple' => true, 'size' => 5))."
+
+
+ "; + $form_container->output_row($lang->available_in_forums." *", '', $actions); + + $actions = "
+
+
+
+ + + + + +
{$lang->groups_colon}".$form->generate_group_select('group_1_groups[]', $mybb->input['group_1_groups'], array('multiple' => true, 'size' => 5))."
+
+
+ "; + $form_container->output_row($lang->available_to_groups." *", '', $actions); + $form_container->output_row($lang->show_confirmation." *", '', $form->generate_yes_no_radio('confirmation', $mybb->input['confirmation'], array('style' => 'width: 2em;'))); + $form_container->end(); + + $approve_unapprove = array( + '' => $lang->no_change, + 'approve' => $lang->approve, + 'unapprove' => $lang->unapprove, + 'toggle' => $lang->toggle + ); + + $open_close = array( + '' => $lang->no_change, + 'open' => $lang->open, + 'close' => $lang->close, + 'toggle' => $lang->toggle + ); + + $stick_unstick = array( + '' => $lang->no_change, + 'stick' => $lang->stick, + 'unstick' => $lang->unstick, + 'toggle' => $lang->toggle + ); + + $form_container = new FormContainer($lang->thread_moderation); + $form_container->output_row($lang->approve_unapprove." *", '', $form->generate_select_box('approvethread', $approve_unapprove, $mybb->input['approvethread'], array('id' => 'approvethread')), 'approvethread'); + $form_container->output_row($lang->open_close_thread." *", '', $form->generate_select_box('openthread', $open_close, $mybb->input['openthread'], array('id' => 'openthread')), 'openthread'); + $form_container->output_row($lang->stick_unstick_thread." *", '', $form->generate_select_box('stickthread', $stick_unstick, $mybb->input['stickthread'], array('id' => 'stickthread')), 'stickthread'); + + + $actions = " +
+
+
+
+ + + + + + + + + + + + + +
{$lang->forum_to_move_to}".$form->generate_forum_select('move_1_forum', $mybb->input['move_1_forum'])."
{$lang->leave_redirect}".$form->generate_yes_no_radio('move_2_redirect', $mybb->input['move_2_redirect'], array('style' => 'width: 2em;'))."
{$lang->delete_redirect_after}".$form->generate_numeric_field('move_3_redirecttime', $mybb->input['move_3_redirecttime'], array('style' => 'width: 2em;'))." {$lang->days}
+
+
+ "; + $form_container->output_row($lang->move_thread." *", $lang->move_thread_desc, $actions); + + $actions = " +
+
+
+
+ + + + + +
{$lang->forum_to_copy_to}".$form->generate_forum_select('copy_1_forum', $mybb->input['copy_1_forum'])."
+
+
+ "; + $form_container->output_row($lang->copy_thread." *", '', $actions); + + $softdelete_restore = array( + '' => $lang->no_change, + 'restore' => $lang->restore, + 'softdelete' => $lang->softdelete, + 'toggle' => $lang->toggle + ); + + $form_container->output_row($lang->softdelete_restore_thread." *", '', $form->generate_select_box('softdeletethread', $softdelete_restore, $mybb->input['softdeletethread'], array('id' => 'softdeletethread')), 'softdeletethread'); + $form_container->output_row($lang->delete_thread." *", '', $form->generate_yes_no_radio('deletethread', $mybb->input['deletethread'], array('style' => 'width: 2em;'))); + $form_container->output_row($lang->merge_thread." *", $lang->merge_thread_desc, $form->generate_yes_no_radio('mergethreads', $mybb->input['mergethreads'], array('style' => 'width: 2em;'))); + $form_container->output_row($lang->delete_poll." *", '', $form->generate_yes_no_radio('deletepoll', $mybb->input['deletepoll'], array('style' => 'width: 2em;'))); + $form_container->output_row($lang->delete_redirects." *", '', $form->generate_yes_no_radio('removeredirects', $mybb->input['removeredirects'], array('style' => 'width: 2em;'))); + $form_container->output_row($lang->remove_subscriptions." *", '', $form->generate_yes_no_radio('removesubscriptions', $mybb->input['removesubscriptions'], array('style' => 'width: 2em;'))); + $form_container->output_row($lang->recount_rebuild." *", '', $form->generate_yes_no_radio('recountrebuild', $mybb->input['recountrebuild'], array('style' => 'width: 2em;'))); + + $threadprefixes = build_prefixes(); + if(!empty($threadprefixes)) + { + $thread_prefixes = array( + '-1' => $lang->no_change, + '0' => $lang->no_prefix + ); + + foreach($threadprefixes as $prefix) + { + $thread_prefixes[$prefix['pid']] = $prefix['prefix']; + } + + $form_container->output_row($lang->apply_thread_prefix." *", '', $form->generate_select_box('threadprefix', $thread_prefixes, array((int)$mybb->input['threadprefix']), array('id' => 'threadprefix')), 'threadprefix'); + } + + $form_container->output_row($lang->new_subject." *", $lang->new_subject_desc, $form->generate_text_box('newsubject', $mybb->input['newsubject'], array('id' => 'newsubject'))); + $form_container->end(); + + $form_container = new FormContainer($lang->add_new_reply); + $form_container->output_row($lang->add_new_reply, $lang->add_new_reply_desc, $form->generate_text_area('newreply', $mybb->input['newreply'], array('id' => 'newreply')), 'newreply'); + $form_container->output_row($lang->reply_subject, $lang->reply_subject_desc, $form->generate_text_box('newreplysubject', $mybb->input['newreplysubject'], array('id' => 'newreplysubject')), 'newreplysubject'); + $form_container->end(); + + $form_container = new FormContainer($lang->send_private_message); + $form_container->output_row($lang->private_message_message, $lang->private_message_message_desc, $form->generate_text_area('pm_message', $mybb->input['pm_message'], array('id' => 'pm_message')), 'pm_message'); + $form_container->output_row($lang->private_message_subject, $lang->private_message_subject_desc, $form->generate_text_box('pm_subject', $mybb->input['pm_subject'], array('id' => 'pm_subject')), 'pm_subject'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_thread_tool); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "add_thread_tool") +{ + $plugins->run_hooks("admin_config_mod_tools_add_thread_tool"); + + if($mybb->request_method == 'post') + { + if(trim($mybb->input['title']) == "") + { + $errors[] = $lang->error_missing_title; + } + + if(trim($mybb->input['description']) == "") + { + $errors[] = $lang->error_missing_description; + } + + if($mybb->input['forum_type'] == 2) + { + $forum_checked[1] = ''; + $forum_checked[2] = "checked=\"checked\""; + + if(count($mybb->input['forum_1_forums']) < 1) + { + $errors[] = $lang->error_no_forums_selected; + } + } + else + { + $forum_checked[1] = "checked=\"checked\""; + $forum_checked[2] = ''; + + $mybb->input['forum_1_forums'] = ''; + } + + if($mybb->input['group_type'] == 2) + { + $group_checked[1] = ''; + $group_checked[2] = "checked=\"checked\""; + + if(count($mybb->input['group_1_groups']) < 1) + { + $errors[] = $lang->error_no_groups_selected; + } + } + else + { + $group_checked[1] = "checked=\"checked\""; + $group_checked[2] = ''; + + $mybb->input['group_1_groups'] = ''; + } + + if($mybb->input['approvethread'] != '' && $mybb->input['approvethread'] != 'approve' && $mybb->input['approvethread'] != 'unapprove' && $mybb->input['approvethread'] != 'toggle') + { + $mybb->input['approvethread'] = ''; + } + + if($mybb->input['softdeletethread'] != '' && $mybb->input['softdeletethread'] != 'restore' && $mybb->input['softdeletethread'] != 'softdelete' && $mybb->input['softdeletethread'] != 'toggle') + { + $mybb->input['softdeletethread'] = ''; + } + + if($mybb->input['openthread'] != '' && $mybb->input['openthread'] != 'open' && $mybb->input['openthread'] != 'close' && $mybb->input['openthread'] != 'toggle') + { + $mybb->input['openthread'] = ''; + } + + if($mybb->input['stickthread'] != '' && $mybb->input['stickthread'] != 'stick' && $mybb->input['stickthread'] != 'unstick' && $mybb->input['stickthread'] != 'toggle') + { + $mybb->input['stickthread'] = ''; + } + + if(!(int)$mybb->input['threadprefix']) + { + $mybb->input['threadprefix'] = ''; + } + + if($mybb->input['move_type'] == 2) + { + $move_checked[1] = ''; + $move_checked[2] = "checked=\"checked\""; + + if(!$mybb->input['move_1_forum']) + { + $errors[] = $lang->error_no_move_forum_selected; + } + else + { + // Check that the destination forum is not a category + $query = $db->simple_select("forums", "type", "fid = '".(int)$mybb->input['move_1_forum']."'"); + if($db->fetch_field($query, "type") == "c") + { + $errors[] = $lang->error_forum_is_category; + } + } + } + else + { + $move_checked[1] = "checked=\"checked\""; + $move_checked[2] = ''; + + $mybb->input['move_1_forum'] = ''; + $mybb->input['move_2_redirect'] = 0; + $mybb->input['move_3_redirecttime'] = ''; + } + + if($mybb->input['copy_type'] == 2) + { + $copy_checked[1] = ''; + $copy_checked[2] = "checked=\"checked\""; + + if(!$mybb->input['copy_1_forum']) + { + $errors[] = $lang->error_no_copy_forum_selected; + } + else + { + $query = $db->simple_select("forums", "type", "fid = '".(int)$mybb->input['copy_1_forum']."'"); + if($db->fetch_field($query, "type") == "c") + { + $errors[] = $lang->error_forum_is_category; + } + } + } + else + { + $copy_checked[1] = "checked=\"checked\""; + $copy_checked[2] = ''; + + $mybb->input['copy_1_forum'] = ''; + } + + if(!$errors) + { + $thread_options = array( + 'confirmation' => $mybb->input['confirmation'], + 'deletethread' => $mybb->input['deletethread'], + 'mergethreads' => $mybb->input['mergethreads'], + 'deletepoll' => $mybb->input['deletepoll'], + 'removeredirects' => $mybb->input['removeredirects'], + 'removesubscriptions' => $mybb->input['removesubscriptions'], + 'recountrebuild' => $mybb->input['recountrebuild'], + 'approvethread' => $mybb->input['approvethread'], + 'softdeletethread' => $mybb->input['softdeletethread'], + 'openthread' => $mybb->input['openthread'], + 'stickthread' => $mybb->input['stickthread'], + 'movethread' => (int)$mybb->input['move_1_forum'], + 'movethreadredirect' => $mybb->input['move_2_redirect'], + 'movethreadredirectexpire' => (int)$mybb->input['move_3_redirecttime'], + 'copythread' => (int)$mybb->input['copy_1_forum'], + 'newsubject' => $mybb->input['newsubject'], + 'addreply' => $mybb->input['newreply'], + 'replysubject' => $mybb->input['newreplysubject'], + 'pm_subject' => $mybb->input['pm_subject'], + 'pm_message' => $mybb->input['pm_message'], + 'threadprefix' => $mybb->input['threadprefix'], + ); + + $new_tool['type'] = 't'; + $new_tool['threadoptions'] = $db->escape_string(serialize($thread_options)); + $new_tool['name'] = $db->escape_string($mybb->input['title']); + $new_tool['description'] = $db->escape_string($mybb->input['description']); + $new_tool['forums'] = ''; + $new_tool['groups'] = ''; + $new_tool['postoptions'] = ''; + + if($mybb->input['forum_type'] == 2) + { + if(is_array($mybb->input['forum_1_forums'])) + { + $checked = array(); + + foreach($mybb->input['forum_1_forums'] as $fid) + { + $checked[] = (int)$fid; + } + + $new_tool['forums'] = implode(',', $checked); + } + } + else + { + $new_tool['forums'] = "-1"; + } + + if($mybb->input['group_type'] == 2) + { + if(is_array($mybb->input['group_1_groups'])) + { + $checked = array(); + + foreach($mybb->input['group_1_groups'] as $gid) + { + $checked[] = (int)$gid; + } + + $new_tool['groups'] = implode(',', $checked); + } + } + else + { + $new_tool['groups'] = "-1"; + } + + if((int)$mybb->input['threadprefix'] >= 0) + { + $thread_options['threadprefix'] = (int)$mybb->input['threadprefix']; + } + + $tid = $db->insert_query("modtools", $new_tool); + + $plugins->run_hooks("admin_config_mod_tools_add_thread_tool_commit"); + + // Log admin action + log_admin_action($tid, $mybb->input['title']); + $cache->update_forumsdisplay(); + + flash_message($lang->success_mod_tool_created, 'success'); + admin_redirect("index.php?module=config-mod_tools"); + } + } + + $page->add_breadcrumb_item($lang->add_new_thread_tool); + $page->output_header($lang->mod_tools." - ".$lang->add_new_thread_tool); + + $sub_tabs['thread_tools'] = array( + 'title' => $lang->thread_tools, + 'link' => "index.php?module=config-mod_tools" + ); + $sub_tabs['add_thread_tool'] = array( + 'title'=> $lang->add_new_thread_tool, + 'link' => "index.php?module=config-mod_tools&action=add_thread_tool", + 'description' => $lang->add_thread_tool_desc + ); + $sub_tabs['post_tools'] = array( + 'title' => $lang->post_tools, + 'link' => "index.php?module=config-mod_tools&action=post_tools", + ); + $sub_tabs['add_post_tool'] = array( + 'title'=> $lang->add_new_post_tool, + 'link' => "index.php?module=config-mod_tools&action=add_post_tool" + ); + + $page->output_nav_tabs($sub_tabs, 'add_thread_tool'); + + $form = new Form("index.php?module=config-mod_tools&action=add_thread_tool", 'post'); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['title'] = ''; + $mybb->input['description'] = ''; + $mybb->input['forum_1_forums'] = ''; + $forum_checked[1] = "checked=\"checked\""; + $forum_checked[2] = ''; + $mybb->input['group_1_groups'] = ''; + $group_checked[1] = "checked=\"checked\""; + $group_checked[2] = ''; + $mybb->input['confirmation'] = '0'; + $mybb->input['approvethread'] = ''; + $mybb->input['softdeletethread'] = ''; + $mybb->input['openthread'] = ''; + $mybb->input['stickthread'] = ''; + $mybb->input['move_1_forum'] = ''; + $mybb->input['move_2_redirect'] = '0'; + $mybb->input['move_3_redirecttime'] = ''; + $move_checked[1] = "checked=\"checked\""; + $move_checked[2] = ''; + $copy_checked[1] = "checked=\"checked\""; + $copy_checked[2] = ''; + $mybb->input['copy_1_forum'] = ''; + $mybb->input['deletethread'] = '0'; + $mybb->input['mergethreads'] = '0'; + $mybb->input['deletepoll'] = '0'; + $mybb->input['removeredirects'] = '0'; + $mybb->input['removesubscriptions'] = '0'; + $mybb->input['recountrebuild'] = '0'; + $mybb->input['threadprefix'] = '-1'; + $mybb->input['newsubject'] = '{subject}'; + $mybb->input['newreply'] = ''; + $mybb->input['newreplysubject'] = '{subject}'; + $mybb->input['pm_subject'] = ''; + $mybb->input['pm_message'] = ''; + } + + $form_container = new FormContainer($lang->general_options); + $form_container->output_row($lang->name." *", '', $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->short_description." *", '', $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + + $actions = " +
+
+
+
+ + + + + +
{$lang->forums_colon}".$form->generate_forum_select('forum_1_forums[]', $mybb->input['forum_1_forums'], array('multiple' => true, 'size' => 5))."
+
+
+ "; + $form_container->output_row($lang->available_in_forums." *", '', $actions); + + $actions = "
+
+
+
+ + + + + +
{$lang->groups_colon}".$form->generate_group_select('group_1_groups[]', $mybb->input['group_1_groups'], array('multiple' => true, 'size' => 5))."
+
+
+ "; + $form_container->output_row($lang->available_to_groups." *", '', $actions); + $form_container->output_row($lang->show_confirmation." *", '', $form->generate_yes_no_radio('confirmation', $mybb->input['confirmation'], array('style' => 'width: 2em;'))); + $form_container->end(); + + $approve_unapprove = array( + '' => $lang->no_change, + 'approve' => $lang->approve, + 'unapprove' => $lang->unapprove, + 'toggle' => $lang->toggle + ); + + $open_close = array( + '' => $lang->no_change, + 'open' => $lang->open, + 'close' => $lang->close, + 'toggle' => $lang->toggle + ); + + $stick_unstick = array( + '' => $lang->no_change, + 'stick' => $lang->stick, + 'unstick' => $lang->unstick, + 'toggle' => $lang->toggle + ); + + $form_container = new FormContainer($lang->thread_moderation); + $form_container->output_row($lang->approve_unapprove." *", '', $form->generate_select_box('approvethread', $approve_unapprove, $mybb->input['approvethread'], array('id' => 'approvethread')), 'approvethread'); + $form_container->output_row($lang->open_close_thread." *", '', $form->generate_select_box('openthread', $open_close, $mybb->input['openthread'], array('id' => 'openthread')), 'openthread'); + $form_container->output_row($lang->stick_unstick_thread." *", '', $form->generate_select_box('stickthread', $stick_unstick, $mybb->input['stickthread'], array('id' => 'stickthread')), 'stickthread'); + + + $actions = " +
+
+
+
+ + + + + + + + + + + + + +
{$lang->forum_to_move_to}".$form->generate_forum_select('move_1_forum', $mybb->input['move_1_forum'])."
{$lang->leave_redirect}".$form->generate_yes_no_radio('move_2_redirect', $mybb->input['move_2_redirect'], array('style' => 'width: 2em;'))."
{$lang->delete_redirect_after}".$form->generate_numeric_field('move_3_redirecttime', $mybb->input['move_3_redirecttime'], array('style' => 'width: 2em;'))." {$lang->days}
+
+
+ "; + $form_container->output_row($lang->move_thread." *", $lang->move_thread_desc, $actions); + + $actions = " +
+
+
+
+ + + + + +
{$lang->forum_to_copy_to}".$form->generate_forum_select('copy_1_forum', $mybb->input['copy_1_forum'])."
+
+
+ "; + $form_container->output_row($lang->copy_thread." *", '', $actions); + + $softdelete_restore = array( + '' => $lang->no_change, + 'restore' => $lang->restore, + 'softdelete' => $lang->softdelete, + 'toggle' => $lang->toggle + ); + + $form_container->output_row($lang->softdelete_restore_thread." *", '', $form->generate_select_box('softdeletethread', $softdelete_restore, $mybb->input['softdeletethread'], array('id' => 'softdeletethread')), 'softdeletethread'); + $form_container->output_row($lang->delete_thread." *", '', $form->generate_yes_no_radio('deletethread', $mybb->input['deletethread'], array('style' => 'width: 2em;'))); + $form_container->output_row($lang->merge_thread." *", $lang->merge_thread_desc, $form->generate_yes_no_radio('mergethreads', $mybb->input['mergethreads'], array('style' => 'width: 2em;'))); + $form_container->output_row($lang->delete_poll." *", '', $form->generate_yes_no_radio('deletepoll', $mybb->input['deletepoll'], array('style' => 'width: 2em;'))); + $form_container->output_row($lang->delete_redirects." *", '', $form->generate_yes_no_radio('removeredirects', $mybb->input['removeredirects'], array('style' => 'width: 2em;'))); + $form_container->output_row($lang->remove_subscriptions." *", '', $form->generate_yes_no_radio('removesubscriptions', $mybb->input['removesubscriptions'], array('style' => 'width: 2em;'))); + $form_container->output_row($lang->recount_rebuild." *", '', $form->generate_yes_no_radio('recountrebuild', $mybb->input['recountrebuild'], array('style' => 'width: 2em;'))); + + $threadprefixes = build_prefixes(); + if(!empty($threadprefixes)) + { + $thread_prefixes = array( + '-1' => $lang->no_change, + '0' => $lang->no_prefix + ); + + foreach($threadprefixes as $prefix) + { + $thread_prefixes[$prefix['pid']] = $prefix['prefix']; + } + + $form_container->output_row($lang->apply_thread_prefix." *", '', $form->generate_select_box('threadprefix', $thread_prefixes, $mybb->input['threadprefix'], array('id' => 'threadprefix')), 'threadprefix'); + } + + $form_container->output_row($lang->new_subject." *", $lang->new_subject_desc, $form->generate_text_box('newsubject', $mybb->input['newsubject'], array('id' => 'newsubject'))); + $form_container->end(); + + $form_container = new FormContainer($lang->add_new_reply); + $form_container->output_row($lang->add_new_reply, $lang->add_new_reply_desc, $form->generate_text_area('newreply', $mybb->input['newreply'], array('id' => 'newreply')), 'newreply'); + $form_container->output_row($lang->reply_subject, $lang->reply_subject_desc, $form->generate_text_box('newreplysubject', $mybb->input['newreplysubject'], array('id' => 'newreplysubject')), 'newreplysubject'); + $form_container->end(); + + $form_container = new FormContainer($lang->send_private_message); + $form_container->output_row($lang->private_message_message, $lang->private_message_message_desc, $form->generate_text_area('pm_message', $mybb->input['pm_message'], array('id' => 'pm_message')), 'pm_message'); + $form_container->output_row($lang->private_message_subject, $lang->private_message_subject_desc, $form->generate_text_box('pm_subject', $mybb->input['pm_subject'], array('id' => 'pm_subject')), 'pm_subject'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_thread_tool); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit_post_tool") +{ + $query = $db->simple_select("modtools", "COUNT(tid) as tools", "tid = '{$mybb->input['tid']}' AND type='p'"); + if($db->fetch_field($query, "tools") < 1) + { + flash_message($lang->error_invalid_post_tool, 'error'); + admin_redirect("index.php?module=config-mod_tools&action=post_tools"); + } + + $plugins->run_hooks("admin_config_mod_tools_edit_post_tool"); + + if($mybb->request_method == 'post') + { + if(trim($mybb->input['title']) == "") + { + $errors[] = $lang->error_missing_title; + } + + if(trim($mybb->input['description']) == "") + { + $errors[] = $lang->error_missing_description; + } + + if($mybb->input['forum_type'] == 2) + { + if(count($mybb->input['forum_1_forums']) < 1) + { + $errors[] = $lang->error_no_forums_selected; + } + } + else + { + $mybb->input['forum_1_forums'] = ''; + } + + if($mybb->input['group_type'] == 2) + { + if(count($mybb->input['group_1_groups']) < 1) + { + $errors[] = $lang->error_no_groups_selected; + } + } + else + { + $mybb->input['group_1_groups'] = ''; + } + + if($mybb->input['approvethread'] != '' && $mybb->input['approvethread'] != 'approve' && $mybb->input['approvethread'] != 'unapprove' && $mybb->input['approvethread'] != 'toggle') + { + $mybb->input['approvethread'] = ''; + } + + if($mybb->input['softdeletethread'] != '' && $mybb->input['softdeletethread'] != 'softdelete' && $mybb->input['softdeletethread'] != 'restore' && $mybb->input['softdeletethread'] != 'toggle') + { + $mybb->input['softdeletethread'] = ''; + } + + if($mybb->input['openthread'] != '' && $mybb->input['openthread'] != 'open' && $mybb->input['openthread'] != 'close' && $mybb->input['openthread'] != 'toggle') + { + $mybb->input['openthread'] = ''; + } + + if($mybb->input['stickthread'] != '' && $mybb->input['stickthread'] != 'stick' && $mybb->input['stickthread'] != 'unstick' && $mybb->input['stickthread'] != 'toggle') + { + $mybb->input['stickthread'] = ''; + } + + if($mybb->input['move_type'] == 2) + { + if(!$mybb->input['move_1_forum']) + { + $errors[] = $lang->error_no_move_forum_selected; + } + else + { + // Check that the destination forum is not a category + $query = $db->simple_select("forums", "type", "fid = '".(int)$mybb->input['move_1_forum']."'"); + if($db->fetch_field($query, "type") == "c") + { + $errors[] = $lang->error_forum_is_category; + } + } + } + else + { + $mybb->input['move_1_forum'] = ''; + $mybb->input['move_2_redirect'] = 0; + $mybb->input['move_3_redirecttime'] = ''; + } + + if($mybb->input['copy_type'] == 2) + { + if(!$mybb->input['copy_1_forum']) + { + $errors[] = $lang->error_no_copy_forum_selected; + } + else + { + $query = $db->simple_select("forums", "type", "fid = '".(int)$mybb->input['copy_1_forum']."'"); + if($db->fetch_field($query, "type") == "c") + { + $errors[] = $lang->error_forum_is_category; + } + } + } + else + { + $mybb->input['copy_1_forum'] = ''; + } + + if($mybb->input['approveposts'] != '' && $mybb->input['approveposts'] != 'approve' && $mybb->input['approveposts'] != 'unapprove' && $mybb->input['approveposts'] != 'toggle') + { + $mybb->input['approveposts'] = ''; + } + + if($mybb->input['softdeleteposts'] != '' && $mybb->input['softdeleteposts'] != 'approve' && $mybb->input['softdeleteposts'] != 'unapprove' && $mybb->input['softdeleteposts'] != 'toggle') + { + $mybb->input['softdeleteposts'] = ''; + } + + if($mybb->input['splitposts'] < -2) + { + $mybb->input['splitposts'] = -1; + } + + if($mybb->input['splitpostsclose'] == 1) + { + $mybb->input['splitpostsclose'] = 'close'; + } + else + { + $mybb->input['splitpostsclose'] = ''; + } + + if($mybb->input['splitpostsstick'] == 1) + { + $mybb->input['splitpostsstick'] = 'stick'; + } + else + { + $mybb->input['splitpostsstick'] = ''; + } + + if($mybb->input['splitpostsunapprove'] == 1) + { + $mybb->input['splitpostsunapprove'] = 'unapprove'; + } + else + { + $mybb->input['splitpostsunapprove'] = ''; + } + + if(!$errors) + { + $thread_options = array( + 'confirmation' => $mybb->input['confirmation'], + 'deletethread' => $mybb->input['deletethread'], + 'softdeletethread' => $mybb->input['softdeletethread'], + 'approvethread' => $mybb->input['approvethread'], + 'openthread' => $mybb->input['openthread'], + 'stickthread' => $mybb->input['stickthread'], + 'movethread' => (int)$mybb->input['move_1_forum'], + 'movethreadredirect' => $mybb->input['move_2_redirect'], + 'movethreadredirectexpire' => (int)$mybb->input['move_3_redirecttime'], + 'copythread' => (int)$mybb->input['copy_1_forum'], + 'newsubject' => $mybb->input['newsubject'], + 'addreply' => $mybb->input['newreply'], + 'replysubject' => $mybb->input['newreplysubject'], + 'pm_subject' => $mybb->input['pm_subject'], + 'pm_message' => $mybb->input['pm_message'], + 'threadprefix' => (int)$mybb->input['threadprefix'] + ); + + if(stripos($mybb->input['splitpostsnewsubject'], '{subject}') === false) + { + $mybb->input['splitpostsnewsubject'] = '{subject}'.$mybb->input['splitpostsnewsubject']; + } + + $post_options = array( + 'deleteposts' => $mybb->input['deleteposts'], + 'softdeleteposts' => $mybb->input['softdeleteposts'], + 'mergeposts' => $mybb->input['mergeposts'], + 'approveposts' => $mybb->input['approveposts'], + 'splitposts' => (int)$mybb->input['splitposts'], + 'splitpostsclose' => $mybb->input['splitpostsclose'], + 'splitpostsstick' => $mybb->input['splitpostsstick'], + 'splitpostsunapprove' => $mybb->input['splitpostsunapprove'], + 'splitthreadprefix' => (int)$mybb->input['splitthreadprefix'], + 'splitpostsnewsubject' => $mybb->input['splitpostsnewsubject'], + 'splitpostsaddreply' => $mybb->input['splitpostsaddreply'], + 'splitpostsreplysubject' => $mybb->input['splitpostsreplysubject'] + ); + + $update_tool['type'] = 'p'; + $update_tool['threadoptions'] = $db->escape_string(serialize($thread_options)); + $update_tool['postoptions'] = $db->escape_string(serialize($post_options)); + $update_tool['name'] = $db->escape_string($mybb->input['title']); + $update_tool['description'] = $db->escape_string($mybb->input['description']); + $update_tool['forums'] = ''; + $update_tool['groups'] = ''; + + if($mybb->input['forum_type'] == 2) + { + if(is_array($mybb->input['forum_1_forums'])) + { + $checked = array(); + + foreach($mybb->input['forum_1_forums'] as $fid) + { + $checked[] = (int)$fid; + } + + $update_tool['forums'] = implode(',', $checked); + } + } + else + { + $update_tool['forums'] = "-1"; + } + + if($mybb->input['group_type'] == 2) + { + if(is_array($mybb->input['group_1_groups'])) + { + $checked = array(); + + foreach($mybb->input['group_1_groups'] as $gid) + { + $checked[] = (int)$gid; + } + + $update_tool['groups'] = implode(',', $checked); + } + } + else + { + $update_tool['groups'] = "-1"; + } + + $plugins->run_hooks("admin_config_mod_tools_edit_post_tool_commit"); + + $db->update_query("modtools", $update_tool, "tid = '{$mybb->input['tid']}'"); + + // Log admin action + log_admin_action($mybb->input['tid'], $mybb->input['title']); + $cache->update_forumsdisplay(); + + flash_message($lang->success_mod_tool_updated, 'success'); + admin_redirect("index.php?module=config-mod_tools&action=post_tools"); + } + } + + $page->add_breadcrumb_item($lang->edit_post_tool); + $page->output_header($lang->mod_tools." - ".$lang->edit_post_tool); + + $sub_tabs['edit_post_tool'] = array( + "title" => $lang->edit_post_tool, + "description" => $lang->edit_post_tool_desc, + "link" => "index.php?module=config-mod_tools" + ); + + $page->output_nav_tabs($sub_tabs, 'edit_post_tool'); + + $form = new Form("index.php?module=config-mod_tools&action=edit_post_tool", 'post'); + echo $form->generate_hidden_field("tid", $mybb->input['tid']); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $query = $db->simple_select("modtools", "*", "tid = '{$mybb->input['tid']}'"); + $modtool = $db->fetch_array($query); + $thread_options = my_unserialize($modtool['threadoptions']); + $post_options = my_unserialize($modtool['postoptions']); + + $mybb->input['title'] = $modtool['name']; + $mybb->input['description'] = $modtool['description']; + $mybb->input['forum_1_forums'] = explode(",", $modtool['forums']); + $mybb->input['group_1_groups'] = explode(",", $modtool['groups']); + + if(!$modtool['forums'] || $modtool['forums'] == -1) + { + $forum_checked[1] = "checked=\"checked\""; + $forum_checked[2] = ''; + } + else + { + $forum_checked[1] = ''; + $forum_checked[2] = "checked=\"checked\""; + } + + if(!$modtool['groups'] || $modtool['groups'] == -1) + { + $group_checked[1] = "checked=\"checked\""; + $group_checked[2] = ''; + } + else + { + $group_checked[1] = ''; + $group_checked[2] = "checked=\"checked\""; + } + + $mybb->input['confirmation'] = $thread_options['confirmation']; + $mybb->input['approvethread'] = $thread_options['approvethread']; + $mybb->input['softdeletethread'] = $thread_options['softdeletethread']; + $mybb->input['openthread'] = $thread_options['openthread']; + $mybb->input['stickthread'] = $thread_options['stickthread']; + $mybb->input['move_1_forum'] = $thread_options['movethread']; + $mybb->input['move_2_redirect'] = $thread_options['movethreadredirect']; + $mybb->input['move_3_redirecttime'] = $thread_options['movethreadredirectexpire']; + + if(!$thread_options['movethread']) + { + $move_checked[1] = "checked=\"checked\""; + $move_checked[2] = ''; + } + else + { + $move_checked[1] = ''; + $move_checked[2] = "checked=\"checked\""; + } + + if(!$thread_options['copythread']) + { + $copy_checked[1] = "checked=\"checked\""; + $copy_checked[2] = ''; + } + else + { + $copy_checked[1] = ''; + $copy_checked[2] = "checked=\"checked\""; + } + + $mybb->input['copy_1_forum'] = $thread_options['copythread']; + $mybb->input['deletethread'] = $thread_options['deletethread']; + $mybb->input['threadprefix'] = $thread_options['threadprefix']; + $mybb->input['newsubject'] = $thread_options['newsubject']; + $mybb->input['newreply'] = $thread_options['addreply']; + $mybb->input['newreplysubject'] = $thread_options['replysubject']; + $mybb->input['pm_subject'] = $thread_options['pm_subject']; + $mybb->input['pm_message'] = $thread_options['pm_message']; + + if($post_options['splitposts'] == '-1') + { + $do_not_split_checked = ' selected="selected"'; + $split_same_checked = ''; + } + else if($post_options['splitposts'] == '-2') + { + $do_not_split_checked = ''; + $split_same_checked = ' selected="selected"'; + } + + $mybb->input['softdeleteposts'] = $post_options['softdeleteposts']; + $mybb->input['deleteposts'] = $post_options['deleteposts']; + $mybb->input['mergeposts'] = $post_options['mergeposts']; + $mybb->input['approveposts'] = $post_options['approveposts']; + + if($post_options['splitpostsclose'] == 'close') + { + $mybb->input['splitpostsclose'] = '1'; + } + else + { + $mybb->input['splitpostsclose'] = '0'; + } + + if($post_options['splitpostsstick'] == 'stick') + { + $mybb->input['splitpostsstick'] = '1'; + } + else + { + $mybb->input['splitpostsstick'] = '0'; + } + + if($post_options['splitpostsunapprove'] == 'unapprove') + { + $mybb->input['splitpostsunapprove'] = '1'; + } + else + { + $mybb->input['splitpostsunapprove'] = '0'; + } + + $mybb->input['splitposts'] = $post_options['splitposts']; + $mybb->input['splitthreadprefix'] = $post_options['splitthreadprefix']; + $mybb->input['splitpostsnewsubject'] = $post_options['splitpostsnewsubject']; + $mybb->input['splitpostsaddreply'] = $post_options['splitpostsaddreply']; + $mybb->input['splitpostsreplysubject'] = $post_options['splitpostsreplysubject']; + } + + $form_container = new FormContainer($lang->general_options); + $form_container->output_row($lang->name." *", '', $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->short_description." *", '', $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + + $actions = " +
+
+
+
+ + + + + +
{$lang->forums_colon}".$form->generate_forum_select('forum_1_forums[]', $mybb->input['forum_1_forums'], array('multiple' => true, 'size' => 5))."
+
+
+ "; + $form_container->output_row($lang->available_in_forums." *", '', $actions); + + $actions = "
+
+
+
+ + + + + +
{$lang->groups_colon}".$form->generate_group_select('group_1_groups[]', $mybb->input['group_1_groups'], array('multiple' => true, 'size' => 5))."
+
+
+ "; + $form_container->output_row($lang->available_to_groups." *", '', $actions); + $form_container->output_row($lang->show_confirmation." *", '', $form->generate_yes_no_radio('confirmation', $mybb->input['confirmation'], array('style' => 'width: 2em;'))); + $form_container->end(); + + $approve_unapprove = array( + '' => $lang->no_change, + 'approve' => $lang->approve, + 'unapprove' => $lang->unapprove, + 'toggle' => $lang->toggle + ); + + $form_container = new FormContainer($lang->inline_post_moderation); + + $softdelete_restore = array( + '' => $lang->no_change, + 'restore' => $lang->restore, + 'softdelete' => $lang->softdelete, + 'toggle' => $lang->toggle + ); + + $form_container->output_row($lang->softdelete_restore_posts." *", '', $form->generate_select_box('softdeleteposts', $softdelete_restore, $mybb->input['softdeleteposts'], array('id' => 'softdeleteposts')), 'softdeleteposts'); + $form_container->output_row($lang->delete_posts." *", '', $form->generate_yes_no_radio('deleteposts', $mybb->input['deleteposts'])); + $form_container->output_row($lang->merge_posts." *", $lang->merge_posts_desc, $form->generate_yes_no_radio('mergeposts', $mybb->input['mergeposts'])); + $form_container->output_row($lang->approve_unapprove_posts." *", '', $form->generate_select_box('approveposts', $approve_unapprove, $mybb->input['approveposts'], array('id' => 'approveposts')), 'approveposts'); + $form_container->end(); + + $selectoptions = "\n"; + $selectoptions .= "\n"; + + $form_container = new FormContainer($lang->split_posts); + $form_container->output_row($lang->split_posts2." *", '', $form->generate_forum_select('splitposts', $mybb->input['splitposts'])); + $form_container->output_row($lang->close_split_thread." *", '', $form->generate_yes_no_radio('splitpostsclose', $mybb->input['splitpostsclose'])); + $form_container->output_row($lang->stick_split_thread." *", '', $form->generate_yes_no_radio('splitpostsstick', $mybb->input['splitpostsstick'])); + $form_container->output_row($lang->unapprove_split_thread." *", '', $form->generate_yes_no_radio('splitpostsunapprove', $mybb->input['splitpostsunapprove'])); + + $splitthreadprefix = build_prefixes(); + if(!empty($splitthreadprefix)) + { + $split_thread_prefixes = array( + '0' => $lang->no_prefix + ); + + foreach($splitthreadprefix as $prefix) + { + $split_thread_prefixes[$prefix['pid']] = $prefix['prefix']; + } + + $form_container->output_row($lang->split_thread_prefix." *", '', $form->generate_select_box('splitthreadprefix', $split_thread_prefixes, array((int)$mybb->input['splitthreadprefix']), array('id' => 'splitthreadprefix')), 'splitthreadprefix'); + } + + $form_container->output_row($lang->split_thread_subject, $lang->split_thread_subject_desc, $form->generate_text_box('splitpostsnewsubject', $mybb->input['splitpostsnewsubject'], array('id' => 'splitpostsnewsubject ')), 'newreplysubject'); + $form_container->output_row($lang->add_new_split_reply, $lang->add_new_split_reply_desc, $form->generate_text_area('splitpostsaddreply', $mybb->input['splitpostsaddreply'], array('id' => 'splitpostsaddreply')), 'splitpostsaddreply'); + $form_container->output_row($lang->split_reply_subject, $lang->split_reply_subject_desc, $form->generate_text_box('splitpostsreplysubject', $mybb->input['splitpostsreplysubject'], array('id' => 'splitpostsreplysubject')), 'splitpostsreplysubject'); + $form_container->end(); + + $open_close = array( + '' => $lang->no_change, + 'open' => $lang->open, + 'close' => $lang->close, + 'toggle' => $lang->toggle + ); + + $stick_unstick = array( + '' => $lang->no_change, + 'stick' => $lang->stick, + 'unstick' => $lang->unstick, + 'toggle' => $lang->toggle + ); + + $form_container = new FormContainer($lang->thread_moderation); + $form_container->output_row($lang->approve_unapprove." *", '', $form->generate_select_box('approvethread', $approve_unapprove, $mybb->input['approvethread'], array('id' => 'approvethread')), 'approvethread'); + $form_container->output_row($lang->open_close_thread." *", '', $form->generate_select_box('openthread', $open_close, $mybb->input['openthread'], array('id' => 'openthread')), 'openthread'); + $form_container->output_row($lang->stick_unstick_thread." *", '', $form->generate_select_box('stickthread', $stick_unstick, $mybb->input['stickthread'], array('id' => 'stickthread')), 'stickthread'); + + + $actions = " +
+
+
+
+ + + + + + + + + + + + + +
{$lang->forum_to_move_to}".$form->generate_forum_select('move_1_forum', $mybb->input['move_1_forum'])."
{$lang->leave_redirect}".$form->generate_yes_no_radio('move_2_redirect', $mybb->input['move_2_redirect'])."
{$lang->delete_redirect_after}".$form->generate_numeric_field('move_3_redirecttime', $mybb->input['move_3_redirecttime'], array('style' => 'width: 2em;'))." {$lang->days}
+
+
+ "; + $form_container->output_row($lang->move_thread." *", $lang->move_thread_desc, $actions); + + $actions = " +
+
+
+
+ + + + + +
{$lang->forum_to_copy_to}".$form->generate_forum_select('copy_1_forum', $mybb->input['copy_1_forum'])."
+
+
+ "; + $form_container->output_row($lang->copy_thread." *", '', $actions); + $form_container->output_row($lang->softdelete_restore_thread." *", '', $form->generate_select_box('softdeletethread', $softdelete_restore, $mybb->input['softdeletethread'], array('id' => 'softdeletethread')), 'softdeletethread'); + $form_container->output_row($lang->delete_thread." *", '', $form->generate_yes_no_radio('deletethread', $mybb->input['deletethread'])); + + $threadprefixes = build_prefixes(); + if(!empty($threadprefixes)) + { + $thread_prefixes = array( + '-1' => $lang->no_change, + '0' => $lang->no_prefix + ); + + foreach($threadprefixes as $prefix) + { + $thread_prefixes[$prefix['pid']] = $prefix['prefix']; + } + + $form_container->output_row($lang->apply_thread_prefix." *", '', $form->generate_select_box('threadprefix', $thread_prefixes, array((int)$mybb->input['threadprefix']), array('id' => 'threadprefix')), 'threadprefix'); + } + + $form_container->output_row($lang->new_subject." *", $lang->new_subject_desc, $form->generate_text_box('newsubject', $mybb->input['newsubject'])); + $form_container->end(); + + $form_container = new FormContainer($lang->add_new_reply); + $form_container->output_row($lang->add_new_reply, $lang->add_new_reply_desc, $form->generate_text_area('newreply', $mybb->input['newreply']), 'newreply'); + $form_container->output_row($lang->reply_subject, $lang->reply_subject_desc, $form->generate_text_box('newreplysubject', $mybb->input['newreplysubject'], array('id' => 'newreplysubject')), 'newreplysubject'); + $form_container->end(); + + $form_container = new FormContainer($lang->send_private_message); + $form_container->output_row($lang->private_message_message, $lang->private_message_message_desc, $form->generate_text_area('pm_message', $mybb->input['pm_message'], array('id' => 'pm_message')), 'pm_message'); + $form_container->output_row($lang->private_message_subject, $lang->private_message_subject_desc, $form->generate_text_box('pm_subject', $mybb->input['pm_subject'], array('id' => 'pm_subject')), 'pm_subject'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_post_tool); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "add_post_tool") +{ + $plugins->run_hooks("admin_config_mod_tools_add_post_tool"); + + if($mybb->request_method == 'post') + { + if(trim($mybb->input['title']) == "") + { + $errors[] = $lang->error_missing_title; + } + + if(trim($mybb->input['description']) == "") + { + $errors[] = $lang->error_missing_description; + } + + if($mybb->input['forum_type'] == 2) + { + $forum_checked[1] = ''; + $forum_checked[2] = "checked=\"checked\""; + + if(count($mybb->input['forum_1_forums']) < 1) + { + $errors[] = $lang->error_no_forums_selected; + } + } + else + { + $forum_checked[1] = "checked=\"checked\""; + $forum_checked[2] = ''; + + $mybb->input['forum_1_forums'] = ''; + } + + if($mybb->input['group_type'] == 2) + { + $group_checked[1] = ''; + $group_checked[2] = "checked=\"checked\""; + + if(count($mybb->input['group_1_groups']) < 1) + { + $errors[] = $lang->error_no_groups_selected; + } + } + else + { + $group_checked[1] = "checked=\"checked\""; + $group_checked[2] = ''; + + $mybb->input['group_1_groups'] = ''; + } + + if($mybb->input['approvethread'] != '' && $mybb->input['approvethread'] != 'approve' && $mybb->input['approvethread'] != 'unapprove' && $mybb->input['approvethread'] != 'toggle') + { + $mybb->input['approvethread'] = ''; + } + + if($mybb->input['softdeletethread'] != '' && $mybb->input['softdeletethread'] != 'softdelete' && $mybb->input['softdeletethread'] != 'restore' && $mybb->input['softdeletethread'] != 'toggle') + { + $mybb->input['softdeletethread'] = ''; + } + + if($mybb->input['openthread'] != '' && $mybb->input['openthread'] != 'open' && $mybb->input['openthread'] != 'close' && $mybb->input['openthread'] != 'toggle') + { + $mybb->input['openthread'] = ''; + } + + if($mybb->input['stickthread'] != '' && $mybb->input['stickthread'] != 'stick' && $mybb->input['stickthread'] != 'unstick' && $mybb->input['stickthread'] != 'toggle') + { + $mybb->input['stickthread'] = ''; + } + + if(!(int)$mybb->input['threadprefix']) + { + $mybb->input['threadprefix'] = ''; + } + + if($mybb->input['move_type'] == 2) + { + $move_checked[1] = ''; + $move_checked[2] = "checked=\"checked\""; + + if(!$mybb->input['move_1_forum']) + { + $errors[] = $lang->error_no_move_forum_selected; + } + else + { + // Check that the destination forum is not a category + $query = $db->simple_select("forums", "type", "fid = '".(int)$mybb->input['move_1_forum']."'"); + if($db->fetch_field($query, "type") == "c") + { + $errors[] = $lang->error_forum_is_category; + } + } + } + else + { + $move_checked[1] = "checked=\"checked\""; + $move_checked[2] = ''; + + $mybb->input['move_1_forum'] = ''; + $mybb->input['move_2_redirect'] = 0; + $mybb->input['move_3_redirecttime'] = ''; + } + + if($mybb->input['copy_type'] == 2) + { + $copy_checked[1] = ''; + $copy_checked[2] = "checked=\"checked\""; + + if(!$mybb->input['copy_1_forum']) + { + $errors[] = $lang->error_no_copy_forum_selected; + } + else + { + $query = $db->simple_select("forums", "type", "fid = '".(int)$mybb->input['copy_1_forum']."'"); + if($db->fetch_field($query, "type") == "c") + { + $errors[] = $lang->error_forum_is_category; + } + } + } + else + { + $copy_checked[1] = 'checked=\"checked\"'; + $copy_checked[2] = ''; + + $mybb->input['copy_1_forum'] = ''; + } + + if($mybb->input['approveposts'] != '' && $mybb->input['approveposts'] != 'approve' && $mybb->input['approveposts'] != 'unapprove' && $mybb->input['approveposts'] != 'toggle') + { + $mybb->input['approveposts'] = ''; + } + + if($mybb->input['softdeleteposts'] != '' && $mybb->input['softdeleteposts'] != 'softdelete' && $mybb->input['softdeleteposts'] != 'restore' && $mybb->input['softdeleteposts'] != 'toggle') + { + $mybb->input['softdeleteposts'] = ''; + } + + if($mybb->input['splitposts'] < -2) + { + $mybb->input['splitposts'] = -1; + } + + if($mybb->input['splitpostsclose'] == 1) + { + $mybb->input['splitpostsclose'] = 'close'; + } + else + { + $mybb->input['splitpostsclose'] = ''; + } + + if($mybb->input['splitpostsstick'] == 1) + { + $mybb->input['splitpostsstick'] = 'stick'; + } + else + { + $mybb->input['splitpostsstick'] = ''; + } + + if($mybb->input['splitpostsunapprove'] == 1) + { + $mybb->input['splitpostsunapprove'] = 'unapprove'; + } + else + { + $mybb->input['splitpostsunapprove'] = ''; + } + + if(!(int)$mybb->input['splitthreadprefix']) + { + $mybb->input['splitthreadprefix'] = ''; + } + + if(!$errors) + { + $thread_options = array( + 'confirmation' => $mybb->input['confirmation'], + 'deletethread' => $mybb->input['deletethread'], + 'softdeletethread' => $mybb->input['softdeletethread'], + 'approvethread' => $mybb->input['approvethread'], + 'openthread' => $mybb->input['openthread'], + 'stickthread' => $mybb->input['stickthread'], + 'movethread' => (int)$mybb->input['move_1_forum'], + 'movethreadredirect' => $mybb->input['move_2_redirect'], + 'movethreadredirectexpire' => (int)$mybb->input['move_3_redirecttime'], + 'copythread' => (int)$mybb->input['copy_1_forum'], + 'newsubject' => $mybb->input['newsubject'], + 'addreply' => $mybb->input['newreply'], + 'replysubject' => $mybb->input['newreplysubject'], + 'pm_subject' => $mybb->input['pm_subject'], + 'pm_message' => $mybb->input['pm_message'], + 'threadprefix' => (int)$mybb->input['threadprefix'] + ); + + if(stripos($mybb->input['splitpostsnewsubject'], '{subject}') === false) + { + $mybb->input['splitpostsnewsubject'] = '{subject}'.$mybb->input['splitpostsnewsubject']; + } + + $post_options = array( + 'deleteposts' => $mybb->input['deleteposts'], + 'softdeleteposts' => $mybb->input['softdeleteposts'], + 'mergeposts' => $mybb->input['mergeposts'], + 'approveposts' => $mybb->input['approveposts'], + 'splitposts' => (int)$mybb->input['splitposts'], + 'splitpostsclose' => $mybb->input['splitpostsclose'], + 'splitpostsstick' => $mybb->input['splitpostsstick'], + 'splitpostsunapprove' => $mybb->input['splitpostsunapprove'], + 'splitthreadprefix' => (int)$mybb->input['splitthreadprefix'], + 'splitpostsnewsubject' => $mybb->input['splitpostsnewsubject'], + 'splitpostsaddreply' => $mybb->input['splitpostsaddreply'], + 'splitpostsreplysubject' => $mybb->input['splitpostsreplysubject'] + ); + + $new_tool['type'] = 'p'; + $new_tool['threadoptions'] = $db->escape_string(serialize($thread_options)); + $new_tool['postoptions'] = $db->escape_string(serialize($post_options)); + $new_tool['name'] = $db->escape_string($mybb->input['title']); + $new_tool['description'] = $db->escape_string($mybb->input['description']); + $new_tool['forums'] = ''; + $new_tool['groups'] = ''; + + if($mybb->input['forum_type'] == 2) + { + if(is_array($mybb->input['forum_1_forums'])) + { + $checked = array(); + + foreach($mybb->input['forum_1_forums'] as $fid) + { + $checked[] = (int)$fid; + } + + $new_tool['forums'] = implode(',', $checked); + } + } + else + { + $new_tool['forums'] = "-1"; + } + + if($mybb->input['group_type'] == 2) + { + if(is_array($mybb->input['group_1_groups'])) + { + $checked = array(); + + foreach($mybb->input['group_1_groups'] as $gid) + { + $checked[] = (int)$gid; + } + + $new_tool['groups'] = implode(',', $checked); + } + } + else + { + $new_tool['groups'] = "-1"; + } + + $tid = $db->insert_query("modtools", $new_tool); + + $plugins->run_hooks("admin_config_mod_tools_add_post_tool_commit"); + + // Log admin action + log_admin_action($tid, $mybb->input['title']); + $cache->update_forumsdisplay(); + + flash_message($lang->success_mod_tool_created, 'success'); + admin_redirect("index.php?module=config-mod_tools&action=post_tools"); + } + } + + $page->add_breadcrumb_item($lang->add_new_post_tool); + $page->output_header($lang->mod_tools." - ".$lang->add_new_post_tool); + + $sub_tabs['thread_tools'] = array( + 'title' => $lang->thread_tools, + 'link' => "index.php?module=config-mod_tools" + ); + $sub_tabs['add_thread_tool'] = array( + 'title'=> $lang->add_new_thread_tool, + 'link' => "index.php?module=config-mod_tools&action=add_thread_tool" + ); + $sub_tabs['post_tools'] = array( + 'title' => $lang->post_tools, + 'link' => "index.php?module=config-mod_tools&action=post_tools", + ); + $sub_tabs['add_post_tool'] = array( + 'title'=> $lang->add_new_post_tool, + 'link' => "index.php?module=config-mod_tools&action=add_post_tool", + 'description' => $lang->add_post_tool_desc + ); + + $page->output_nav_tabs($sub_tabs, 'add_post_tool'); + + $form = new Form("index.php?module=config-mod_tools&action=add_post_tool", 'post'); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['title'] = ''; + $mybb->input['description'] = ''; + $mybb->input['forum_1_forums'] = ''; + $forum_checked[1] = "checked=\"checked\""; + $forum_checked[2] = ''; + $mybb->input['group_1_groups'] = ''; + $group_checked[1] = "checked=\"checked\""; + $group_checked[2] = ''; + $mybb->input['confirmation'] = '0'; + $mybb->input['approvethread'] = ''; + $mybb->input['softdeletethread'] = ''; + $mybb->input['openthread'] = ''; + $mybb->input['stickthread'] = ''; + $mybb->input['move_1_forum'] = ''; + $mybb->input['move_2_redirect'] = '0'; + $mybb->input['move_3_redirecttime'] = ''; + $move_checked[1] = "checked=\"checked\""; + $move_checked[2] = ''; + $copy_checked[1] = "checked=\"checked\""; + $copy_checked[2] = ''; + $mybb->input['copy_1_forum'] = ''; + $mybb->input['deletethread'] = '0'; + $mybb->input['threadprefix'] = '-1'; + $mybb->input['newsubject'] = '{subject}'; + $mybb->input['newreply'] = ''; + $mybb->input['newreplysubject'] = '{subject}'; + $do_not_split_checked = ' selected="selected"'; + $split_same_checked = ''; + $mybb->input['deleteposts'] = '0'; + $mybb->input['mergeposts'] = '0'; + $mybb->input['approveposts'] = ''; + $mybb->input['softdeleteposts'] = ''; + $mybb->input['splitposts'] = '-1'; + $mybb->input['splitpostsclose'] = '0'; + $mybb->input['splitpostsstick'] = '0'; + $mybb->input['splitpostsunapprove'] = '0'; + $mybb->input['splitthreadprefix'] = '0'; + $mybb->input['splitpostsnewsubject'] = '{subject}'; + $mybb->input['splitpostsaddreply'] = ''; + $mybb->input['splitpostsreplysubject'] = '{subject}'; + } + + $form_container = new FormContainer($lang->general_options); + $form_container->output_row($lang->name." *", '', $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->short_description." *", '', $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + + $actions = " +
+
+
+
+ + + + + +
{$lang->forums_colon}".$form->generate_forum_select('forum_1_forums[]', $mybb->input['forum_1_forums'], array('multiple' => true, 'size' => 5))."
+
+
+ "; + $form_container->output_row($lang->available_in_forums." *", '', $actions); + + $actions = "
+
+
+
+ + + + + +
{$lang->groups_colon}".$form->generate_group_select('group_1_groups[]', $mybb->input['group_1_groups'], array('multiple' => true, 'size' => 5))."
+
+
+ "; + $form_container->output_row($lang->available_to_groups." *", '', $actions); + $form_container->output_row($lang->show_confirmation." *", '', $form->generate_yes_no_radio('confirmation', $mybb->input['confirmation'], array('style' => 'width: 2em;'))); + $form_container->end(); + + $approve_unapprove = array( + '' => $lang->no_change, + 'approve' => $lang->approve, + 'unapprove' => $lang->unapprove, + 'toggle' => $lang->toggle + ); + + $form_container = new FormContainer($lang->inline_post_moderation); + + $softdelete_restore = array( + '' => $lang->no_change, + 'restore' => $lang->restore, + 'softdelete' => $lang->softdelete, + 'toggle' => $lang->toggle + ); + + $form_container->output_row($lang->softdelete_restore_posts." *", '', $form->generate_select_box('softdeleteposts', $softdelete_restore, $mybb->input['softdeleteposts'], array('id' => 'softdeleteposts')), 'softdeleteposts'); + $form_container->output_row($lang->delete_posts." *", '', $form->generate_yes_no_radio('deleteposts', $mybb->input['deleteposts'])); + $form_container->output_row($lang->merge_posts." *", $lang->merge_posts_desc, $form->generate_yes_no_radio('mergeposts', $mybb->input['mergeposts'])); + $form_container->output_row($lang->approve_unapprove_posts." *", '', $form->generate_select_box('approveposts', $approve_unapprove, $mybb->input['approveposts'], array('id' => 'approveposts')), 'approveposts'); + $form_container->end(); + + $selectoptions = "\n"; + $selectoptions .= "\n"; + + $form_container = new FormContainer($lang->split_posts); + $form_container->output_row($lang->split_posts2." *", '', $form->generate_forum_select('splitposts', $mybb->input['splitposts'])); + $form_container->output_row($lang->close_split_thread." *", '', $form->generate_yes_no_radio('splitpostsclose', $mybb->input['splitpostsclose'])); + $form_container->output_row($lang->stick_split_thread." *", '', $form->generate_yes_no_radio('splitpostsstick', $mybb->input['splitpostsstick'])); + $form_container->output_row($lang->unapprove_split_thread." *", '', $form->generate_yes_no_radio('splitpostsunapprove', $mybb->input['splitpostsunapprove'])); + + $splitthreadprefix = build_prefixes(); + if(!empty($splitthreadprefix)) + { + $split_thread_prefixes = array( + '0' => $lang->no_prefix + ); + + foreach($splitthreadprefix as $prefix) + { + $split_thread_prefixes[$prefix['pid']] = $prefix['prefix']; + } + + $form_container->output_row($lang->split_thread_prefix." *", '', $form->generate_select_box('splitthreadprefix', $split_thread_prefixes, array((int)$mybb->input['splitthreadprefix']), array('id' => 'splitthreadprefix')), 'splitthreadprefix'); + } + + $form_container->output_row($lang->split_thread_subject, $lang->split_thread_subject_desc, $form->generate_text_box('splitpostsnewsubject', $mybb->input['splitpostsnewsubject'], array('id' => 'splitpostsnewsubject ')), 'newreplysubject'); + $form_container->output_row($lang->add_new_split_reply, $lang->add_new_split_reply_desc, $form->generate_text_area('splitpostsaddreply', $mybb->input['splitpostsaddreply'], array('id' => 'splitpostsaddreply')), 'splitpostsaddreply'); + $form_container->output_row($lang->split_reply_subject, $lang->split_reply_subject_desc, $form->generate_text_box('splitpostsreplysubject', $mybb->input['splitpostsreplysubject'], array('id' => 'splitpostsreplysubject')), 'splitpostsreplysubject'); + $form_container->end(); + + $open_close = array( + '' => $lang->no_change, + 'open' => $lang->open, + 'close' => $lang->close, + 'toggle' => $lang->toggle + ); + + $stick_unstick = array( + '' => $lang->no_change, + 'stick' => $lang->stick, + 'unstick' => $lang->unstick, + 'toggle' => $lang->toggle + ); + + + $form_container = new FormContainer($lang->thread_moderation); + $form_container->output_row($lang->approve_unapprove." *", '', $form->generate_select_box('approvethread', $approve_unapprove, $mybb->input['approvethread'], array('id' => 'approvethread')), 'approvethread'); + $form_container->output_row($lang->open_close_thread." *", '', $form->generate_select_box('openthread', $open_close, $mybb->input['openthread'], array('id' => 'openthread')), 'openthread'); + $form_container->output_row($lang->stick_unstick_thread." *", '', $form->generate_select_box('stickthread', $stick_unstick, $mybb->input['stickthread'], array('id' => 'stickthread')), 'stickthread'); + + + $actions = " +
+
+
+
+ + + + + + + + + + + + + +
{$lang->forum_to_move_to}".$form->generate_forum_select('move_1_forum', $mybb->input['move_1_forum'])."
{$lang->leave_redirect}".$form->generate_yes_no_radio('move_2_redirect', $mybb->input['move_2_redirect'])."
{$lang->delete_redirect_after}".$form->generate_numeric_field('move_3_redirecttime', $mybb->input['move_3_redirecttime'], array('style' => 'width: 2em;'))." {$lang->days}
+
+
+ "; + $form_container->output_row($lang->move_thread." *", $lang->move_thread_desc, $actions); + + $actions = " +
+
+
+
+ + + + + +
{$lang->forum_to_copy_to}".$form->generate_forum_select('copy_1_forum', $mybb->input['copy_1_forum'])."
+
+
+ "; + $form_container->output_row($lang->copy_thread." *", '', $actions); + $form_container->output_row($lang->softdelete_restore_thread." *", '', $form->generate_select_box('softdeletethread', $softdelete_restore, $mybb->input['softdeletethread'], array('id' => 'softdeletethread')), 'softdeletethread'); + $form_container->output_row($lang->delete_thread." *", '', $form->generate_yes_no_radio('deletethread', $mybb->input['deletethread'])); + + $threadprefixes = build_prefixes(); + if(!empty($threadprefixes)) + { + $thread_prefixes = array( + '-1' => $lang->no_change, + '0' => $lang->no_prefix + ); + + foreach($threadprefixes as $prefix) + { + $thread_prefixes[$prefix['pid']] = $prefix['prefix']; + } + + $form_container->output_row($lang->apply_thread_prefix." *", '', $form->generate_select_box('threadprefix', $thread_prefixes, $mybb->input['threadprefix'], array('id' => 'threadprefix')), 'threadprefix'); + } + + $form_container->output_row($lang->new_subject." *", $lang->new_subject_desc, $form->generate_text_box('newsubject', $mybb->input['newsubject'])); + $form_container->end(); + + $form_container = new FormContainer($lang->add_new_reply); + $form_container->output_row($lang->add_new_reply, $lang->add_new_reply_desc, $form->generate_text_area('newreply', $mybb->input['newreply'], array('id' => 'newreply')), 'newreply'); + $form_container->output_row($lang->reply_subject, $lang->reply_subject_desc, $form->generate_text_box('newreplysubject', $mybb->input['newreplysubject'], array('id' => 'newreplysubject')), 'newreplysubject'); + $form_container->end(); + + $form_container = new FormContainer($lang->send_private_message); + $form_container->output_row($lang->private_message_message, $lang->private_message_message_desc, $form->generate_text_area('pm_message', $mybb->input['pm_message'], array('id' => 'pm_message')), 'pm_message'); + $form_container->output_row($lang->private_message_subject, $lang->private_message_subject_desc, $form->generate_text_box('pm_subject', $mybb->input['pm_subject'], array('id' => 'pm_subject')), 'pm_subject'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_post_tool); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_config_mod_tools_start"); + + $page->output_header($lang->mod_tools." - ".$lang->thread_tools); + + $sub_tabs['thread_tools'] = array( + 'title' => $lang->thread_tools, + 'link' => "index.php?module=config-mod_tools", + 'description' => $lang->thread_tools_desc + ); + $sub_tabs['add_thread_tool'] = array( + 'title'=> $lang->add_new_thread_tool, + 'link' => "index.php?module=config-mod_tools&action=add_thread_tool" + ); + $sub_tabs['post_tools'] = array( + 'title' => $lang->post_tools, + 'link' => "index.php?module=config-mod_tools&action=post_tools", + ); + $sub_tabs['add_post_tool'] = array( + 'title'=> $lang->add_new_post_tool, + 'link' => "index.php?module=config-mod_tools&action=add_post_tool" + ); + + $page->output_nav_tabs($sub_tabs, 'thread_tools'); + + $table = new Table; + $table->construct_header($lang->title); + $table->construct_header($lang->controls, array('class' => "align_center", 'colspan' => 2)); + + $query = $db->simple_select('modtools', 'tid, name, description, type', "type='t'", array('order_by' => 'name')); + while($tool = $db->fetch_array($query)) + { + $table->construct_cell("".htmlspecialchars_uni($tool['name'])."
".htmlspecialchars_uni($tool['description']).""); + $table->construct_cell("{$lang->edit}", array('width' => 100, 'class' => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_thread_tool_deletion}')\">{$lang->delete}", array('width' => 100, 'class' => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_thread_tools, array('colspan' => 3)); + $table->construct_row(); + } + + $table->output($lang->thread_tools); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/config/module_meta.php b/Upload/admin/modules/config/module_meta.php new file mode 100644 index 0000000..023be19 --- /dev/null +++ b/Upload/admin/modules/config/module_meta.php @@ -0,0 +1,114 @@ +
Please make sure IN_MYBB is defined."); +} + +function config_meta() +{ + global $page, $lang, $plugins; + + $sub_menu = array(); + $sub_menu['10'] = array("id" => "settings", "title" => $lang->bbsettings, "link" => "index.php?module=config-settings"); + $sub_menu['20'] = array("id" => "banning", "title" => $lang->banning, "link" => "index.php?module=config-banning"); + $sub_menu['30'] = array("id" => "profile_fields", "title" => $lang->custom_profile_fields, "link" => "index.php?module=config-profile_fields"); + $sub_menu['40'] = array("id" => "smilies", "title" => $lang->smilies, "link" => "index.php?module=config-smilies"); + $sub_menu['50'] = array("id" => "badwords", "title" => $lang->word_filters, "link" => "index.php?module=config-badwords"); + $sub_menu['60'] = array("id" => "mycode", "title" => $lang->mycode, "link" => "index.php?module=config-mycode"); + $sub_menu['70'] = array("id" => "languages", "title" => $lang->languages, "link" => "index.php?module=config-languages"); + $sub_menu['80'] = array("id" => "post_icons", "title" => $lang->post_icons, "link" => "index.php?module=config-post_icons"); + $sub_menu['90'] = array("id" => "help_documents", "title" => $lang->help_documents, "link" => "index.php?module=config-help_documents"); + $sub_menu['100'] = array("id" => "plugins", "title" => $lang->plugins, "link" => "index.php?module=config-plugins"); + $sub_menu['110'] = array("id" => "attachment_types", "title" => $lang->attachment_types, "link" => "index.php?module=config-attachment_types"); + $sub_menu['120'] = array("id" => "mod_tools", "title" => $lang->moderator_tools, "link" => "index.php?module=config-mod_tools"); + $sub_menu['130'] = array("id" => "spiders", "title" => $lang->spiders_bots, "link" => "index.php?module=config-spiders"); + $sub_menu['140'] = array("id" => "calendars", "title" => $lang->calendars, "link" => "index.php?module=config-calendars"); + $sub_menu['150'] = array("id" => "warning", "title" => $lang->warning_system, "link" => "index.php?module=config-warning"); + $sub_menu['160'] = array("id" => "thread_prefixes", "title" => $lang->thread_prefixes, "link" => "index.php?module=config-thread_prefixes"); + $sub_menu['170'] = array("id" => "questions", "title" => $lang->security_questions, "link" => "index.php?module=config-questions"); + + $sub_menu = $plugins->run_hooks("admin_config_menu", $sub_menu); + + $page->add_menu_item($lang->configuration, "config", "index.php?module=config", 10, $sub_menu); + + return true; +} + +function config_action_handler($action) +{ + global $page, $plugins; + + $page->active_module = "config"; + + $actions = array( + 'plugins' => array('active' => 'plugins', 'file' => 'plugins.php'), + 'smilies' => array('active' => 'smilies', 'file' => 'smilies.php'), + 'banning' => array('active' => 'banning', 'file' => 'banning.php'), + 'badwords' => array('active' => 'badwords', 'file' => 'badwords.php'), + 'profile_fields' => array('active' => 'profile_fields', 'file' => 'profile_fields.php'), + 'spiders' => array('active' => 'spiders', 'file' => 'spiders.php'), + 'attachment_types' => array('active' => 'attachment_types', 'file' => 'attachment_types.php'), + 'languages' => array('active' => 'languages', 'file' => 'languages.php'), + 'post_icons' => array('active' => 'post_icons', 'file' => 'post_icons.php'), + 'help_documents' => array('active' => 'help_documents', 'file' => 'help_documents.php'), + 'calendars' => array('active' => 'calendars', 'file' => 'calendars.php'), + 'warning' => array('active' => 'warning', 'file' => 'warning.php'), + 'mod_tools' => array('active' => 'mod_tools', 'file' => 'mod_tools.php'), + 'mycode' => array('active' => 'mycode', 'file' => 'mycode.php'), + 'settings' => array('active' => 'settings', 'file' => 'settings.php'), + 'thread_prefixes' => array('active' => 'thread_prefixes', 'file' => 'thread_prefixes.php'), + 'questions' => array('active' => 'questions', 'file' => 'questions.php') + ); + + $actions = $plugins->run_hooks("admin_config_action_handler", $actions); + + if(isset($actions[$action])) + { + $page->active_action = $actions[$action]['active']; + return $actions[$action]['file']; + } + else + { + $page->active_action = "settings"; + return "settings.php"; + } +} + +function config_admin_permissions() +{ + global $lang, $plugins; + + $admin_permissions = array( + "settings" => $lang->can_manage_settings, + "banning" => $lang->can_manage_banned_accounts, + "profile_fields" => $lang->can_manage_custom_profile_fields, + "smilies" => $lang->can_manage_smilies, + "badwords" => $lang->can_manage_bad_words, + "mycode" => $lang->can_manage_custom_mycode, + "languages" => $lang->can_manage_language_packs, + "post_icons" => $lang->can_manage_post_icons, + "help_documents" => $lang->can_manage_help_documents, + "plugins" => $lang->can_manage_plugins, + "attachment_types" => $lang->can_manage_attachment_types, + "spiders" => $lang->can_manage_spiders_bots, + "calendars" => $lang->can_manage_calendars, + "warning" => $lang->can_manage_warning_system, + "mod_tools" => $lang->can_manage_mod_tools, + "thread_prefixes" => $lang->can_manage_thread_prefixes, + "questions" => $lang->can_manage_security_questions + ); + + $admin_permissions = $plugins->run_hooks("admin_config_permissions", $admin_permissions); + + return array("name" => $lang->configuration, "permissions" => $admin_permissions, "disporder" => 10); +} diff --git a/Upload/admin/modules/config/mycode.php b/Upload/admin/modules/config/mycode.php new file mode 100644 index 0000000..c3cc6ac --- /dev/null +++ b/Upload/admin/modules/config/mycode.php @@ -0,0 +1,437 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->mycode, "index.php?module=config-mycode"); + +$plugins->run_hooks("admin_config_mycode_begin"); + +if($mybb->input['action'] == "toggle_status") +{ + if(!verify_post_check($mybb->input['my_post_key'])) + { + flash_message($lang->invalid_post_verify_key2, 'error'); + admin_redirect("index.php?module=config-mycode"); + } + + $query = $db->simple_select("mycode", "*", "cid='".$mybb->get_input('cid', 1)."'"); + $mycode = $db->fetch_array($query); + + if(!$mycode['cid']) + { + flash_message($lang->error_invalid_mycode, 'error'); + admin_redirect("index.php?module=config-mycode"); + } + + $plugins->run_hooks("admin_config_mycode_toggle_status"); + + if($mycode['active'] == 1) + { + $new_status = 0; + $phrase = $lang->success_deactivated_mycode; + } + else + { + $new_status = 1; + $phrase = $lang->success_activated_mycode; + } + $mycode_update = array( + 'active' => $new_status, + ); + + $plugins->run_hooks("admin_config_mycode_toggle_status_commit"); + + $db->update_query("mycode", $mycode_update, "cid='".$mybb->get_input('cid', 1)."'"); + + $cache->update_mycode(); + + // Log admin action + log_admin_action($mycode['cid'], $mycode['title'], $new_status); + + flash_message($phrase, 'success'); + admin_redirect('index.php?module=config-mycode'); +} + +if($mybb->input['action'] == "xmlhttp_test_mycode" && $mybb->request_method == "post") +{ + $plugins->run_hooks("admin_config_mycode_xmlhttp_test_mycode_start"); + + // Send no cache headers + header("Expires: Sat, 1 Jan 2000 01:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + header("Cache-Control: no-cache, must-revalidate"); + header("Pragma: no-cache"); + header("Content-type: text/html"); + + $sandbox = test_regex($mybb->input['regex'], $mybb->input['replacement'], $mybb->input['test_value']); + + $plugins->run_hooks("admin_config_mycode_xmlhttp_test_mycode_end"); + + echo $sandbox['actual']; + exit; +} + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_config_mycode_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + if(!trim($mybb->input['regex'])) + { + $errors[] = $lang->error_missing_regex; + } + + if(!trim($mybb->input['replacement'])) + { + $errors[] = $lang->error_missing_replacement; + } + + if($mybb->input['test']) + { + $errors[] = $lang->changes_not_saved; + $sandbox = test_regex($mybb->input['regex'], $mybb->input['replacement'], $mybb->input['test_value']); + } + + if(!$errors) + { + $new_mycode = array( + 'title' => $db->escape_string($mybb->input['title']), + 'description' => $db->escape_string($mybb->input['description']), + 'regex' => $db->escape_string(str_replace("\x0", "", $mybb->input['regex'])), + 'replacement' => $db->escape_string($mybb->input['replacement']), + 'active' => $db->escape_string($mybb->input['active']), + 'parseorder' => (int)$mybb->input['parseorder'] + ); + + $cid = $db->insert_query("mycode", $new_mycode); + + $plugins->run_hooks("admin_config_mycode_add_commit"); + + $cache->update_mycode(); + + // Log admin action + log_admin_action($cid, $mybb->input['title']); + + flash_message($lang->success_added_mycode, 'success'); + admin_redirect('index.php?module=config-mycode'); + } + } + + $sub_tabs['mycode'] = array( + 'title' => $lang->mycode, + 'link' => "index.php?module=config-mycode", + 'description' => $lang->mycode_desc + ); + + $sub_tabs['add_new_mycode'] = array( + 'title' => $lang->add_new_mycode, + 'link' => "index.php?module=config-mycode&action=add", + 'description' => $lang->add_new_mycode_desc + ); + + $page->extra_header .= " + "; + + $page->add_breadcrumb_item($lang->add_new_mycode); + $page->output_header($lang->custom_mycode." - ".$lang->add_new_mycode); + $page->output_nav_tabs($sub_tabs, 'add_new_mycode'); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['active'] = 1; + } + + $form = new Form("index.php?module=config-mycode&action=add", "post", "add"); + $form_container = new FormContainer($lang->add_mycode); + $form_container->output_row($lang->title." *", '', $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->short_description, '', $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + $form_container->output_row($lang->regular_expression." *", $lang->regular_expression_desc.'
'.$lang->example.' \[b\](.*?)\[/b\]', $form->generate_text_area('regex', $mybb->input['regex'], array('id' => 'regex')), 'regex'); + $form_container->output_row($lang->replacement." *", $lang->replacement_desc.'
'.$lang->example.' <strong>$1</strong>', $form->generate_text_area('replacement', $mybb->input['replacement'], array('id' => 'replacement')), 'replacement'); + $form_container->output_row($lang->enabled." *", '', $form->generate_yes_no_radio('active', $mybb->input['active'])); + $form_container->output_row($lang->parse_order, $lang->parse_order_desc, $form->generate_numeric_field('parseorder', $mybb->input['parseorder'], array('id' => 'parseorder')), 'parseorder'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_mycode); + $form->output_submit_wrapper($buttons); + + // Sandbox + echo "
\n"; + $form_container = new FormContainer($lang->sandbox); + $form_container->output_row($lang->sandbox_desc); + $form_container->output_row($lang->test_value, $lang->test_value_desc, $form->generate_text_area('test_value', $mybb->input['test_value'], array('id' => 'test_value'))."
".$form->generate_submit_button($lang->test, array('id' => 'test', 'name' => 'test')), 'test_value'); + $form_container->output_row($lang->result_html, $lang->result_html_desc, $form->generate_text_area('result_html', $sandbox['html'], array('id' => 'result_html', 'disabled' => 1)), 'result_html'); + $form_container->output_row($lang->result_actual, $lang->result_actual_desc, "
{$sandbox['actual']}
"); + $form_container->end(); + echo ''; + echo ''; + + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("mycode", "*", "cid='".$mybb->get_input('cid', 1)."'"); + $mycode = $db->fetch_array($query); + + if(!$mycode['cid']) + { + flash_message($lang->error_invalid_mycode, 'error'); + admin_redirect("index.php?module=config-mycode"); + } + + $plugins->run_hooks("admin_config_mycode_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + if(!trim($mybb->input['regex'])) + { + $errors[] = $lang->error_missing_regex; + } + + if(!trim($mybb->input['replacement'])) + { + $errors[] = $lang->error_missing_replacement; + } + + if($mybb->input['test']) + { + $errors[] = $lang->changes_not_saved; + $sandbox = test_regex($mybb->input['regex'], $mybb->input['replacement'], $mybb->input['test_value']); + } + + if(!$errors) + { + $updated_mycode = array( + 'title' => $db->escape_string($mybb->input['title']), + 'description' => $db->escape_string($mybb->input['description']), + 'regex' => $db->escape_string(str_replace("\x0", "", $mybb->input['regex'])), + 'replacement' => $db->escape_string($mybb->input['replacement']), + 'active' => $db->escape_string($mybb->input['active']), + 'parseorder' => (int)$mybb->input['parseorder'] + ); + + $plugins->run_hooks("admin_config_mycode_edit_commit"); + + $db->update_query("mycode", $updated_mycode, "cid='".$mybb->get_input('cid', 1)."'"); + + $cache->update_mycode(); + + // Log admin action + log_admin_action($mycode['cid'], $mybb->input['title']); + + flash_message($lang->success_updated_mycode, 'success'); + admin_redirect('index.php?module=config-mycode'); + } + } + + $sub_tabs['edit_mycode'] = array( + 'title' => $lang->edit_mycode, + 'link' => "index.php?module=config-mycode&action=edit", + 'description' => $lang->edit_mycode_desc + ); + + $page->extra_header .= " + "; + + $page->add_breadcrumb_item($lang->edit_mycode); + $page->output_header($lang->custom_mycode." - ".$lang->edit_mycode); + $page->output_nav_tabs($sub_tabs, 'edit_mycode'); + + $form = new Form("index.php?module=config-mycode&action=edit", "post", "edit"); + echo $form->generate_hidden_field('cid', $mycode['cid']); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input = array_merge($mybb->input, $mycode); + } + + $form_container = new FormContainer($lang->edit_mycode); + $form_container->output_row($lang->title." *", '', $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->short_description, '', $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + $form_container->output_row($lang->regular_expression." *", $lang->regular_expression_desc.'
'.$lang->example.' \[b\](.*?)\[/b\]', $form->generate_text_area('regex', $mybb->input['regex'], array('id' => 'regex')), 'regex'); + $form_container->output_row($lang->replacement." *", $lang->replacement_desc.'
'.$lang->example.' <strong>$1</strong>', $form->generate_text_area('replacement', $mybb->input['replacement'], array('id' => 'replacement')), 'replacement'); + $form_container->output_row($lang->enabled." *", '', $form->generate_yes_no_radio('active', $mybb->input['active'])); + $form_container->output_row($lang->parse_order, $lang->parse_order_desc, $form->generate_numeric_field('parseorder', $mybb->input['parseorder'], array('id' => 'parseorder')), 'parseorder'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_mycode); + + $form->output_submit_wrapper($buttons); + + // Sandbox + echo "
\n"; + $form_container = new FormContainer($lang->sandbox); + $form_container->output_row($lang->sandbox_desc); + $form_container->output_row($lang->test_value, $lang->test_value_desc, $form->generate_text_area('test_value', $mybb->input['test_value'], array('id' => 'test_value'))."
".$form->generate_submit_button($lang->test, array('id' => 'test', 'name' => 'test')), 'test_value'); + $form_container->output_row($lang->result_html, $lang->result_html_desc, $form->generate_text_area('result_html', $sandbox['html'], array('id' => 'result_html', 'disabled' => 1)), 'result_html'); + $form_container->output_row($lang->result_actual, $lang->result_actual_desc, "
{$sandbox['actual']}
"); + $form_container->end(); + echo ''; + echo ''; + + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("mycode", "*", "cid='".$mybb->get_input('cid', 1)."'"); + $mycode = $db->fetch_array($query); + + if(!$mycode['cid']) + { + flash_message($lang->error_invalid_mycode, 'error'); + admin_redirect("index.php?module=config-mycode"); + } + + $plugins->run_hooks("admin_config_mycode_delete"); + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-mycode"); + } + + if($mybb->request_method == "post") + { + $db->delete_query("mycode", "cid='{$mycode['cid']}'"); + + $plugins->run_hooks("admin_config_mycode_delete_commit"); + + $cache->update_mycode(); + + // Log admin action + log_admin_action($mycode['cid'], $mycode['title']); + + flash_message($lang->success_deleted_mycode, 'success'); + admin_redirect("index.php?module=config-mycode"); + } + else + { + $page->output_confirm_action("index.php?module=config-mycode&action=delete&cid={$mycode['cid']}", $lang->confirm_mycode_deletion); + } +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_config_mycode_start"); + + $page->output_header($lang->custom_mycode); + + $sub_tabs['mycode'] = array( + 'title' => $lang->mycode, + 'link' => "index.php?module=config-mycode", + 'description' => $lang->mycode_desc + ); + + $sub_tabs['add_new_mycode'] = array( + 'title' => $lang->add_new_mycode, + 'link' => "index.php?module=config-mycode&action=add" + ); + + $page->output_nav_tabs($sub_tabs, 'mycode'); + + $table = new Table; + $table->construct_header($lang->title); + $table->construct_header($lang->controls, array('class' => 'align_center', 'width' => 150)); + + $query = $db->simple_select("mycode", "*", "", array('order_by' => 'parseorder')); + while($mycode = $db->fetch_array($query)) + { + if($mycode['active'] == 1) + { + $phrase = $lang->deactivate_mycode; + $icon = "style}/images/icons/bullet_on.png\" alt=\"({$lang->alt_enabled})\" title=\"{$lang->alt_enabled}\" style=\"vertical-align: middle;\" /> "; + } + else + { + $phrase = $lang->activate_mycode; + $icon = "style}/images/icons/bullet_off.png\" alt=\"({$lang->alt_disabled})\" title=\"{$lang->alt_disabled}\" style=\"vertical-align: middle;\" /> "; + } + + if($mycode['description']) + { + $mycode['description'] = "{$mycode['description']}"; + } + + $table->construct_cell("
{$icon}{$mycode['title']}
{$mycode['description']}
"); + + $popup = new PopupMenu("mycode_{$mycode['cid']}", $lang->options); + $popup->add_item($lang->edit_mycode, "index.php?module=config-mycode&action=edit&cid={$mycode['cid']}"); + $popup->add_item($phrase, "index.php?module=config-mycode&action=toggle_status&cid={$mycode['cid']}&my_post_key={$mybb->post_code}"); + $popup->add_item($lang->delete_mycode, "index.php?module=config-mycode&action=delete&cid={$mycode['cid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_mycode_deletion}')"); + $table->construct_cell($popup->fetch(), array('class' => 'align_center')); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_mycode, array('colspan' => 2)); + $table->construct_row(); + } + + $table->output($lang->custom_mycode); + + $page->output_footer(); +} + +function test_regex($regex, $replacement, $test) +{ + $array = array(); + $array['actual'] = @preg_replace("#".str_replace("\x0", "", $regex)."#si", $replacement, $test); + $array['html'] = htmlspecialchars_uni($array['actual']); + return $array; +} diff --git a/Upload/admin/modules/config/plugins.php b/Upload/admin/modules/config/plugins.php new file mode 100644 index 0000000..b951699 --- /dev/null +++ b/Upload/admin/modules/config/plugins.php @@ -0,0 +1,709 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->plugins, "index.php?module=config-plugins"); + +$plugins->run_hooks("admin_config_plugins_begin"); + +if($mybb->input['action'] == "browse") +{ + $page->add_breadcrumb_item($lang->browse_plugins); + + $page->output_header($lang->browse_plugins); + + $sub_tabs['plugins'] = array( + 'title' => $lang->plugins, + 'link' => "index.php?module=config-plugins", + 'description' => $lang->plugins_desc + ); + $sub_tabs['update_plugins'] = array( + 'title' => $lang->plugin_updates, + 'link' => "index.php?module=config-plugins&action=check", + 'description' => $lang->plugin_updates_desc + ); + + $sub_tabs['browse_plugins'] = array( + 'title' => $lang->browse_plugins, + 'link' => "index.php?module=config-plugins&action=browse", + 'description' => $lang->browse_plugins_desc + ); + + $page->output_nav_tabs($sub_tabs, 'browse_plugins'); + + // Process search requests + require_once MYBB_ROOT."inc/class_xml.php"; + + $keywords = ""; + if($mybb->input['keywords']) + { + $keywords = "&keywords=".urlencode($mybb->input['keywords']); + } + + if($mybb->input['page']) + { + $url_page = "&page=".$mybb->get_input('page', 1); + } + else + { + $mybb->input['page'] = 1; + $url_page = ""; + } + + // Gets the major version code. i.e. 1410 -> 1400 or 121 -> 1200 + $major_version_code = round($mybb->version_code/100, 0)*100; + // Convert to mods site version codes + $search_version = ($major_version_code/100).'x'; + + $contents = fetch_remote_file("http://community.mybb.com/xmlbrowse.php?type=plugins&version={$search_version}{$keywords}{$url_page}", $post_data); + + if(!$contents) + { + $page->output_inline_error($lang->error_communication_problem); + $page->output_footer(); + exit; + } + + $table = new Table; + $table->construct_header($lang->plugin); + $table->construct_header($lang->latest_version, array("class" => "align_center", 'width' => 125)); + $table->construct_header($lang->controls, array("class" => "align_center", 'width' => 125)); + + $parser = new XMLParser($contents); + $tree = $parser->get_tree(); + + if(!is_array($tree) || !isset($tree['results'])) + { + $page->output_inline_error($lang->error_communication_problem); + $page->output_footer(); + exit; + } + + if(!empty($tree['results']['result'])) + { + if(array_key_exists("tag", $tree['results']['result'])) + { + $only_plugin = $tree['results']['result']; + unset($tree['results']['result']); + $tree['results']['result'][0] = $only_plugin; + } + + require_once MYBB_ROOT . '/inc/class_parser.php'; + $post_parser = new postParser(); + + foreach($tree['results']['result'] as $result) + { + $result['name']['value'] = htmlspecialchars_uni($result['name']['value']); + $result['description']['value'] = htmlspecialchars_uni($result['description']['value']); + $result['author']['value'] = $post_parser->parse_message($result['author']['value'], array( + 'allow_html' => true + ) + ); + $result['version']['value'] = htmlspecialchars_uni($result['version']['value']); + $result['download_url']['value'] = htmlspecialchars_uni(html_entity_decode($result['download_url']['value'])); + + $table->construct_cell("{$result['name']['value']}
{$result['description']['value']}
{$lang->created_by} {$result['author']['value']}"); + $table->construct_cell($result['version']['value'], array("class" => "align_center")); + $table->construct_cell("{$lang->download}", array("class" => "align_center")); + $table->construct_row(); + } + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->error_no_results_found, array("colspan" => 3)); + $table->construct_row(); + } + + $search = new Form("index.php?module=config-plugins&action=browse", 'post', 'search_form'); + echo "
"; + if($mybb->input['keywords']) + { + $default_class = ''; + $value = htmlspecialchars_uni($mybb->input['keywords']); + } + else + { + $default_class = "search_default"; + $value = $lang->search_for_plugins; + } + echo $search->generate_text_box('keywords', $value, array('id' => 'search_keywords', 'class' => "{$default_class} field150 field_small"))."\n"; + echo "search}\" />\n"; + echo "\n"; + echo "
\n"; + echo $search->end(); + + // Recommended plugins = Default; Otherwise search results & pagination + if($mybb->request_method == "post") + { + $table->output("{$lang->browse_all_plugins}".$lang->sprintf($lang->browse_results_for_mybb, $mybb->version)); + } + else + { + $table->output("{$lang->browse_all_plugins}".$lang->sprintf($lang->recommended_plugins_for_mybb, $mybb->version)); + } + + echo "
".draw_admin_pagination($mybb->input['page'], 15, $tree['results']['attributes']['total'], "index.php?module=config-plugins&action=browse{$keywords}&page={page}"); + + $page->output_footer(); +} + +if($mybb->input['action'] == "check") +{ + $plugins_list = get_plugins_list(); + + $plugins->run_hooks("admin_config_plugins_check"); + + $info = array(); + + if($plugins_list) + { + $active_hooks = $plugins->hooks; + foreach($plugins_list as $plugin_file) + { + require_once MYBB_ROOT."inc/plugins/".$plugin_file; + $codename = str_replace(".php", "", $plugin_file); + $infofunc = $codename."_info"; + if(!function_exists($infofunc)) + { + continue; + } + $plugininfo = $infofunc(); + $plugininfo['guid'] = trim($plugininfo['guid']); + $plugininfo['codename'] = trim($plugininfo['codename']); + + if($plugininfo['codename'] != "") + { + $info[] = $plugininfo['codename']; + $names[$plugininfo['codename']] = array('name' => $plugininfo['name'], 'version' => $plugininfo['version']); + } + elseif($plugininfo['guid'] != "") + { + $info[] = $plugininfo['guid']; + $names[$plugininfo['guid']] = array('name' => $plugininfo['name'], 'version' => $plugininfo['version']); + } + } + $plugins->hooks = $active_hooks; + } + + if(empty($info)) + { + flash_message($lang->error_vcheck_no_supported_plugins, 'error'); + admin_redirect("index.php?module=config-plugins"); + } + + $url = "http://community.mybb.com/version_check.php?"; + $url .= http_build_query(array("info" => $info))."&"; + require_once MYBB_ROOT."inc/class_xml.php"; + $contents = fetch_remote_file($url); + + if(!$contents) + { + flash_message($lang->error_vcheck_communications_problem, 'error'); + admin_redirect("index.php?module=config-plugins"); + } + + $parser = new XMLParser($contents); + $tree = $parser->get_tree(); + + if(!is_array($tree) || !isset($tree['plugins'])) + { + flash_message($lang->error_communication_problem, 'error'); + admin_redirect("index.php?module=config-plugins"); + } + + if(array_key_exists('error', $tree['plugins'])) + { + switch($tree['plugins'][0]['error']) + { + case "1": + $error_msg = $lang->error_no_input; + break; + case "2": + $error_msg = $lang->error_no_pids; + break; + default: + $error_msg = ""; + } + flash_message($lang->error_communication_problem.$error_msg, 'error'); + admin_redirect("index.php?module=config-plugins"); + } + + $table = new Table; + $table->construct_header($lang->plugin); + $table->construct_header($lang->your_version, array("class" => "align_center", 'width' => 125)); + $table->construct_header($lang->latest_version, array("class" => "align_center", 'width' => 125)); + $table->construct_header($lang->controls, array("class" => "align_center", 'width' => 125)); + + if(!is_array($tree['plugins']['plugin'])) + { + flash_message($lang->success_plugins_up_to_date, 'success'); + admin_redirect("index.php?module=config-plugins"); + } + + if(array_key_exists("tag", $tree['plugins']['plugin'])) + { + $only_plugin = $tree['plugins']['plugin']; + unset($tree['plugins']['plugin']); + $tree['plugins']['plugin'][0] = $only_plugin; + } + + foreach($tree['plugins']['plugin'] as $plugin) + { + $compare_by = array_key_exists("codename", $plugin['attributes']) ? "codename" : "guid"; + $is_vulnerable = array_key_exists("vulnerable", $plugin) ? true : false; + + if(version_compare($names[$plugin['attributes'][$compare_by]]['version'], $plugin['version']['value'], "<")) + { + $plugin['download_url']['value'] = htmlspecialchars_uni($plugin['download_url']['value']); + $plugin['vulnerable']['value'] = htmlspecialchars_uni($plugin['vulnerable']['value']); + $plugin['version']['value'] = htmlspecialchars_uni($plugin['version']['value']); + + if($is_vulnerable) + { + $table->construct_cell("
+ {$lang->error_vcheck_vulnerable} {$names[$plugin['attributes'][$compare_by]]['name']} +
+

{$lang->error_vcheck_vulnerable_notes}

{$plugin['vulnerable']['value']}

"); + } + else + { + $table->construct_cell("{$names[$plugin['attributes'][$compare_by]]['name']}"); + } + $table->construct_cell("{$names[$plugin['attributes'][$compare_by]]['version']}", array("class" => "align_center")); + $table->construct_cell("{$plugin['version']['value']}", array("class" => "align_center")); + if($is_vulnerable) + { + $table->construct_cell("{$lang->deactivate}", array("class" => "align_center", "width" => 150)); + } + else + { + $table->construct_cell("{$lang->download}", array("class" => "align_center")); + } + $table->construct_row(); + } + } + + if($table->num_rows() == 0) + { + flash_message($lang->success_plugins_up_to_date, 'success'); + admin_redirect("index.php?module=config-plugins"); + } + + $page->add_breadcrumb_item($lang->plugin_updates); + + $page->output_header($lang->plugin_updates); + + $sub_tabs['plugins'] = array( + 'title' => $lang->plugins, + 'link' => "index.php?module=config-plugins", + ); + + $sub_tabs['update_plugins'] = array( + 'title' => $lang->plugin_updates, + 'link' => "index.php?module=config-plugins&action=check", + 'description' => $lang->plugin_updates_desc + ); + + $sub_tabs['browse_plugins'] = array( + 'title' => $lang->browse_plugins, + 'link' => "index.php?module=config-plugins&action=browse", + 'description' => $lang->browse_plugins_desc + ); + + $page->output_nav_tabs($sub_tabs, 'update_plugins'); + + $table->output($lang->plugin_updates); + + $page->output_footer(); +} + +// Activates or deactivates a specific plugin +if($mybb->input['action'] == "activate" || $mybb->input['action'] == "deactivate") +{ + if(!verify_post_check($mybb->input['my_post_key'])) + { + flash_message($lang->invalid_post_verify_key2, 'error'); + admin_redirect("index.php?module=config-plugins"); + } + + if($mybb->input['action'] == "activate") + { + $plugins->run_hooks("admin_config_plugins_activate"); + } + else + { + $plugins->run_hooks("admin_config_plugins_deactivate"); + } + + $codename = $mybb->input['plugin']; + $codename = str_replace(array(".", "/", "\\"), "", $codename); + $file = basename($codename.".php"); + + // Check if the file exists and throw an error if it doesn't + if(!file_exists(MYBB_ROOT."inc/plugins/$file")) + { + flash_message($lang->error_invalid_plugin, 'error'); + admin_redirect("index.php?module=config-plugins"); + } + + $plugins_cache = $cache->read("plugins"); + $active_plugins = $plugins_cache['active']; + + require_once MYBB_ROOT."inc/plugins/$file"; + + $installed_func = "{$codename}_is_installed"; + $installed = true; + if(function_exists($installed_func) && $installed_func() != true) + { + $installed = false; + } + + $install_uninstall = false; + + if($mybb->input['action'] == "activate") + { + $message = $lang->success_plugin_activated; + + // Plugin is compatible with this version? + if($plugins->is_compatible($codename) == false) + { + flash_message($lang->sprintf($lang->plugin_incompatible, $mybb->version), 'error'); + admin_redirect("index.php?module=config-plugins"); + } + + // If not installed and there is a custom installation function + if($installed == false && function_exists("{$codename}_install")) + { + call_user_func("{$codename}_install"); + $message = $lang->success_plugin_installed; + $install_uninstall = true; + } + + if(function_exists("{$codename}_activate")) + { + call_user_func("{$codename}_activate"); + } + + $active_plugins[$codename] = $codename; + $executed[] = 'activate'; + } + else if($mybb->input['action'] == "deactivate") + { + $message = $lang->success_plugin_deactivated; + + if(function_exists("{$codename}_deactivate")) + { + call_user_func("{$codename}_deactivate"); + } + + if($mybb->input['uninstall'] == 1 && function_exists("{$codename}_uninstall")) + { + call_user_func("{$codename}_uninstall"); + $message = $lang->success_plugin_uninstalled; + $install_uninstall = true; + } + + unset($active_plugins[$codename]); + } + + // Update plugin cache + $plugins_cache['active'] = $active_plugins; + $cache->update("plugins", $plugins_cache); + + // Log admin action + log_admin_action($codename, $install_uninstall); + + if($mybb->input['action'] == "activate") + { + $plugins->run_hooks("admin_config_plugins_activate_commit"); + } + else + { + $plugins->run_hooks("admin_config_plugins_deactivate_commit"); + } + + flash_message($message, 'success'); + admin_redirect("index.php?module=config-plugins"); +} + +if(!$mybb->input['action']) +{ + $page->output_header($lang->plugins); + + $sub_tabs['plugins'] = array( + 'title' => $lang->plugins, + 'link' => "index.php?module=config-plugins", + 'description' => $lang->plugins_desc + ); + $sub_tabs['update_plugins'] = array( + 'title' => $lang->plugin_updates, + 'link' => "index.php?module=config-plugins&action=check", + 'description' => $lang->plugin_updates_desc + ); + + $sub_tabs['browse_plugins'] = array( + 'title' => $lang->browse_plugins, + 'link' => "index.php?module=config-plugins&action=browse", + 'description' => $lang->browse_plugins_desc + ); + + $page->output_nav_tabs($sub_tabs, 'plugins'); + + // Let's make things easier for our user - show them active + // and inactive plugins in different lists + $plugins_cache = $cache->read("plugins"); + $active_plugins = $plugins_cache['active']; + + $plugins_list = get_plugins_list(); + + $plugins->run_hooks("admin_config_plugins_plugin_list"); + + if(!empty($plugins_list)) + { + $a_plugins = $i_plugins = array(); + + foreach($plugins_list as $plugin_file) + { + require_once MYBB_ROOT."inc/plugins/".$plugin_file; + $codename = str_replace(".php", "", $plugin_file); + $infofunc = $codename."_info"; + + if(!function_exists($infofunc)) + { + continue; + } + + $plugininfo = $infofunc(); + $plugininfo['codename'] = $codename; + + if($active_plugins[$codename]) + { + // This is an active plugin + $plugininfo['is_active'] = 1; + + $a_plugins[] = $plugininfo; + continue; + } + + // Either installed and not active or completely inactive + $i_plugins[] = $plugininfo; + } + + $table = new Table; + $table->construct_header($lang->plugin); + $table->construct_header($lang->controls, array("colspan" => 2, "class" => "align_center", "width" => 300)); + + if(empty($a_plugins)) + { + $table->construct_cell($lang->no_active_plugins, array('colspan' => 3)); + $table->construct_row(); + } + else + { + build_plugin_list($a_plugins); + } + + $table->output($lang->active_plugin); + + $table = new Table; + $table->construct_header($lang->plugin); + $table->construct_header($lang->controls, array("colspan" => 2, "class" => "align_center", "width" => 300)); + + if(empty($i_plugins)) + { + $table->construct_cell($lang->no_inactive_plugins, array('colspan' => 3)); + $table->construct_row(); + } + else + { + build_plugin_list($i_plugins); + } + + $table->output($lang->inactive_plugin); + } + else + { + // No plugins + $table = new Table; + $table->construct_header($lang->plugin); + $table->construct_header($lang->controls, array("colspan" => 2, "class" => "align_center", "width" => 300)); + + $table->construct_cell($lang->no_plugins, array('colspan' => 3)); + $table->construct_row(); + + $table->output($lang->plugins); + } + + $page->output_footer(); +} + +function get_plugins_list() +{ + // Get a list of the plugin files which exist in the plugins directory + $dir = @opendir(MYBB_ROOT."inc/plugins/"); + if($dir) + { + while($file = readdir($dir)) + { + $ext = get_extension($file); + if($ext == "php") + { + $plugins_list[] = $file; + } + } + @sort($plugins_list); + } + @closedir($dir); + + return $plugins_list; +} + +function build_plugin_list($plugin_list) +{ + global $lang, $mybb, $plugins, $table; + + foreach($plugin_list as $plugininfo) + { + if($plugininfo['website']) + { + $plugininfo['name'] = "".$plugininfo['name'].""; + } + + if($plugininfo['authorsite']) + { + $plugininfo['author'] = "".$plugininfo['author'].""; + } + + if($plugins->is_compatible($plugininfo['codename']) == false) + { + $compatibility_warning = "".$lang->sprintf($lang->plugin_incompatible, $mybb->version).""; + } + else + { + $compatibility_warning = ""; + } + + $installed_func = "{$plugininfo['codename']}_is_installed"; + $install_func = "{$plugininfo['codename']}_install"; + $uninstall_func = "{$plugininfo['codename']}_uninstall"; + + $installed = true; + $install_button = false; + $uninstall_button = false; + + if(function_exists($installed_func) && $installed_func() != true) + { + $installed = false; + } + + if(function_exists($install_func)) + { + $install_button = true; + } + + if(function_exists($uninstall_func)) + { + $uninstall_button = true; + } + + $table->construct_cell("{$plugininfo['name']} ({$plugininfo['version']})
{$plugininfo['description']}
{$lang->created_by} {$plugininfo['author']}"); + + // Plugin is not installed at all + if($installed == false) + { + if($compatibility_warning) + { + $table->construct_cell("{$compatibility_warning}", array("class" => "align_center", "colspan" => 2)); + } + else + { + $table->construct_cell("post_code}\">{$lang->install_and_activate}", array("class" => "align_center", "colspan" => 2)); + } + } + // Plugin is activated and installed + else if($plugininfo['is_active']) + { + $table->construct_cell("post_code}\">{$lang->deactivate}", array("class" => "align_center", "width" => 150)); + if($uninstall_button) + { + $table->construct_cell("post_code}\">{$lang->uninstall}", array("class" => "align_center", "width" => 150)); + } + else + { + $table->construct_cell(" ", array("class" => "align_center", "width" => 150)); + } + } + // Plugin is installed but not active + else if($installed == true) + { + if($compatibility_warning && !$uninstall_button) + { + $table->construct_cell("{$compatibility_warning}", array("class" => "align_center", "colspan" => 2)); + } + else + { + $table->construct_cell("post_code}\">{$lang->activate}", array("class" => "align_center", "width" => 150)); + if($uninstall_button) + { + $table->construct_cell("post_code}\">{$lang->uninstall}", array("class" => "align_center", "width" => 150)); + } + else + { + $table->construct_cell(" ", array("class" => "align_center", "width" => 150)); + } + } + } + $table->construct_row(); + } +} diff --git a/Upload/admin/modules/config/post_icons.php b/Upload/admin/modules/config/post_icons.php new file mode 100644 index 0000000..2529d6b --- /dev/null +++ b/Upload/admin/modules/config/post_icons.php @@ -0,0 +1,499 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->post_icons, "index.php?module=config-post_icons"); + +$plugins->run_hooks("admin_config_post_icons_begin"); + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_config_post_icons_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_name; + } + + if(!trim($mybb->input['path'])) + { + $errors[] = $lang->error_missing_path; + } + + if(!$errors) + { + $new_icon = array( + 'name' => $db->escape_string($mybb->input['name']), + 'path' => $db->escape_string($mybb->input['path']) + ); + + $iid = $db->insert_query("icons", $new_icon); + + $plugins->run_hooks("admin_config_post_icons_add_commit"); + + $cache->update_posticons(); + + // Log admin action + log_admin_action($iid, $mybb->input['name']); + + flash_message($lang->success_post_icon_added, 'success'); + admin_redirect('index.php?module=config-post_icons'); + } + } + + $page->add_breadcrumb_item($lang->add_post_icon); + $page->output_header($lang->post_icons." - ".$lang->add_post_icon); + + $sub_tabs['manage_icons'] = array( + 'title' => $lang->manage_post_icons, + 'link' => "index.php?module=config-post_icons" + ); + + $sub_tabs['add_icon'] = array( + 'title' => $lang->add_post_icon, + 'link' => "index.php?module=config-post_icons&action=add", + 'description' => $lang->add_post_icon_desc + ); + + $sub_tabs['add_multiple'] = array( + 'title' => $lang->add_multiple_post_icons, + 'link' => "index.php?module=config-post_icons&action=add_multiple" + ); + + $page->output_nav_tabs($sub_tabs, 'add_icon'); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['path'] = 'images/icons/'; + } + + $form = new Form("index.php?module=config-post_icons&action=add", "post", "add"); + $form_container = new FormContainer($lang->add_post_icon); + $form_container->output_row($lang->name." *", $lang->name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->image_path." *", $lang->image_path_desc, $form->generate_text_box('path', $mybb->input['path'], array('id' => 'path')), 'path'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_post_icon); + + $form->output_submit_wrapper($buttons); + + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "add_multiple") +{ + $plugins->run_hooks("admin_config_post_icons_add_multiple"); + + if($mybb->request_method == "post") + { + if($mybb->input['step'] == 1) + { + if(!trim($mybb->input['pathfolder'])) + { + $errors[] = $lang->error_missing_path_multiple; + } + + $path = $mybb->input['pathfolder']; + $dir = @opendir(MYBB_ROOT.$path); + if(!$dir) + { + $errors[] = $lang->error_invalid_path; + } + + if(substr($path, -1, 1) !== "/") + { + $path .= "/"; + } + + $query = $db->simple_select("icons"); + + $aicons = array(); + while($icon = $db->fetch_array($query)) + { + $aicons[$icon['path']] = 1; + } + + $icons = array(); + if(!$errors) + { + while($file = readdir($dir)) + { + if($file != ".." && $file != ".") + { + $ext = get_extension($file); + if($ext == "gif" || $ext == "jpg" || $ext == "jpeg" || $ext == "png" || $ext == "bmp") + { + if(!$aicons[$path.$file]) + { + $icons[] = $file; + } + } + } + } + closedir($dir); + + if(count($icons) == 0) + { + $errors[] = $lang->error_no_images; + } + } + + // Check for errors again (from above statement)! + if(!$errors) + { + // We have no errors so let's proceed! + $page->add_breadcrumb_item($lang->add_multiple_post_icons); + $page->output_header($lang->post_icons." - ".$lang->add_multiple_post_icons); + + $sub_tabs['manage_icons'] = array( + 'title' => $lang->manage_post_icons, + 'link' => "index.php?module=config-post_icons" + ); + + $sub_tabs['add_icon'] = array( + 'title' => $lang->add_post_icon, + 'link' => "index.php?module=config-post_icons&action=add" + ); + + $sub_tabs['add_multiple'] = array( + 'title' => $lang->add_multiple_post_icons, + 'link' => "index.php?module=config-post_icons&action=add_multiple", + 'description' => $lang->add_multiple_post_icons_desc + ); + + $page->output_nav_tabs($sub_tabs, 'add_multiple'); + + $form = new Form("index.php?module=config-post_icons&action=add_multiple", "post", "add_multiple"); + echo $form->generate_hidden_field("step", "2"); + echo $form->generate_hidden_field("pathfolder", $path); + + $form_container = new FormContainer($lang->add_multiple_post_icons); + $form_container->output_row_header($lang->image, array("class" => "align_center", 'width' => '10%')); + $form_container->output_row_header($lang->name); + $form_container->output_row_header($lang->add, array("class" => "align_center", 'width' => '5%')); + + foreach($icons as $key => $file) + { + $ext = get_extension($file); + $find = str_replace(".".$ext, "", $file); + $name = ucfirst($find); + + $form_container->output_cell("\"\"
{$file}", array("class" => "align_center", "width" => 1)); + $form_container->output_cell($form->generate_text_box("name[{$file}]", $name, array('id' => 'name', 'style' => 'width: 98%'))); + $form_container->output_cell($form->generate_check_box("include[{$file}]", 1, "", array('checked' => 1)), array("class" => "align_center")); + $form_container->construct_row(); + } + + if($form_container->num_rows() == 0) + { + flash_message($lang->error_no_images, 'error'); + admin_redirect("index.php?module=config-post_icons&action=add_multiple"); + } + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_post_icons); + $form->output_submit_wrapper($buttons); + + $form->end(); + + $page->output_footer(); + exit; + } + } + else + { + $path = $mybb->input['pathfolder']; + reset($mybb->input['include']); + $name = $mybb->input['name']; + + if(empty($mybb->input['include'])) + { + flash_message($lang->error_none_included, 'error'); + admin_redirect("index.php?module=config-post_icons&action=add_multiple"); + } + + foreach($mybb->input['include'] as $image => $insert) + { + if($insert) + { + $new_icon = array( + 'name' => $db->escape_string($name[$image]), + 'path' => $db->escape_string($path.$image) + ); + + $db->insert_query("icons", $new_icon); + } + } + + $plugins->run_hooks("admin_config_post_icons_add_multiple_commit"); + + $cache->update_posticons(); + + // Log admin action + log_admin_action(); + + flash_message($lang->success_post_icons_added, 'success'); + admin_redirect("index.php?module=config-post_icons"); + } + } + + $page->add_breadcrumb_item($lang->add_multiple_post_icons); + $page->output_header($lang->post_icons." - ".$lang->add_multiple_post_icons); + + $sub_tabs['manage_icons'] = array( + 'title' => $lang->manage_post_icons, + 'link' => "index.php?module=config-post_icons" + ); + + $sub_tabs['add_icon'] = array( + 'title' => $lang->add_post_icon, + 'link' => "index.php?module=config-post_icons&action=add" + ); + + $sub_tabs['add_multiple'] = array( + 'title' => $lang->add_multiple_post_icons, + 'link' => "index.php?module=config-post_icons&action=add_multiple", + 'description' => $lang->add_multiple_post_icons_desc + ); + + $page->output_nav_tabs($sub_tabs, 'add_multiple'); + + $form = new Form("index.php?module=config-post_icons&action=add_multiple", "post", "add_multiple"); + echo $form->generate_hidden_field("step", "1"); + + if($errors) + { + $page->output_inline_error($errors); + } + + $form_container = new FormContainer($lang->add_multiple_post_icons); + $form_container->output_row($lang->path_to_images." *", $lang->path_to_images_desc, $form->generate_text_box('pathfolder', $mybb->input['pathfolder'], array('id' => 'pathfolder')), 'pathfolder'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->show_post_icons); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("icons", "*", "iid='".(int)$mybb->input['iid']."'"); + $icon = $db->fetch_array($query); + + if(!$icon['iid']) + { + flash_message($lang->error_invalid_post_icon, 'error'); + admin_redirect("index.php?module=config-post_icons"); + } + + $plugins->run_hooks("admin_config_post_icons_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_name; + } + + if(!trim($mybb->input['path'])) + { + $errors[] = $lang->error_missing_path; + } + + if(!$errors) + { + $updated_icon = array( + 'name' => $db->escape_string($mybb->input['name']), + 'path' => $db->escape_string($mybb->input['path']) + ); + + $plugins->run_hooks("admin_config_post_icons_edit_commit"); + + $db->update_query("icons", $updated_icon, "iid='".(int)$mybb->input['iid']."'"); + + $cache->update_posticons(); + + // Log admin action + log_admin_action($icon['iid'], $mybb->input['name']); + + flash_message($lang->success_post_icon_updated, 'success'); + admin_redirect('index.php?module=config-post_icons'); + } + } + + $page->add_breadcrumb_item($lang->edit_post_icon); + $page->output_header($lang->post_icons." - ".$lang->edit_post_icon); + + $sub_tabs['edit_icon'] = array( + 'title' => $lang->edit_post_icon, + 'link' => "index.php?module=config-post_icons", + 'description' => $lang->edit_post_icon_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_icon'); + + $form = new Form("index.php?module=config-post_icons&action=edit", "post", "edit"); + echo $form->generate_hidden_field("iid", $icon['iid']); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input = array_merge($mybb->input, $icon); + } + + $form_container = new FormContainer($lang->edit_post_icon); + $form_container->output_row($lang->name." *", $lang->name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->image_path." *", $lang->image_path_desc, $form->generate_text_box('path', $mybb->input['path'], array('id' => 'path')), 'path'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_post_icon); + $buttons[] = $form->generate_reset_button($lang->reset); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("icons", "*", "iid='".(int)$mybb->input['iid']."'"); + $icon = $db->fetch_array($query); + + if(!$icon['iid']) + { + flash_message($lang->error_invalid_post_icon, 'error'); + admin_redirect("index.php?module=config-post_icons"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-post_icons"); + } + + $plugins->run_hooks("admin_config_post_icons_delete"); + + if($mybb->request_method == "post") + { + $db->delete_query("icons", "iid='{$icon['iid']}'"); + + $plugins->run_hooks("admin_config_post_icons_delete_commit"); + + $cache->update_posticons(); + + // Log admin action + log_admin_action($icon['iid'], $icon['name']); + + flash_message($lang->success_post_icon_deleted, 'success'); + admin_redirect("index.php?module=config-post_icons"); + } + else + { + $page->output_confirm_action("index.php?module=config-post_icons&action=delete&iid={$icon['iid']}", $lang->confirm_post_icon_deletion); + } +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_config_post_icons_start"); + + $page->output_header($lang->post_icons); + + $sub_tabs['manage_icons'] = array( + 'title' => $lang->manage_post_icons, + 'link' => "index.php?module=config-post_icons", + 'description' => $lang->manage_post_icons_desc + ); + + $sub_tabs['add_icon'] = array( + 'title' => $lang->add_post_icon, + 'link' => "index.php?module=config-post_icons&action=add" + ); + + $sub_tabs['add_multiple'] = array( + 'title' => $lang->add_multiple_post_icons, + 'link' => "index.php?module=config-post_icons&action=add_multiple" + ); + + $page->output_nav_tabs($sub_tabs, 'manage_icons'); + + $pagenum = $mybb->get_input('page', 1); + if($pagenum) + { + $start = ($pagenum - 1) * 20; + } + else + { + $start = 0; + $pagenum = 1; + } + + $table = new Table; + $table->construct_header($lang->image, array('class' => "align_center", 'width' => 1)); + $table->construct_header($lang->name, array('width' => "70%")); + $table->construct_header($lang->controls, array('class' => "align_center", 'colspan' => 2)); + + $query = $db->simple_select("icons", "*", "", array('limit_start' => $start, 'limit' => 20, 'order_by' => 'name')); + while($icon = $db->fetch_array($query)) + { + $icon['path'] = str_replace("{theme}", "images", $icon['path']); + if(my_strpos($icon['path'], "p://") || substr($icon['path'], 0, 1) == "/") + { + $image = $icon['path']; + } + else + { + $image = "../".$icon['path']; + } + + $table->construct_cell("\"\"", array("class" => "align_center")); + $table->construct_cell(htmlspecialchars_uni($icon['name'])); + + $table->construct_cell("{$lang->edit}", array("class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_post_icon_deletion}')\">{$lang->delete}", array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_post_icons, array('colspan' => 4)); + $table->construct_row(); + } + + $table->output($lang->manage_post_icons); + + $query = $db->simple_select("icons", "COUNT(iid) AS icons"); + $total_rows = $db->fetch_field($query, "icons"); + + echo "
".draw_admin_pagination($pagenum, "20", $total_rows, "index.php?module=config-post_icons&page={page}"); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/config/profile_fields.php b/Upload/admin/modules/config/profile_fields.php new file mode 100644 index 0000000..f0601bf --- /dev/null +++ b/Upload/admin/modules/config/profile_fields.php @@ -0,0 +1,795 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->custom_profile_fields, "index.php?module=config-profile_fields"); + +$plugins->run_hooks("admin_config_profile_fields_begin"); + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_config_profile_fields_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_name; + } + + if(!trim($mybb->input['description'])) + { + $errors[] = $lang->error_missing_description; + } + + if(!trim($mybb->input['fieldtype'])) + { + $errors[] = $lang->error_missing_fieldtype; + } + + if(!$errors) + { + $type = $mybb->input['fieldtype']; + $options = preg_replace("#(\r\n|\r|\n)#s", "\n", trim($mybb->input['options'])); + if($type != "text" && $type != "textarea") + { + $thing = "$type\n$options"; + } + else + { + $thing = $type; + } + + foreach(array('viewableby', 'editableby') as $key) + { + if($mybb->input[$key] == 'all') + { + $mybb->input[$key] = -1; + } + elseif($mybb->input[$key] == 'custom') + { + if(isset($mybb->input['select'][$key]) && is_array($mybb->input['select'][$key])) + { + foreach($mybb->input['select'][$key] as &$val) + { + $val = (int)$val; + } + unset($val); + + $mybb->input[$key] = implode(',', (array)$mybb->input['select'][$key]); + } + else + { + $mybb->input[$key] = ''; + } + } + else + { + $mybb->input[$key] = ''; + } + } + + $new_profile_field = array( + "name" => $db->escape_string($mybb->input['name']), + "description" => $db->escape_string($mybb->input['description']), + "disporder" => (int)$mybb->input['disporder'], + "type" => $db->escape_string($thing), + "regex" => $db->escape_string($mybb->input['regex']), + "length" => (int)$mybb->input['length'], + "maxlength" => (int)$mybb->input['maxlength'], + "required" => $db->escape_string($mybb->input['required']), + "registration" => $db->escape_string($mybb->input['registration']), + "profile" => $db->escape_string($mybb->input['profile']), + "viewableby" => $db->escape_string($mybb->input['viewableby']), + "editableby" => $db->escape_string($mybb->input['editableby']), + "postbit" => $db->escape_string($mybb->input['postbit']), + "postnum" => (int)$mybb->input['postnum'], + "allowhtml" => (int)$mybb->input['allowhtml'], + "allowmycode" => (int)$mybb->input['allowmycode'], + "allowsmilies" => (int)$mybb->input['allowsmilies'], + "allowimgcode" => (int)$mybb->input['allowimgcode'], + "allowvideocode" => (int)$mybb->input['allowvideocode'] + ); + + $fid = $db->insert_query("profilefields", $new_profile_field); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."userfields ADD fid{$fid} TEXT"); + + $plugins->run_hooks("admin_config_profile_fields_add_commit"); + + $cache->update_profilefields(); + + // Log admin action + log_admin_action($fid, $mybb->input['name']); + + flash_message($lang->success_profile_field_added, 'success'); + admin_redirect("index.php?module=config-profile_fields"); + } + } + + $page->add_breadcrumb_item($lang->add_new_profile_field); + $page->output_header($lang->custom_profile_fields." - ".$lang->add_new_profile_field); + + $sub_tabs['custom_profile_fields'] = array( + 'title' => $lang->custom_profile_fields, + 'link' => "index.php?module=config-profile_fields" + ); + + $sub_tabs['add_profile_field'] = array( + 'title' => $lang->add_new_profile_field, + 'link' => "index.php?module=config-profile_fields&action=add", + 'description' => $lang->add_new_profile_field_desc + ); + + $page->output_nav_tabs($sub_tabs, 'add_profile_field'); + $form = new Form("index.php?module=config-profile_fields&action=add", "post", "add"); + + if($errors) + { + switch($mybb->input['viewableby']) + { + case 'all': + $mybb->input['viewableby'] = -1; + break; + case 'custom': + $mybb->input['viewableby'] = implode(',', (array)$mybb->input['select']['viewableby']); + break; + default: + $mybb->input['viewableby'] = ''; + break; + } + + switch($mybb->input['editableby']) + { + case 'all': + $mybb->input['editableby'] = -1; + break; + case 'custom': + $mybb->input['editableby'] = implode(',', (array)$mybb->input['select']['editableby']); + break; + default: + $mybb->input['editableby'] = ''; + break; + } + + $page->output_inline_error($errors); + } + else + { + $mybb->input['fieldtype'] = 'textbox'; + $mybb->input['required'] = 0; + $mybb->input['registration'] = 0; + $mybb->input['editable'] = 1; + $mybb->input['hidden'] = 0; + $mybb->input['postbit'] = 0; + } + + if(empty($mybb->input['viewableby'])) + { + $mybb->input['viewableby'] = ''; + } + + if(empty($mybb->input['editableby'])) + { + $mybb->input['editableby'] = ''; + } + + $form_container = new FormContainer($lang->add_new_profile_field); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->short_description." *", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + $select_list = array( + "text" => $lang->text, + "textarea" => $lang->textarea, + "select" => $lang->select, + "multiselect" => $lang->multiselect, + "radio" => $lang->radio, + "checkbox" => $lang->checkbox + ); + $form_container->output_row($lang->field_type." *", $lang->field_type_desc, $form->generate_select_box('fieldtype', $select_list, $mybb->input['fieldtype'], array('id' => 'fieldtype')), 'fieldtype'); + $form_container->output_row($lang->field_regex, $lang->field_regex_desc, $form->generate_text_box('regex', $mybb->input['regex'], array('id' => 'regex')), 'regex', array(), array('id' => 'row_regex')); + $form_container->output_row($lang->maximum_length, $lang->maximum_length_desc, $form->generate_numeric_field('maxlength', $mybb->input['maxlength'], array('id' => 'maxlength')), 'maxlength', array(), array('id' => 'row_maxlength')); + $form_container->output_row($lang->field_length, $lang->field_length_desc, $form->generate_numeric_field('length', $mybb->input['length'], array('id' => 'length')), 'length', array(), array('id' => 'row_fieldlength')); + $form_container->output_row($lang->selectable_options, $lang->selectable_options_desc, $form->generate_text_area('options', $mybb->input['options'], array('id' => 'options')), 'options', array(), array('id' => 'row_options')); + $form_container->output_row($lang->min_posts_enabled, $lang->min_posts_enabled_desc, $form->generate_numeric_field('postnum', $mybb->input['postnum'], array('id' => 'postnum')), 'postnum'); + $form_container->output_row($lang->display_order." *", $lang->display_order_desc, $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder')), 'disporder'); + $form_container->output_row($lang->required." *", $lang->required_desc, $form->generate_yes_no_radio('required', $mybb->input['required'])); + $form_container->output_row($lang->show_on_registration." *", $lang->show_on_registration_desc, $form->generate_yes_no_radio('registration', $mybb->input['registration'])); + $form_container->output_row($lang->display_on_profile." *", $lang->display_on_profile_desc, $form->generate_yes_no_radio('profile', $mybb->input['profile'])); + $form_container->output_row($lang->display_on_postbit." *", $lang->display_on_postbit_desc, $form->generate_yes_no_radio('postbit', $mybb->input['postbit'])); + + $selected_values = ''; + if($mybb->input['viewableby'] != '' && $mybb->input['viewableby'] != -1) + { + $selected_values = explode(',', (string)$mybb->input['viewableby']); + + foreach($selected_values as &$value) + { + $value = (int)$value; + } + unset($value); + } + + $group_checked = array('all' => '', 'custom' => '', 'none' => ''); + if($mybb->input['viewableby'] == -1) + { + $group_checked['all'] = 'checked="checked"'; + } + elseif($mybb->input['viewableby'] != '') + { + $group_checked['custom'] = 'checked="checked"'; + } + else + { + $group_checked['none'] = 'checked="checked"'; + } + + print_selection_javascript(); + + $select_code = " +
+
+
+
+ + + + + +
{$lang->groups_colon}".$form->generate_group_select('select[viewableby][]', $selected_values, array('id' => 'viewableby', 'multiple' => true, 'size' => 5))."
+
+
+
+ "; + $form_container->output_row($lang->viewableby, $lang->viewableby_desc, $select_code, '', array(), array('id' => 'row_viewableby')); + + $selected_values = ''; + if($mybb->input['editableby'] != '' && $mybb->input['editableby'] != -1) + { + $selected_values = explode(',', (string)$mybb->input['editableby']); + + foreach($selected_values as &$value) + { + $value = (int)$value; + } + unset($value); + } + + $group_checked = array('all' => '', 'custom' => '', 'none' => ''); + if($mybb->input['editableby'] == -1) + { + $group_checked['all'] = 'checked="checked"'; + } + elseif($mybb->input['editableby'] != '') + { + $group_checked['custom'] = 'checked="checked"'; + } + else + { + $group_checked['none'] = 'checked="checked"'; + } + + print_selection_javascript(); + + $select_code = " +
+
+
+
+ + + + + +
{$lang->groups_colon}".$form->generate_group_select('select[editableby][]', $selected_values, array('id' => 'editableby', 'multiple' => true, 'size' => 5))."
+
+
+
+ "; + $form_container->output_row($lang->editableby, $lang->editableby_desc, $select_code, '', array(), array('id' => 'row_editableby')); + + $parser_options = array( + $form->generate_check_box('allowhtml', 1, $lang->parse_allowhtml, array('checked' => $mybb->input['allowhtml'], 'id' => 'allowhtml')), + $form->generate_check_box('allowmycode', 1, $lang->parse_allowmycode, array('checked' => $mybb->input['allowmycode'], 'id' => 'allowmycode')), + $form->generate_check_box('allowsmilies', 1, $lang->parse_allowsmilies, array('checked' => $mybb->input['allowsmilies'], 'id' => 'allowsmilies')), + $form->generate_check_box('allowimgcode', 1, $lang->parse_allowimgcode, array('checked' => $mybb->input['allowimgcode'], 'id' => 'allowimgcode')), + $form->generate_check_box('allowvideocode', 1, $lang->parse_allowvideocode, array('checked' => $mybb->input['allowvideocode'], 'id' => 'allowvideocode')) + ); + $form_container->output_row($lang->parser_options, '', implode('
', $parser_options), '', array(), array('id' => 'row_parser_options')); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_profile_field); + + $form->output_submit_wrapper($buttons); + $form->end(); + + echo ' + '; + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("profilefields", "*", "fid = '".$mybb->get_input('fid', 1)."'"); + $profile_field = $db->fetch_array($query); + + if(!$profile_field['fid']) + { + flash_message($lang->error_invalid_fid, 'error'); + admin_redirect("index.php?module=config-profile_fields"); + } + + $plugins->run_hooks("admin_config_profile_fields_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_name; + } + + if(!trim($mybb->input['description'])) + { + $errors[] = $lang->error_missing_description; + } + + if(!trim($mybb->input['fieldtype'])) + { + $errors[] = $lang->error_missing_fieldtype; + } + + $type = $mybb->input['fieldtype']; + $options = preg_replace("#(\r\n|\r|\n)#s", "\n", trim($mybb->input['options'])); + if($type != "text" && $type != "textarea") + { + $type = "$type\n$options"; + } + + if(!$errors) + { + foreach(array('viewableby', 'editableby') as $key) + { + if($mybb->input[$key] == 'all') + { + $mybb->input[$key] = -1; + } + elseif($mybb->input[$key] == 'custom') + { + if(isset($mybb->input['select'][$key]) && is_array($mybb->input['select'][$key])) + { + foreach($mybb->input['select'][$key] as &$val) + { + $val = (int)$val; + } + unset($val); + + $mybb->input[$key] = implode(',', (array)$mybb->input['select'][$key]); + } + else + { + $mybb->input[$key] = ''; + } + } + else + { + $mybb->input[$key] = ''; + } + } + + $updated_profile_field = array( + "name" => $db->escape_string($mybb->input['name']), + "description" => $db->escape_string($mybb->input['description']), + "disporder" => (int)$mybb->input['disporder'], + "type" => $db->escape_string($type), + "regex" => $db->escape_string($mybb->input['regex']), + "length" => (int)$mybb->input['length'], + "maxlength" => (int)$mybb->input['maxlength'], + "required" => $db->escape_string($mybb->input['required']), + "registration" => $db->escape_string($mybb->input['registration']), + "profile" => $db->escape_string($mybb->input['profile']), + "viewableby" => $db->escape_string($mybb->input['viewableby']), + "editableby" => $db->escape_string($mybb->input['editableby']), + "postbit" => $db->escape_string($mybb->input['postbit']), + "postnum" => (int)$mybb->input['postnum'], + "allowhtml" => (int)$mybb->input['allowhtml'], + "allowmycode" => (int)$mybb->input['allowmycode'], + "allowsmilies" => (int)$mybb->input['allowsmilies'], + "allowimgcode" => (int)$mybb->input['allowimgcode'], + "allowvideocode" => (int)$mybb->input['allowvideocode'] + ); + + $plugins->run_hooks("admin_config_profile_fields_edit_commit"); + + $db->update_query("profilefields", $updated_profile_field, "fid = '".$mybb->get_input('fid', 1)."'"); + + $cache->update_profilefields(); + + // Log admin action + log_admin_action($profile_field['fid'], $mybb->input['name']); + + flash_message($lang->success_profile_field_saved, 'success'); + admin_redirect("index.php?module=config-profile_fields"); + } + } + + $page->add_breadcrumb_item($lang->edit_profile_field); + $page->output_header($lang->custom_profile_fields." - ".$lang->edit_profile_field); + + $sub_tabs['edit_profile_field'] = array( + 'title' => $lang->edit_profile_field, + 'link' => "index.php?module=config-profile_fields&action=edit&fid=".$mybb->get_input('fid', 1), + 'description' => $lang->edit_profile_field_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_profile_field'); + $form = new Form("index.php?module=config-profile_fields&action=edit", "post", "edit"); + + + echo $form->generate_hidden_field("fid", $profile_field['fid']); + + if($errors) + { + switch($mybb->input['viewableby']) + { + case 'all': + $mybb->input['viewableby'] = -1; + break; + case 'custom': + $mybb->input['viewableby'] = implode(',', (array)$mybb->input['select']['viewableby']); + break; + default: + $mybb->input['viewableby'] = ''; + break; + } + + switch($mybb->input['editableby']) + { + case 'all': + $mybb->input['editableby'] = -1; + break; + case 'custom': + $mybb->input['editableby'] = implode(',', (array)$mybb->input['select']['editableby']); + break; + default: + $mybb->input['editableby'] = ''; + break; + } + + $page->output_inline_error($errors); + } + else + { + $type = explode("\n", $profile_field['type'], "2"); + + $mybb->input = $profile_field; + $mybb->input['fieldtype'] = $type[0]; + $mybb->input['options'] = $type[1]; + } + + if(empty($mybb->input['viewableby'])) + { + $mybb->input['viewableby'] = ''; + } + + if(empty($mybb->input['editableby'])) + { + $mybb->input['editableby'] = ''; + } + + $form_container = new FormContainer($lang->edit_profile_field); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->short_description." *", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + $select_list = array( + "text" => $lang->text, + "textarea" => $lang->textarea, + "select" => $lang->select, + "multiselect" => $lang->multiselect, + "radio" => $lang->radio, + "checkbox" => $lang->checkbox + ); + $form_container->output_row($lang->field_type." *", $lang->field_type_desc, $form->generate_select_box('fieldtype', $select_list, $mybb->input['fieldtype'], array('id' => 'fieldtype')), 'fieldtype'); + $form_container->output_row($lang->field_regex, $lang->field_regex_desc, $form->generate_text_box('regex', $mybb->input['regex'], array('id' => 'regex')), 'regex', array(), array('id' => 'row_regex')); + $form_container->output_row($lang->maximum_length, $lang->maximum_length_desc, $form->generate_numeric_field('maxlength', $mybb->input['maxlength'], array('id' => 'maxlength')), 'maxlength', array(), array('id' => 'row_maxlength')); + $form_container->output_row($lang->field_length, $lang->field_length_desc, $form->generate_numeric_field('length', $mybb->input['length'], array('id' => 'length')), 'length', array(), array('id' => 'row_fieldlength')); + $form_container->output_row($lang->selectable_options, $lang->selectable_options_desc, $form->generate_text_area('options', $mybb->input['options'], array('id' => 'options')), 'options', array(), array('id' => 'row_options')); + $form_container->output_row($lang->min_posts_enabled, $lang->min_posts_enabled_desc, $form->generate_numeric_field('postnum', $mybb->input['postnum'], array('id' => 'postnum')), 'postnum'); + $form_container->output_row($lang->display_order." *", $lang->display_order_desc, $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder')), 'disporder'); + $form_container->output_row($lang->required." *", $lang->required_desc, $form->generate_yes_no_radio('required', $mybb->input['required'])); + $form_container->output_row($lang->show_on_registration." *", $lang->show_on_registration_desc, $form->generate_yes_no_radio('registration', $mybb->input['registration'])); + $form_container->output_row($lang->display_on_profile." *", $lang->display_on_profile_desc, $form->generate_yes_no_radio('profile', $mybb->input['profile'])); + $form_container->output_row($lang->display_on_postbit." *", $lang->display_on_postbit_desc, $form->generate_yes_no_radio('postbit', $mybb->input['postbit'])); + + $selected_values = ''; + if($mybb->input['viewableby'] != '' && $mybb->input['viewableby'] != -1) + { + $selected_values = explode(',', (string)$mybb->input['viewableby']); + + foreach($selected_values as &$value) + { + $value = (int)$value; + } + unset($value); + } + + $group_checked = array('all' => '', 'custom' => '', 'none' => ''); + if($mybb->input['viewableby'] == -1) + { + $group_checked['all'] = 'checked="checked"'; + } + elseif($mybb->input['viewableby'] != '') + { + $group_checked['custom'] = 'checked="checked"'; + } + else + { + $group_checked['none'] = 'checked="checked"'; + } + + print_selection_javascript(); + + $select_code = " +
+
+
+
+ + + + + +
{$lang->groups_colon}".$form->generate_group_select('select[viewableby][]', $selected_values, array('id' => 'viewableby', 'multiple' => true, 'size' => 5))."
+
+
+
+ "; + $form_container->output_row($lang->viewableby, $lang->viewableby_desc, $select_code, '', array(), array('id' => 'row_viewableby')); + + $selected_values = ''; + if($mybb->input['editableby'] != '' && $mybb->input['editableby'] != -1) + { + $selected_values = explode(',', (string)$mybb->input['editableby']); + + foreach($selected_values as &$value) + { + $value = (int)$value; + } + unset($value); + } + + $group_checked = array('all' => '', 'custom' => '', 'none' => ''); + if($mybb->input['editableby'] == -1) + { + $group_checked['all'] = 'checked="checked"'; + } + elseif($mybb->input['editableby'] != '') + { + $group_checked['custom'] = 'checked="checked"'; + } + else + { + $group_checked['none'] = 'checked="checked"'; + } + + print_selection_javascript(); + + $select_code = " +
+
+
+
+ + + + + +
{$lang->groups_colon}".$form->generate_group_select('select[editableby][]', $selected_values, array('id' => 'editableby', 'multiple' => true, 'size' => 5))."
+
+
+
+ "; + $form_container->output_row($lang->editableby, $lang->editableby_desc, $select_code, '', array(), array('id' => 'row_editableby')); + + $parser_options = array( + $form->generate_check_box('allowhtml', 1, $lang->parse_allowhtml, array('checked' => $mybb->input['allowhtml'], 'id' => 'allowhtml')), + $form->generate_check_box('allowmycode', 1, $lang->parse_allowmycode, array('checked' => $mybb->input['allowmycode'], 'id' => 'allowmycode')), + $form->generate_check_box('allowsmilies', 1, $lang->parse_allowsmilies, array('checked' => $mybb->input['allowsmilies'], 'id' => 'allowsmilies')), + $form->generate_check_box('allowimgcode', 1, $lang->parse_allowimgcode, array('checked' => $mybb->input['allowimgcode'], 'id' => 'allowimgcode')), + $form->generate_check_box('allowvideocode', 1, $lang->parse_allowvideocode, array('checked' => $mybb->input['allowvideocode'], 'id' => 'allowvideocode')) + ); + $form_container->output_row($lang->parser_options, '', implode('
', $parser_options), '', array(), array('id' => 'row_parser_options')); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_profile_field); + + $form->output_submit_wrapper($buttons); + $form->end(); + + echo ' + '; + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("profilefields", "*", "fid='".$mybb->get_input('fid', 1)."'"); + $profile_field = $db->fetch_array($query); + + // Does the profile field not exist? + if(!$profile_field['fid']) + { + flash_message($lang->error_invalid_fid, 'error'); + admin_redirect("index.php?module=config-profile_fields"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-profile_fields"); + } + + $plugins->run_hooks("admin_config_profile_fields_delete"); + + if($mybb->request_method == "post") + { + // Delete the profile field + $db->delete_query("profilefields", "fid='{$profile_field['fid']}'"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."userfields DROP fid{$profile_field['fid']}"); + + $plugins->run_hooks("admin_config_profile_fields_delete_commit"); + + $cache->update_profilefields(); + + // Log admin action + log_admin_action($profile_field['fid'], $profile_field['name']); + + flash_message($lang->success_profile_field_deleted, 'success'); + admin_redirect("index.php?module=config-profile_fields"); + } + else + { + $page->output_confirm_action("index.php?module=config-profile_fields&action=delete&fid={$profile_field['fid']}", $lang->confirm_profile_field_deletion); + } +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_config_profile_fields_start"); + + $page->output_header($lang->custom_profile_fields); + + $sub_tabs['custom_profile_fields'] = array( + 'title' => $lang->custom_profile_fields, + 'link' => "index.php?module=config-profile_fields", + 'description' => $lang->custom_profile_fields_desc + ); + + $sub_tabs['add_profile_field'] = array( + 'title' => $lang->add_new_profile_field, + 'link' => "index.php?module=config-profile_fields&action=add", + ); + + + $page->output_nav_tabs($sub_tabs, 'custom_profile_fields'); + + $table = new Table; + $table->construct_header($lang->name); + $table->construct_header($lang->required, array("class" => "align_center")); + $table->construct_header($lang->registration, array("class" => "align_center")); + $table->construct_header($lang->editable, array("class" => "align_center")); + $table->construct_header($lang->profile, array("class" => "align_center")); + $table->construct_header($lang->postbit, array("class" => "align_center")); + $table->construct_header($lang->controls, array("class" => "align_center")); + + $query = $db->simple_select("profilefields", "*", "", array('order_by' => 'disporder')); + while($field = $db->fetch_array($query)) + { + if($field['required']) + { + $required = $lang->yes; + } + else + { + $required = $lang->no; + } + + if($field['registration']) + { + $registration = $lang->yes; + } + else + { + $registration = $lang->no; + } + + if($field['editableby'] == '') + { + $editable = $lang->no; + } + else + { + $editable = $lang->yes; + } + + if($field['profile']) + { + $profile = $lang->yes; + } + else + { + $profile = $lang->no; + } + + if($field['postbit']) + { + $postbit = $lang->yes; + } + else + { + $postbit = $lang->no; + } + + $table->construct_cell("".htmlspecialchars_uni($field['name'])."
".htmlspecialchars_uni($field['description'])."", array('width' => '35%')); + $table->construct_cell($required, array("class" => "align_center", 'width' => '10%')); + $table->construct_cell($registration, array("class" => "align_center", 'width' => '10%')); + $table->construct_cell($editable, array("class" => "align_center", 'width' => '10%')); + $table->construct_cell($profile, array("class" => "align_center", 'width' => '10%')); + $table->construct_cell($postbit, array("class" => "align_center", 'width' => '10%')); + + $popup = new PopupMenu("field_{$field['fid']}", $lang->options); + $popup->add_item($lang->edit_field, "index.php?module=config-profile_fields&action=edit&fid={$field['fid']}"); + $popup->add_item($lang->delete_field, "index.php?module=config-profile_fields&action=delete&fid={$field['fid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_profile_field_deletion}')"); + $table->construct_cell($popup->fetch(), array("class" => "align_center", 'width' => '20%')); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_profile_fields, array('colspan' => 7)); + $table->construct_row(); + } + + $table->output($lang->custom_profile_fields); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/config/questions.php b/Upload/admin/modules/config/questions.php new file mode 100644 index 0000000..9defdd8 --- /dev/null +++ b/Upload/admin/modules/config/questions.php @@ -0,0 +1,347 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->security_questions, "index.php?module=config-questions"); + +$plugins->run_hooks("admin_config_questions_begin"); + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_config_questions_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['question'])) + { + $errors[] = $lang->error_missing_question; + } + + if(!trim($mybb->input['answer'])) + { + $errors[] = $lang->error_missing_answer; + } + + if(!$errors) + { + $answer = preg_replace("#(\r\n|\r|\n)#s", "\n", trim($mybb->input['answer'])); + + $new_question = array( + "question" => $db->escape_string($mybb->input['question']), + "answer" => $db->escape_string($answer), + "active" => (int)$mybb->input['active'] + ); + $qid = $db->insert_query("questions", $new_question); + + $plugins->run_hooks("admin_config_questions_add_commit"); + + // Log admin action + log_admin_action($qid, $mybb->input['question']); + + flash_message($lang->success_question_created, 'success'); + admin_redirect("index.php?module=config-questions"); + } + } + + $page->add_breadcrumb_item($lang->add_new_question); + $page->output_header($lang->security_questions." - ".$lang->add_new_question); + + $sub_tabs['security_questions'] = array( + 'title' => $lang->security_questions, + 'link' => "index.php?module=config-questions" + ); + + $sub_tabs['add_new_question'] = array( + 'title' => $lang->add_new_question, + 'link' => "index.php?module=config-questions&action=add", + 'description' => $lang->add_new_question_desc + ); + + $page->output_nav_tabs($sub_tabs, 'add_new_question'); + + $form = new Form("index.php?module=config-questions&action=add", "post", "add"); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['active'] = '1'; + } + + $form_container = new FormContainer($lang->add_new_question); + $form_container->output_row($lang->question." *", $lang->question_desc, $form->generate_text_area('question', $mybb->input['question'], array('id' => 'question')), 'question'); + $form_container->output_row($lang->answers." *", $lang->answers_desc, $form->generate_text_area('answer', $mybb->input['answer'], array('id' => 'answer')), 'answer'); + $form_container->output_row($lang->active." *", "", $form->generate_yes_no_radio('active', $mybb->input['active'])); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_question); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("questions", "*", "qid='".(int)$mybb->input['qid']."'"); + $question = $db->fetch_array($query); + + if(!$question['qid']) + { + flash_message($lang->error_invalid_question, 'error'); + admin_redirect("index.php?module=config-questions"); + } + + $plugins->run_hooks("admin_config_questions_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['question'])) + { + $errors[] = $lang->error_missing_question; + } + + if(!trim($mybb->input['answer'])) + { + $errors[] = $lang->error_missing_answer; + } + + if(!$errors) + { + $answer = preg_replace("#(\r\n|\r|\n)#s", "\n", trim($mybb->input['answer'])); + + $updated_question = array( + "question" => $db->escape_string($mybb->input['question']), + "answer" => $db->escape_string($answer), + "active" => (int)$mybb->input['active'] + ); + + $plugins->run_hooks("admin_config_questions_edit_commit"); + + $db->update_query("questions", $updated_question, "qid='{$question['qid']}'"); + + // Log admin action + log_admin_action($question['qid'], $mybb->input['question']); + + flash_message($lang->success_question_updated, 'success'); + admin_redirect("index.php?module=config-questions"); + } + } + + $page->add_breadcrumb_item($lang->edit_question); + $page->output_header($lang->security_questions." - ".$lang->edit_question); + + $sub_tabs['edit_question'] = array( + 'title' => $lang->edit_question, + 'link' => "index.php?module=config-questions&action=edit&qid={$question['qid']}", + 'description' => $lang->edit_question_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_question'); + + $form = new Form("index.php?module=config-questions&action=edit&qid={$question['qid']}", "post", "add"); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input = $question; + } + + $form_container = new FormContainer($lang->edit_question); + $form_container->output_row($lang->question." *", $lang->question_desc, $form->generate_text_area('question', $mybb->input['question'], array('id' => 'question')), 'question'); + $form_container->output_row($lang->answers." *", $lang->answers_desc, $form->generate_text_area('answer', $mybb->input['answer'], array('id' => 'answer')), 'answer'); + $form_container->output_row($lang->active." *", "", $form->generate_yes_no_radio('active', $mybb->input['active'])); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_question); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete") +{ + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-questions"); + } + + $query = $db->simple_select("questions", "*", "qid='".(int)$mybb->input['qid']."'"); + $question = $db->fetch_array($query); + + if(!$question['qid']) + { + flash_message($lang->error_invalid_question, 'error'); + admin_redirect("index.php?module=config-questions"); + } + + $plugins->run_hooks("admin_config_questions_delete"); + + if($mybb->request_method == "post") + { + $db->delete_query("questions", "qid='{$question['qid']}'"); + $db->delete_query("questionsessions", "qid='{$question['qid']}'"); + + $plugins->run_hooks("admin_config_questions_delete_commit"); + + // Log admin action + log_admin_action($question['qid'], $question['question']); + + flash_message($lang->success_question_deleted, 'success'); + admin_redirect("index.php?module=config-questions"); + } + else + { + $page->output_confirm_action("index.php?module=config-questions&action=delete&qid={$question['qid']}", $lang->confirm_question_deletion); + } +} + +if($mybb->input['action'] == "disable") +{ + $query = $db->simple_select("questions", "*", "qid='".(int)$mybb->input['qid']."'"); + $question = $db->fetch_array($query); + + if(!$question['qid']) + { + flash_message($lang->error_invalid_question, 'error'); + admin_redirect("index.php?module=config-questions"); + } + + $plugins->run_hooks("admin_config_questions_disable"); + + $update_question = array( + "active" => 0 + ); + + $plugins->run_hooks("admin_config_questions_disable_commit"); + + $db->update_query("questions", $update_question, "qid = '{$question['qid']}'"); + + // Log admin action + log_admin_action($question['qid'], $question['question']); + + flash_message($lang->success_question_disabled, 'success'); + admin_redirect("index.php?module=config-questions"); +} + +if($mybb->input['action'] == "enable") +{ + $query = $db->simple_select("questions", "*", "qid='".(int)$mybb->input['qid']."'"); + $question = $db->fetch_array($query); + + if(!$question['qid']) + { + flash_message($lang->error_invalid_question, 'error'); + admin_redirect("index.php?module=config-questions"); + } + + $plugins->run_hooks("admin_config_questions_enable"); + + $update_question = array( + "active" => 1 + ); + + $plugins->run_hooks("admin_config_questions_enable_commit"); + + $db->update_query("questions", $update_question, "qid = '{$question['qid']}'"); + + // Log admin action + log_admin_action($question['qid'], $question['question']); + + flash_message($lang->success_question_enabled, 'success'); + admin_redirect("index.php?module=config-questions"); +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_config_questions_start"); + + $page->output_header($lang->security_questions); + + $sub_tabs['security_questions'] = array( + 'title' => $lang->security_questions, + 'link' => "index.php?module=config-questions", + 'description' => $lang->security_questions_desc + ); + $sub_tabs['add_new_question'] = array( + 'title' => $lang->add_new_question, + 'link' => "index.php?module=config-questions&action=add", + ); + + $page->output_nav_tabs($sub_tabs, 'security_questions'); + + $table = new Table; + $table->construct_header($lang->question); + $table->construct_header($lang->answers, array("width" => "35%")); + $table->construct_header($lang->correct, array("width" => "5%", "class" => "align_center")); + $table->construct_header($lang->incorrect, array("width" => "5%", "class" => "align_center")); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 150)); + + $query = $db->simple_select("questions", "*", "", array('order_by' => 'question')); + while($questions = $db->fetch_array($query)) + { + $questions['question'] = htmlspecialchars_uni($questions['question']); + $questions['answer'] = htmlspecialchars_uni($questions['answer']); + $questions['answer'] = preg_replace("#(\n)#s", "
", trim($questions['answer'])); + $questions['correct'] = my_number_format($questions['correct']); + $questions['incorrect'] = my_number_format($questions['incorrect']); + + if($questions['active'] == 1) + { + $icon = "style}/images/icons/bullet_on.png\" alt=\"({$lang->alt_enabled})\" title=\"{$lang->alt_enabled}\" style=\"vertical-align: middle;\" /> "; + } + else + { + $icon = "style}/images/icons/bullet_off.png\" alt=\"({$lang->alt_disabled})\" title=\"{$lang->alt_disabled}\" style=\"vertical-align: middle;\" /> "; + } + + $table->construct_cell("
{$icon}{$questions['question']}
"); + $table->construct_cell($questions['answer']); + $table->construct_cell($questions['correct'], array("class" => "align_center")); + $table->construct_cell($questions['incorrect'], array("class" => "align_center")); + $popup = new PopupMenu("questions_{$questions['qid']}", $lang->options); + $popup->add_item($lang->edit_question, "index.php?module=config-questions&action=edit&qid={$questions['qid']}"); + if($questions['active'] == 1) + { + $popup->add_item($lang->disable_question, "index.php?module=config-questions&action=disable&qid={$questions['qid']}&my_post_key={$mybb->post_code}"); + } + else + { + $popup->add_item($lang->enable_question, "index.php?module=config-questions&action=enable&qid={$questions['qid']}&my_post_key={$mybb->post_code}"); + } + $popup->add_item($lang->delete_question, "index.php?module=config-questions&action=delete&qid={$questions['qid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_question_deletion}')"); + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_security_questions, array('colspan' => 5)); + $table->construct_row(); + } + + $table->output($lang->security_questions); + + $page->output_footer(); +} + diff --git a/Upload/admin/modules/config/settings.php b/Upload/admin/modules/config/settings.php new file mode 100644 index 0000000..fc07f13 --- /dev/null +++ b/Upload/admin/modules/config/settings.php @@ -0,0 +1,1640 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->board_settings, "index.php?module=config-settings"); + +$plugins->run_hooks("admin_config_settings_begin"); + +// Creating a new setting group +if($mybb->input['action'] == "addgroup") +{ + $plugins->run_hooks("admin_config_settings_addgroup"); + + if($mybb->request_method == "post") + { + // Validate title + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_group_title; + } + + // Validate identifier + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_group_name; + } + $query = $db->simple_select("settinggroups", "title", "name='".$db->escape_string($mybb->input['name'])."'"); + if($db->num_rows($query) > 0) + { + $dup_group_title = $db->fetch_field($query, 'title'); + $errors[] = $lang->sprintf($lang->error_duplicate_group_name, $dup_group_title); + } + + if(!$errors) + { + $new_setting_group = array( + "name" => $db->escape_string($mybb->input['name']), + "title" => $db->escape_string($mybb->input['title']), + "description" => $db->escape_string($mybb->input['description']), + "disporder" => (int)$mybb->input['disporder'], + "isdefault" => 0 + ); + $gid = $db->insert_query("settinggroups", $new_setting_group); + + $plugins->run_hooks("admin_config_settings_addgroup_commit"); + + // Log admin action + log_admin_action($gid, $mybb->input['name']); + + flash_message($lang->success_setting_group_added, 'success'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + } + + $page->add_breadcrumb_item($lang->add_new_setting_group); + $page->output_header($lang->board_settings." - ".$lang->add_new_setting_group); + + $sub_tabs['change_settings'] = array( + 'title' => $lang->change_settings, + 'link' => "index.php?module=config-settings" + ); + + $sub_tabs['add_setting'] = array( + 'title' => $lang->add_new_setting, + 'link' => "index.php?module=config-settings&action=add" + ); + + $sub_tabs['add_setting_group'] = array( + 'title' => $lang->add_new_setting_group, + 'link' => "index.php?module=config-settings&action=addgroup", + 'description' => $lang->add_new_setting_group_desc + ); + + $sub_tabs['modify_setting'] = array( + 'title' => $lang->modify_existing_settings, + 'link' => "index.php?module=config-settings&action=manage" + ); + + $page->output_nav_tabs($sub_tabs, 'add_setting_group'); + + $form = new Form("index.php?module=config-settings&action=addgroup", "post", "add"); + + if($errors) + { + $page->output_inline_error($errors); + } + + $form_container = new FormContainer($lang->add_new_setting_group); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->description, "", $form->generate_text_area('description', $mybb->input['description'], array('id' => 'description')), 'description'); + $form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder')), 'disporder'); + $form_container->output_row($lang->name." *", $lang->group_name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->insert_new_setting_group); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +// Edit setting group +if($mybb->input['action'] == "editgroup") +{ + $query = $db->simple_select("settinggroups", "*", "gid='".(int)$mybb->input['gid']."'"); + $group = $db->fetch_array($query); + + // Does the setting not exist? + if(!$group['gid']) + { + flash_message($lang->error_invalid_gid2, 'error'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + // Prevent editing of default + if($group['isdefault'] == 1) + { + flash_message($lang->error_cannot_edit_default, 'error'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + + $plugins->run_hooks("admin_config_settings_editgroup"); + + // Do edit? + if($mybb->request_method == "post") + { + // Validate title + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_group_title; + } + + // Validate identifier + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_group_name; + } + $query = $db->simple_select("settinggroups", "title", "name='".$db->escape_string($mybb->input['name'])."' AND gid != '{$group['gid']}'"); + if($db->num_rows($query) > 0) + { + $dup_group_title = $db->fetch_field($query, 'title'); + $errors[] = $lang->sprintf($lang->error_duplicate_group_name, $dup_group_title); + } + + if(!$errors) + { + $update_setting_group = array( + "name" => $db->escape_string($mybb->input['name']), + "title" => $db->escape_string($mybb->input['title']), + "description" => $db->escape_string($mybb->input['description']), + "disporder" => (int)$mybb->input['disporder'], + ); + + $plugins->run_hooks("admin_config_settings_editgroup_commit"); + + $db->update_query("settinggroups", $update_setting_group, "gid='{$group['gid']}'"); + + // Log admin action + log_admin_action($group['gid'], $mybb->input['name']); + + flash_message($lang->success_setting_group_updated, 'success'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + } + + $page->add_breadcrumb_item($lang->edit_setting_group); + $page->output_header($lang->board_settings." - ".$lang->edit_setting_group); + + $sub_tabs['edit_setting_group'] = array( + 'title' => $lang->edit_setting_group, + 'link' => "index.php?module=config-settings&action=editgroup&gid={$group['gid']}", + 'description' => $lang->edit_setting_group_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_setting_group'); + + $form = new Form("index.php?module=config-settings&action=editgroup", "post", "editgroup"); + + echo $form->generate_hidden_field("gid", $group['gid']); + + if($errors) + { + $group_data = $mybb->input; + $page->output_inline_error($errors); + } + else + { + $group_data = $group; + } + + $form_container = new FormContainer($lang->edit_setting_group); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $group_data['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->description, "", $form->generate_text_area('description', $group_data['description'], array('id' => 'description')), 'description'); + $form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $group_data['disporder'], array('id' => 'disporder')), 'disporder'); + $form_container->output_row($lang->name." *", $lang->group_name_desc, $form->generate_text_box('name', $group_data['name'], array('id' => 'name')), 'name'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->update_setting_group); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +// Delete Setting Group +if($mybb->input['action'] == "deletegroup") +{ + $query = $db->simple_select("settinggroups", "*", "gid='".(int)$mybb->input['gid']."'"); + $group = $db->fetch_array($query); + + // Does the setting group not exist? + if(!$group['gid']) + { + flash_message($lang->error_invalid_gid2, 'error'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + // Prevent deletion of default + if($group['isdefault'] == 1) + { + flash_message($lang->error_cannot_edit_default, 'error'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-settings&action=manage"); + } + + $plugins->run_hooks("admin_config_settings_deletegroup"); + + if($mybb->request_method == "post") + { + // Delete the setting group and its settings + $db->delete_query("settinggroups", "gid='{$group['gid']}'"); + $db->delete_query("settings", "gid='{$group['gid']}'"); + + rebuild_settings(); + + $plugins->run_hooks("admin_config_settings_deletegroup_commit"); + + // Log admin action + log_admin_action($group['gid'], $group['name']); + + flash_message($lang->success_setting_group_deleted, 'success'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + else + { + $page->output_confirm_action("index.php?module=config-settings&action=deletegroup&gid={$group['gid']}", $lang->confirm_setting_group_deletion); + } +} + +// Creating a new setting +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_config_settings_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + $query = $db->simple_select("settinggroups", "gid", "gid='".(int)$mybb->input['gid']."'"); + $gid = $db->fetch_field($query, 'gid'); + if(!$gid) + { + $errors[] = $lang->error_invalid_gid; + } + + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_name; + } + $query = $db->simple_select("settings", "title", "name='".$db->escape_string($mybb->input['name'])."'"); + if($db->num_rows($query) > 0) + { + $dup_setting_title = $db->fetch_field($query, 'title'); + $errors[] = $lang->sprintf($lang->error_duplicate_name, $dup_setting_title); + } + + // do some type filtering + $mybb->input['type'] = str_replace("\n", "", $mybb->input['type']); + if(strtolower(substr($mybb->input['type'], 0, 3)) == "php") + { + $mybb->input['type'] = ""; + } + + if(!$mybb->input['type']) + { + $errors[] = $lang->error_invalid_type; + } + + if(!$errors) + { + if($mybb->input['type'] == "custom") + { + $options_code = $mybb->input['extra']; + } + else if($mybb->input['extra']) + { + $options_code = "{$mybb->input['type']}\n{$mybb->input['extra']}"; + } + else + { + $options_code = $mybb->input['type']; + } + + $mybb->input['name'] = str_replace("\\", '', $mybb->input['name']); + $mybb->input['name'] = str_replace('$', '', $mybb->input['name']); + $mybb->input['name'] = str_replace("'", '', $mybb->input['name']); + + if($options_code == "numeric") + { + $value = (int)$mybb->input['value']; + } + else + { + $value = $db->escape_string($mybb->input['value']); + } + + $new_setting = array( + "name" => $db->escape_string($mybb->input['name']), + "title" => $db->escape_string($mybb->input['title']), + "description" => $db->escape_string($mybb->input['description']), + "optionscode" => $db->escape_string($options_code), + "value" => $value, + "disporder" => (int)$mybb->input['disporder'], + "gid" => (int)$mybb->input['gid'] + ); + + $sid = $db->insert_query("settings", $new_setting); + rebuild_settings(); + + $plugins->run_hooks("admin_config_settings_add_commit"); + + // Log admin action + log_admin_action($sid, $mybb->input['title']); + + flash_message($lang->success_setting_added, 'success'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + } + + $page->add_breadcrumb_item($lang->add_new_setting); + $page->output_header($lang->board_settings." - ".$lang->add_new_setting); + + $sub_tabs['change_settings'] = array( + 'title' => $lang->change_settings, + 'link' => "index.php?module=config-settings" + ); + + $sub_tabs['add_setting'] = array( + 'title' => $lang->add_new_setting, + 'link' => "index.php?module=config-settings&action=add", + 'description' => $lang->add_new_setting_desc + ); + + $sub_tabs['add_setting_group'] = array( + 'title' => $lang->add_new_setting_group, + 'link' => "index.php?module=config-settings&action=addgroup" + ); + + $sub_tabs['modify_setting'] = array( + 'title' => $lang->modify_existing_settings, + 'link' => "index.php?module=config-settings&action=manage" + ); + + $page->output_nav_tabs($sub_tabs, 'add_setting'); + + $form = new Form("index.php?module=config-settings&action=add", "post", "add"); + + if($errors) + { + $page->output_inline_error($errors); + } + + $form_container = new FormContainer($lang->add_new_setting); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->description, "", $form->generate_text_area('description', $mybb->input['description'], array('id' => 'description')), 'description'); + + $query = $db->simple_select("settinggroups", "*", "", array('order_by' => 'disporder')); + while($group = $db->fetch_array($query)) + { + $options[$group['gid']] = $group['title']; + } + $form_container->output_row($lang->group." *", "", $form->generate_select_box("gid", $options, $mybb->input['gid'], array('id' => 'gid')), 'gid'); + $form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder')), 'disporder'); + + $form_container->output_row($lang->name." *", $lang->name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + + $setting_types = array( + "text" => $lang->text, + "numeric" => $lang->numeric_text, + "textarea" => $lang->textarea, + "yesno" => $lang->yesno, + "onoff" => $lang->onoff, + "select" => $lang->select, + "forumselect" => $lang->forum_selection_box, + "groupselect" => $lang->group_selection_box, + "radio" => $lang->radio, + "checkbox" => $lang->checkbox, + "language" => $lang->language_selection_box, + "adminlanguage" => $lang->adminlanguage, + "cpstyle" => $lang->cpstyle, + //"php" => $lang->php // Internal Use Only + ); + + $form_container->output_row($lang->type." *", "", $form->generate_select_box("type", $setting_types, $mybb->input['type'], array('id' => 'type')), 'type'); + $form_container->output_row($lang->extra, $lang->extra_desc, $form->generate_text_area('extra', $mybb->input['extra'], array('id' => 'extra')), 'extra', array(), array('id' => 'row_extra')); + $form_container->output_row($lang->value, "", $form->generate_text_area('value', $mybb->input['value'], array('id' => 'value')), 'value'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->insert_new_setting); + $form->output_submit_wrapper($buttons); + $form->end(); + + echo ' + '; + + $page->output_footer(); +} + +// Editing a particular setting +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("settings", "*", "sid='".$mybb->get_input('sid', 1)."'"); + $setting = $db->fetch_array($query); + + // Does the setting not exist? + if(!$setting['sid']) + { + flash_message($lang->error_invalid_sid, 'error'); + admin_redirect("index.php?module=config-settings"); + } + + // Prevent editing of default + if($setting['isdefault'] == 1) + { + flash_message($lang->error_cannot_edit_default, 'error'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + + $plugins->run_hooks("admin_config_settings_edit"); + + $type = explode("\n", $setting['optionscode'], 2); + $type = trim($type[0]); + if($type == "php") + { + flash_message($lang->error_cannot_edit_php, 'error'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_name; + } + $query = $db->simple_select("settings", "title", "name='".$db->escape_string($mybb->input['name'])."' AND sid != '{$setting['sid']}'"); + if($db->num_rows($query) > 0) + { + $dup_setting_title = $db->fetch_field($query, 'title'); + $errors[] = $lang->sprintf($lang->error_duplicate_name, $dup_setting_title); + } + + // do some type filtering + $mybb->input['type'] = str_replace("\n", "", $mybb->input['type']); + if(strtolower(substr($mybb->input['type'], 0, 3)) == "php") + { + $mybb->input['type'] = ""; + } + + if(!$mybb->input['type']) + { + $errors[] = $lang->error_invalid_type; + } + + if(!$errors) + { + if($mybb->input['type'] == "custom") + { + $options_code = $mybb->input['extra']; + } + else if($mybb->input['extra']) + { + $options_code = "{$mybb->input['type']}\n{$mybb->input['extra']}"; + } + else + { + $options_code = $mybb->input['type']; + } + + $mybb->input['name'] = str_replace("\\", '', $mybb->input['name']); + $mybb->input['name'] = str_replace('$', '', $mybb->input['name']); + $mybb->input['name'] = str_replace("'", '', $mybb->input['name']); + + if($options_code == "numeric") + { + $value = (int)$mybb->input['value']; + } + else + { + $value = $db->escape_string($mybb->input['value']); + } + + $updated_setting = array( + "name" => $db->escape_string($mybb->input['name']), + "title" => $db->escape_string($mybb->input['title']), + "description" => $db->escape_string($mybb->input['description']), + "optionscode" => $db->escape_string($options_code), + "value" => $value, + "disporder" => (int)$mybb->input['disporder'], + "gid" => (int)$mybb->input['gid'] + ); + + $plugins->run_hooks("admin_config_settings_edit_commit"); + + $db->update_query("settings", $updated_setting, "sid='{$mybb->input['sid']}'"); + rebuild_settings(); + + // Log admin action + log_admin_action($setting['sid'], $mybb->input['title']); + + flash_message($lang->success_setting_updated, 'success'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + } + + $page->add_breadcrumb_item($lang->edit_setting); + $page->output_header($lang->board_settings." - ".$lang->edit_setting); + + $sub_tabs['change_settings'] = array( + 'title' => $lang->change_settings, + 'link' => "index.php?module=config-settings", + ); + + $sub_tabs['add_setting'] = array( + 'title' => $lang->add_new_setting, + 'link' => "index.php?module=config-settings&action=add" + ); + + $sub_tabs['add_setting_group'] = array( + 'title' => $lang->add_new_setting_group, + 'link' => "index.php?module=config-settings&action=addgroup" + ); + + $sub_tabs['modify_setting'] = array( + 'title' => $lang->modify_existing_settings, + 'link' => "index.php?module=config-settings&action=manage", + 'description' => $lang->modify_existing_settings_desc + ); + + $page->output_nav_tabs($sub_tabs, 'modify_setting'); + + $form = new Form("index.php?module=config-settings&action=edit", "post", "edit"); + + echo $form->generate_hidden_field("sid", $setting['sid']); + + if($errors) + { + $setting_data = $mybb->input; + $page->output_inline_error($errors); + } + else + { + $setting_data = $setting; + $type = explode("\n", $setting['optionscode'], 2); + $setting_data['type'] = trim($type[0]); + $setting_data['extra'] = trim($type[1]); + } + + $form_container = new FormContainer($lang->modify_setting); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $setting_data['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->description, "", $form->generate_text_area('description', $setting_data['description'], array('id' => 'description')), 'description'); + + $query = $db->simple_select("settinggroups", "*", "", array('order_by' => 'disporder')); + while($group = $db->fetch_array($query)) + { + $options[$group['gid']] = $group['title']; + } + $form_container->output_row($lang->group." *", "", $form->generate_select_box("gid", $options, $setting_data['gid'], array('id' => 'gid')), 'gid'); + $form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $setting_data['disporder'], array('id' => 'disporder')), 'disporder'); + $form_container->end(); + + $form_container = new FormContainer($lang->setting_configuration, 1); + $form_container->output_row($lang->name." *", $lang->name_desc, $form->generate_text_box('name', $setting_data['name'], array('id' => 'name')), 'name'); + + $setting_types = array( + "text" => $lang->text, + "numeric" => $lang->numeric_text, + "textarea" => $lang->textarea, + "yesno" => $lang->yesno, + "onoff" => $lang->onoff, + "select" => $lang->select, + "forumselect" => $lang->forum_selection_box, + "groupselect" => $lang->group_selection_box, + "radio" => $lang->radio, + "checkbox" => $lang->checkbox, + "language" => $lang->language_selection_box, + "adminlanguage" => $lang->adminlanguage, + "cpstyle" => $lang->cpstyle, + //"php" => $lang->php // Internal Use Only + ); + + $form_container->output_row($lang->type." *", "", $form->generate_select_box("type", $setting_types, $setting_data['type'], array('id' => 'type')), 'type'); + $form_container->output_row($lang->extra, $lang->extra_desc, $form->generate_text_area('extra', $setting_data['extra'], array('id' => 'extra')), 'extra', array(), array('id' => 'row_extra')); + $form_container->output_row($lang->value, '', $form->generate_text_area('value', $setting_data['value'], array('id' => 'value')), 'value'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->update_setting); + $form->output_submit_wrapper($buttons); + $form->end(); + + echo ' + '; + + $page->output_footer(); +} + +// Delete Setting +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("settings", "*", "sid='".$mybb->get_input('sid', 1)."'"); + $setting = $db->fetch_array($query); + + // Does the setting not exist? + if(!$setting['sid']) + { + flash_message($lang->error_invalid_sid, 'error'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + + // Prevent editing of default + if($setting['isdefault'] == 1) + { + flash_message($lang->error_cannot_edit_default, 'error'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-settings&action=manage"); + } + + $plugins->run_hooks("admin_config_settings_delete"); + + if($mybb->request_method == "post") + { + // Delete the setting + $db->delete_query("settings", "sid='{$setting['sid']}'"); + + rebuild_settings(); + + $plugins->run_hooks("admin_config_settings_delete_commit"); + + // Log admin action + log_admin_action($setting['sid'], $setting['title']); + + flash_message($lang->success_setting_deleted, 'success'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + else + { + $page->output_confirm_action("index.php?module=config-settings&action=delete&sid={$setting['sid']}", $lang->confirm_setting_deletion); + } +} + +// Modify Existing Settings +if($mybb->input['action'] == "manage") +{ + $plugins->run_hooks("admin_config_settings_manage"); + + // Update orders + if($mybb->request_method == "post") + { + if(is_array($mybb->input['group_disporder'])) + { + foreach($mybb->input['group_disporder'] as $gid => $new_order) + { + $gid = (int)$gid; + $update_group = array('disporder' => (int)$new_order); + $db->update_query("settinggroups", $update_group, "gid={$gid}"); + } + } + + if(is_array($mybb->input['setting_disporder'])) + { + foreach($mybb->input['setting_disporder'] as $sid => $new_order) + { + $sid = (int)$sid; + $update_setting = array('disporder' => (int)$new_order); + $db->update_query("settings", $update_setting, "sid={$sid}"); + } + } + + $plugins->run_hooks("admin_config_settings_manage_commit"); + + // Log admin action + log_admin_action(); + + flash_message($lang->success_display_orders_updated, 'success'); + admin_redirect("index.php?module=config-settings&action=manage"); + } + + $page->add_breadcrumb_item($lang->modify_existing_settings); + $page->output_header($lang->board_settings." - ".$lang->modify_existing_settings); + + $sub_tabs['change_settings'] = array( + 'title' => $lang->change_settings, + 'link' => "index.php?module=config-settings", + ); + + $sub_tabs['add_setting'] = array( + 'title' => $lang->add_new_setting, + 'link' => "index.php?module=config-settings&action=add" + ); + + $sub_tabs['add_setting_group'] = array( + 'title' => $lang->add_new_setting_group, + 'link' => "index.php?module=config-settings&action=addgroup" + ); + + $sub_tabs['modify_setting'] = array( + 'title' => $lang->modify_existing_settings, + 'link' => "index.php?module=config-settings&action=manage", + 'description' => $lang->modify_existing_settings_desc + ); + + $page->output_nav_tabs($sub_tabs, 'modify_setting'); + + // Cache settings + $settings_cache = array(); + $query = $db->simple_select("settings", "sid, name, title, disporder, gid, isdefault", "", array('order_by' => 'disporder', 'order_dir' => 'asc')); + while($setting = $db->fetch_array($query)) + { + $settings_cache[$setting['gid']][] = $setting; + } + + $form = new Form("index.php?module=config-settings&action=manage", "post", "edit"); + + $table = new Table; + + $table->construct_header($lang->setting_group_setting); + $table->construct_header($lang->order, array('class' => 'align_center', 'style' => 'width: 5%')); + $table->construct_header($lang->controls, array('class' => 'align_center', 'style' => 'width: 200px')); + + // Generate table + $query = $db->simple_select("settinggroups", "*", "", array('order_by' => 'disporder', 'order_dir' => 'asc')); + while($group = $db->fetch_array($query)) + { + // Make setting group row + // Translated? + $group_lang_var = "setting_group_{$group['name']}"; + if($lang->$group_lang_var) + { + $group_title = htmlspecialchars_uni($lang->$group_lang_var); + } + else + { + $group_title = htmlspecialchars_uni($group['title']); + } + $table->construct_cell("{$group_title}", array('id' => "group{$group['gid']}")); + $table->construct_cell($form->generate_numeric_field("group_disporder[{$group['gid']}]", $group['disporder'], array('style' => 'width: 80%; font-weight: bold', 'class' => 'align_center'))); + // Only show options if not a default setting group + if($group['isdefault'] != 1) + { + $popup = new PopupMenu("group_{$group['gid']}", $lang->options); + $popup->add_item($lang->edit_setting_group, "index.php?module=config-settings&action=editgroup&gid={$group['gid']}"); + $popup->add_item($lang->delete_setting_group, "index.php?module=config-settings&action=deletegroup&gid={$group['gid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_setting_group_deletion}')"); + $table->construct_cell($popup->fetch(), array('class' => 'align_center')); + } + else + { + $table->construct_cell(''); + } + $table->construct_row(array('class' => 'alt_row', 'no_alt_row' => 1)); + + // Make rows for each setting in the group + if(is_array($settings_cache[$group['gid']])) + { + foreach($settings_cache[$group['gid']] as $setting) + { + $setting_lang_var = "setting_{$setting['name']}"; + if($lang->$setting_lang_var) + { + $setting_title = htmlspecialchars_uni($lang->$setting_lang_var); + } + else + { + $setting_title = htmlspecialchars_uni($setting['title']); + } + $table->construct_cell($setting_title, array('style' => 'padding-left: 40px;')); + $table->construct_cell($form->generate_numeric_field("setting_disporder[{$setting['sid']}]", $setting['disporder'], array('style' => 'width: 80%', 'class' => 'align_center'))); + // Only show options if not a default setting group or is a custom setting + if($group['isdefault'] != 1 || $setting['isdefault'] != 1) + { + $popup = new PopupMenu("setting_{$setting['sid']}", $lang->options); + $popup->add_item($lang->edit_setting, "index.php?module=config-settings&action=edit&sid={$setting['sid']}"); + $popup->add_item($lang->delete_setting, "index.php?module=config-settings&action=delete&sid={$setting['sid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_setting_deletion}')"); + $table->construct_cell($popup->fetch(), array('class' => 'align_center')); + } + else + { + $table->construct_cell(''); + } + $table->construct_row(array('no_alt_row' => 1, 'class' => "group{$group['gid']}")); + } + } + } + + $table->output($lang->modify_existing_settings); + + $buttons[] = $form->generate_submit_button($lang->save_display_orders); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +// Change settings for a specified group. +if($mybb->input['action'] == "change") +{ + $plugins->run_hooks("admin_config_settings_change"); + + if($mybb->request_method == "post") + { + if(!is_writable(MYBB_ROOT.'inc/settings.php')) + { + flash_message($lang->error_chmod_settings_file, 'error'); + admin_redirect("index.php?module=config-settings"); + } + + // If we are changing the hidden captcha, make sure it doesn't conflict with another registration field + if(isset($mybb->input['upsetting']['hiddencaptchaimagefield'])) + { + // Not allowed to be hidden captcha fields + $disallowed_fields = array( + 'username', + 'password', + 'password2', + 'email', + 'email2', + 'imagestring', + 'allownotices', + 'hideemail', + 'receivepms', + 'pmnotice', + 'emailpmnotify', + 'invisible', + 'subscriptionmethod', + 'timezoneoffset', + 'dstcorrection', + 'language', + 'step', + 'action', + 'regsubmit' + ); + + if(in_array($mybb->input['upsetting']['hiddencaptchaimagefield'], $disallowed_fields)) + { + // Whoopsies, you can't do that! + $error_message = $lang->sprintf($lang->error_hidden_captcha_conflict, htmlspecialchars_uni($mybb->input['upsetting']['hiddencaptchaimagefield'])); + + flash_message($error_message, 'error'); + admin_redirect("index.php?module=config-settings&action=change&gid=9"); + } + } + + // Get settings which optionscode is a forum/group select + // We cannot rely on user input to decide this + $forum_group_select = array(); + $query = $db->simple_select('settings', 'name', 'optionscode IN (\'forumselect\', \'groupselect\')'); + while($name = $db->fetch_field($query, 'name')) + { + $forum_group_select[] = $name; + } + + if(is_array($mybb->input['upsetting'])) + { + foreach($mybb->input['upsetting'] as $name => $value) + { + if(!empty($forum_group_select) && in_array($name, $forum_group_select)) + { + if($value == 'all') + { + $value = -1; + } + elseif($value == 'custom') + { + if(isset($mybb->input['select'][$name]) && is_array($mybb->input['select'][$name])) + { + foreach($mybb->input['select'][$name] as &$val) + { + $val = (int)$val; + } + unset($val); + + $value = implode(',', (array)$mybb->input['select'][$name]); + } + else + { + $value = ''; + } + } + else + { + $value = ''; + } + } + + $value = $db->escape_string($value); + $db->update_query("settings", array('value' => $value), "name='".$db->escape_string($name)."'"); + } + } + + // Check if we need to create our fulltext index after changing the search mode + if($mybb->settings['searchtype'] != $mybb->input['upsetting']['searchtype'] && $mybb->input['upsetting']['searchtype'] == "fulltext") + { + if(!$db->is_fulltext("posts") && $db->supports_fulltext_boolean("posts")) + { + $db->create_fulltext_index("posts", "message"); + } + if(!$db->is_fulltext("posts") && $db->supports_fulltext("threads")) + { + $db->create_fulltext_index("threads", "subject"); + } + } + + // If the delayedthreadviews setting was changed, enable or disable the tasks for it. + if(isset($mybb->input['upsetting']['delayedthreadviews']) && $mybb->settings['delayedthreadviews'] != $mybb->input['upsetting']['delayedthreadviews']) + { + if($mybb->input['upsetting']['delayedthreadviews'] == 0) + { + $updated_task = array( + "enabled" => 0 + ); + } + else + { + $updated_task = array( + "enabled" => 1 + ); + } + $db->update_query("tasks", $updated_task, "file='threadviews'"); + } + + // Have we changed our cookie prefix? If so, update our adminsid so we're not logged out + if($mybb->input['upsetting']['cookieprefix'] && $mybb->input['upsetting']['cookieprefix'] != $mybb->settings['cookieprefix']) + { + my_unsetcookie("adminsid"); + $mybb->settings['cookieprefix'] = $mybb->input['upsetting']['cookieprefix']; + my_setcookie("adminsid", $admin_session['sid'], '', true); + } + + // Have we opted for a reCAPTCHA and not set a public/private key? + if($mybb->input['upsetting']['captchaimage'] == 2 && !$mybb->input['upsetting']['captchaprivatekey'] && !$mybb->input['upsetting']['captchapublickey']) + { + $db->update_query("settings", array("value" => 1), "name = 'captchaimage'"); + } + + rebuild_settings(); + + $plugins->run_hooks("admin_config_settings_change_commit"); + + // If we have changed our report reasons recache them + if(isset($mybb->input['upsetting']['reportreasons'])) + { + $cache->update_reportedposts(); + } + + // Log admin action + log_admin_action(); + + flash_message($lang->success_settings_updated, 'success'); + admin_redirect("index.php?module=config-settings"); + } + + // What type of page + $cache_groups = $cache_settings = array(); + if(isset($mybb->input['search'])) + { + // Search + + // Search for settings + $search = $db->escape_string_like($mybb->input['search']); + $query = $db->query(" + SELECT s.* + FROM ".TABLE_PREFIX."settings s + LEFT JOIN ".TABLE_PREFIX."settinggroups g ON(s.gid=g.gid) + WHERE s.name LIKE '%{$search}%' OR s.title LIKE '%{$search}%' OR s.description LIKE '%{$search}%' OR g.name LIKE '%{$search}%' OR g.title LIKE '%{$search}%' OR g.description LIKE '%{$search}%' + ORDER BY s.disporder + "); + while($setting = $db->fetch_array($query)) + { + $cache_settings[$setting['gid']][$setting['sid']] = $setting; + } + + if(!$db->num_rows($query)) + { + if(isset($mybb->input['ajax_search'])) + { + echo json_encode(array("errors" => array($lang->error_no_settings_found))); + exit; + } + else + { + flash_message($lang->error_no_settings_found, 'error'); + admin_redirect("index.php?module=config-settings"); + } + } + + // Cache groups + $groups = array_keys($cache_settings); + $groups = implode(',', $groups); + $query = $db->simple_select("settinggroups", "*", "gid IN ({$groups})", array('order_by' => 'disporder')); + while($group = $db->fetch_array($query)) + { + $cache_groups[$group['gid']] = $group; + } + + // Page header only if not AJAX + if(!isset($mybb->input['ajax_search'])) + { + $page->add_breadcrumb_item($lang->settings_search); + $page->output_header($lang->board_settings." - {$lang->settings_search}"); + } + + $form = new Form("index.php?module=config-settings&action=change", "post", "change"); + + echo $form->generate_hidden_field("gid", $group['gid']); + } + elseif($mybb->input['gid']) + { + // Group listing + // Cache groups + $query = $db->simple_select("settinggroups", "*", "gid = '".(int)$mybb->input['gid']."'"); + $groupinfo = $db->fetch_array($query); + $cache_groups[$groupinfo['gid']] = $groupinfo; + + if(!$db->num_rows($query)) + { + $page->output_error($lang->error_invalid_gid2); + } + + // Cache settings + $query = $db->simple_select("settings", "*", "gid='".(int)$mybb->input['gid']."'", array('order_by' => 'disporder')); + while($setting = $db->fetch_array($query)) + { + $cache_settings[$setting['gid']][$setting['sid']] = $setting; + } + + if(!$db->num_rows($query)) + { + flash_message($lang->error_no_settings_found, 'error'); + admin_redirect("index.php?module=config-settings"); + } + + $group_lang_var = "setting_group_{$groupinfo['name']}"; + if(isset($lang->$group_lang_var)) + { + $groupinfo['title'] = $lang->$group_lang_var; + } + + // Page header + $page->add_breadcrumb_item($groupinfo['title']); + $page->output_header($lang->board_settings." - {$groupinfo['title']}"); + + $form = new Form("index.php?module=config-settings&action=change", "post", "change"); + + echo $form->generate_hidden_field("gid", $groupinfo['gid']); + } + else + { + // All settings list + // Cache groups + $query = $db->simple_select("settinggroups", "*", "", array('order_by' => 'disporder')); + while($group = $db->fetch_array($query)) + { + $cache_groups[$group['gid']] = $group; + } + + if(!$db->num_rows($query)) + { + $page->output_error($lang->error_invalid_gid2); + } + + // Cache settings + $query = $db->simple_select("settings", "*", "", array('order_by' => 'disporder')); + while($setting = $db->fetch_array($query)) + { + $cache_settings[$setting['gid']][$setting['sid']] = $setting; + } + + // Page header + $page->add_breadcrumb_item($lang->show_all_settings); + $page->output_header($lang->board_settings." - {$lang->show_all_settings}"); + + $form = new Form("index.php?module=config-settings&action=change", "post", "change"); + } + + // Build rest of page + $buttons[] = $form->generate_submit_button($lang->save_settings); + foreach($cache_groups as $groupinfo) + { + $group_lang_var = "setting_group_{$groupinfo['name']}"; + if(isset($lang->$group_lang_var)) + { + $groupinfo['title'] = $lang->$group_lang_var; + } + + $form_container = new FormContainer($groupinfo['title']); + + if(empty($cache_settings[$groupinfo['gid']])) + { + $form_container->output_cell($lang->error_no_settings_found); + $form_container->construct_row(); + + $form_container->end(); + echo '
'; + + continue; + } + + foreach($cache_settings[$groupinfo['gid']] as $setting) + { + $options = ""; + $type = explode("\n", $setting['optionscode']); + $type[0] = trim($type[0]); + $element_name = "upsetting[{$setting['name']}]"; + $element_id = "setting_{$setting['name']}"; + if($type[0] == "text" || $type[0] == "") + { + $setting_code = $form->generate_text_box($element_name, $setting['value'], array('id' => $element_id)); + } + else if($type[0] == "numeric") + { + $setting_code = $form->generate_numeric_field($element_name, $setting['value'], array('id' => $element_id)); + } + else if($type[0] == "textarea") + { + $setting_code = $form->generate_text_area($element_name, $setting['value'], array('id' => $element_id)); + } + else if($type[0] == "yesno") + { + $setting_code = $form->generate_yes_no_radio($element_name, $setting['value'], true, array('id' => $element_id.'_yes', 'class' => $element_id), array('id' => $element_id.'_no', 'class' => $element_id)); + } + else if($type[0] == "onoff") + { + $setting_code = $form->generate_on_off_radio($element_name, $setting['value'], true, array('id' => $element_id.'_on', 'class' => $element_id), array('id' => $element_id.'_off', 'class' => $element_id)); + } + else if($type[0] == "cpstyle") + { + $dir = @opendir(MYBB_ROOT.$config['admin_dir']."/styles"); + + $folders = array(); + while($folder = readdir($dir)) + { + if($file != "." && $file != ".." && @file_exists(MYBB_ROOT.$config['admin_dir']."/styles/$folder/main.css")) + { + $folders[$folder] = ucfirst($folder); + } + } + closedir($dir); + ksort($folders); + $setting_code = $form->generate_select_box($element_name, $folders, $setting['value'], array('id' => $element_id)); + } + else if($type[0] == "language") + { + $languages = $lang->get_languages(); + $setting_code = $form->generate_select_box($element_name, $languages, $setting['value'], array('id' => $element_id)); + } + else if($type[0] == "adminlanguage") + { + $languages = $lang->get_languages(1); + $setting_code = $form->generate_select_box($element_name, $languages, $setting['value'], array('id' => $element_id)); + } + else if($type[0] == "passwordbox") + { + $setting_code = $form->generate_password_box($element_name, $setting['value'], array('id' => $element_id)); + } + else if($type[0] == "php") + { + $setting['optionscode'] = substr($setting['optionscode'], 3); + eval("\$setting_code = \"".$setting['optionscode']."\";"); + } + else if($type[0] == "forumselect") + { + $selected_values = ''; + if($setting['value'] != '' && $setting['value'] != -1) + { + $selected_values = explode(',', (string)$setting['value']); + + foreach($selected_values as &$value) + { + $value = (int)$value; + } + unset($value); + } + + $forum_checked = array('all' => '', 'custom' => '', 'none' => ''); + if($setting['value'] == -1) + { + $forum_checked['all'] = 'checked="checked"'; + } + elseif($setting['value'] != '') + { + $forum_checked['custom'] = 'checked="checked"'; + } + else + { + $forum_checked['none'] = 'checked="checked"'; + } + + print_selection_javascript(); + + $setting_code = " +
+
+
+
+ + + + + +
{$lang->forums_colon}".$form->generate_forum_select('select['.$setting['name'].'][]', $selected_values, array('id' => $element_id, 'multiple' => true, 'size' => 5))."
+
+
+
+ "; + } + else if($type[0] == "groupselect") + { + $selected_values = ''; + if($setting['value'] != '' && $setting['value'] != -1) + { + $selected_values = explode(',', (string)$setting['value']); + + foreach($selected_values as &$value) + { + $value = (int)$value; + } + unset($value); + } + + $group_checked = array('all' => '', 'custom' => '', 'none' => ''); + if($setting['value'] == -1) + { + $group_checked['all'] = 'checked="checked"'; + } + elseif($setting['value'] != '') + { + $group_checked['custom'] = 'checked="checked"'; + } + else + { + $group_checked['none'] = 'checked="checked"'; + } + + print_selection_javascript(); + + $setting_code = " +
+
+
+
+ + + + + +
{$lang->groups_colon}".$form->generate_group_select('select['.$setting['name'].'][]', $selected_values, array('id' => $element_id, 'multiple' => true, 'size' => 5))."
+
+
+
+ "; + } + else + { + for($i=0; $i < count($type); $i++) + { + $optionsexp = explode("=", $type[$i]); + if(!isset($optionsexp[1])) + { + continue; + } + $title_lang = "setting_{$setting['name']}_{$optionsexp[0]}"; + if(isset($lang->$title_lang)) + { + $optionsexp[1] = $lang->$title_lang; + } + + if($type[0] == "select") + { + $option_list[$optionsexp[0]] = htmlspecialchars_uni($optionsexp[1]); + } + else if($type[0] == "radio") + { + if($setting['value'] == $optionsexp[0]) + { + $option_list[$i] = $form->generate_radio_button($element_name, $optionsexp[0], htmlspecialchars_uni($optionsexp[1]), array('id' => $element_id.'_'.$i, "checked" => 1, 'class' => $element_id)); + } + else + { + $option_list[$i] = $form->generate_radio_button($element_name, $optionsexp[0], htmlspecialchars_uni($optionsexp[1]), array('id' => $element_id.'_'.$i, 'class' => $element_id)); + } + } + else if($type[0] == "checkbox") + { + if($setting['value'] == $optionsexp[0]) + { + $option_list[$i] = $form->generate_check_box($element_name, $optionsexp[0], htmlspecialchars_uni($optionsexp[1]), array('id' => $element_id.'_'.$i, "checked" => 1, 'class' => $element_id)); + } + else + { + $option_list[$i] = $form->generate_check_box($element_name, $optionsexp[0], htmlspecialchars_uni($optionsexp[1]), array('id' => $element_id.'_'.$i, 'class' => $element_id)); + } + } + } + if($type[0] == "select") + { + $setting_code = $form->generate_select_box($element_name, $option_list, $setting['value'], array('id' => $element_id)); + } + else + { + $setting_code = implode("
", $option_list); + } + $option_list = array(); + } + // Do we have a custom language variable for this title or description? + $title_lang = "setting_".$setting['name']; + $desc_lang = $title_lang."_desc"; + if(isset($lang->$title_lang)) + { + $setting['title'] = $lang->$title_lang; + } + if(isset($lang->$desc_lang)) + { + $setting['description'] = $lang->$desc_lang; + } + $form_container->output_row(htmlspecialchars_uni($setting['title']), $setting['description'], $setting_code, '', array(), array('id' => 'row_'.$element_id)); + } + $form_container->end(); + + $form->output_submit_wrapper($buttons); + echo '
'; + } + $form->end(); + + print_setting_peekers(); + + if(!isset($mybb->input['ajax_search'])) + { + $page->output_footer(); + } +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_config_settings_start"); + + $page->extra_header .= << + + +EOF; + + $page->output_header($lang->board_settings); + if(isset($message)) + { + $page->output_inline_message($message); + } + + $sub_tabs['change_settings'] = array( + 'title' => $lang->change_settings, + 'link' => "index.php?module=config-settings", + 'description' => $lang->change_settings_desc + ); + + $sub_tabs['add_setting'] = array( + 'title' => $lang->add_new_setting, + 'link' => "index.php?module=config-settings&action=add" + ); + + $sub_tabs['add_setting_group'] = array( + 'title' => $lang->add_new_setting_group, + 'link' => "index.php?module=config-settings&action=addgroup" + ); + + $sub_tabs['modify_setting'] = array( + 'title' => $lang->modify_existing_settings, + 'link' => "index.php?module=config-settings&action=manage", + ); + + $page->output_nav_tabs($sub_tabs, 'change_settings'); + + // Search form + echo "
"; + $search = new Form("index.php", 'get', 'settings_search', 0, 'settings_search'); + echo $search->generate_hidden_field('module', 'config/settings'); + echo $search->generate_hidden_field('action', 'change'); + echo $search->generate_text_box('search', $lang->settings_search, array('id' => 'search', 'class' => 'search_default field150 field_small')); + echo "search}\" />"; + $search->end(); + echo "
\n"; + + echo '
 
'; + $table = new Table; + $table->construct_header($lang->setting_groups); + + switch($db->type) + { + case "pgsql": + $query = $db->query(" + SELECT g.*, COUNT(s.sid) AS settingcount + FROM ".TABLE_PREFIX."settinggroups g + LEFT JOIN ".TABLE_PREFIX."settings s ON (s.gid=g.gid) + WHERE g.isdefault = 1 + GROUP BY ".$db->build_fields_string("settinggroups", "g.")." + ORDER BY g.disporder + "); + break; + default: + $query = $db->query(" + SELECT g.*, COUNT(s.sid) AS settingcount + FROM ".TABLE_PREFIX."settinggroups g + LEFT JOIN ".TABLE_PREFIX."settings s ON (s.gid=g.gid) + WHERE g.isdefault = 1 + GROUP BY g.gid + ORDER BY g.disporder + "); + } + while($group = $db->fetch_array($query)) + { + $group_lang_var = "setting_group_{$group['name']}"; + if(isset($lang->$group_lang_var)) + { + $group_title = htmlspecialchars_uni($lang->$group_lang_var); + } + else + { + $group_title = htmlspecialchars_uni($group['title']); + } + + $group_desc_lang_var = "setting_group_{$group['name']}_desc"; + if(isset($lang->$group_desc_lang_var)) + { + $group_desc = htmlspecialchars_uni($lang->$group_desc_lang_var); + } + else + { + $group_desc = htmlspecialchars_uni($group['description']); + } + + $table->construct_cell("{$group_title} ({$group['settingcount']} {$lang->bbsettings})
{$group_desc}"); + $table->construct_row(); + } + + $table->output("{$lang->show_all_settings}{$lang->board_settings}"); + + // Plugin Settings + switch($db->type) + { + case "pgsql": + $query = $db->query(" + SELECT g.*, COUNT(s.sid) AS settingcount + FROM ".TABLE_PREFIX."settinggroups g + LEFT JOIN ".TABLE_PREFIX."settings s ON (s.gid=g.gid) + WHERE g.isdefault <> 1 + GROUP BY ".$db->build_fields_string("settinggroups", "g.")." + ORDER BY g.disporder + "); + break; + default: + $query = $db->query(" + SELECT g.*, COUNT(s.sid) AS settingcount + FROM ".TABLE_PREFIX."settinggroups g + LEFT JOIN ".TABLE_PREFIX."settings s ON (s.gid=g.gid) + WHERE g.isdefault <> 1 + GROUP BY g.gid + ORDER BY g.disporder + "); + } + + if($db->num_rows($query)) + { + $table = new Table; + $table->construct_header($lang->setting_groups); + + while($group = $db->fetch_array($query)) + { + $group_lang_var = "setting_group_{$group['name']}"; + if($lang->$group_lang_var) + { + $group_title = htmlspecialchars_uni($lang->$group_lang_var); + } + else + { + $group_title = htmlspecialchars_uni($group['title']); + } + + $group_desc_lang_var = "setting_group_{$group['name']}_desc"; + if($lang->$group_desc_lang_var) + { + $group_desc = htmlspecialchars_uni($lang->$group_desc_lang_var); + } + else + { + $group_desc = htmlspecialchars_uni($group['description']); + } + + $table->construct_cell("{$group_title} ({$group['settingcount']} {$lang->bbsettings})
{$group_desc}"); + $table->construct_row(); + } + + $table->output($lang->plugin_settings); + } + + echo '
'; + + echo ' + +'; + + print_setting_peekers(); + $page->output_footer(); +} + +function print_setting_peekers() +{ + global $plugins; + + $peekers = array( + 'new Peeker($(".setting_boardclosed"), $("#row_setting_boardclosed_reason"), /1/, true)', + 'new Peeker($(".setting_gzipoutput"), $("#row_setting_gziplevel"), /1/, true)', + 'new Peeker($(".setting_useerrorhandling"), $("#row_setting_errorlogmedium"), /1/, true)', + 'new Peeker($(".setting_useerrorhandling"), $("#row_setting_errortypemedium"), /1/, true)', + 'new Peeker($(".setting_useerrorhandling"), $("#row_setting_errorloglocation"), /1/, true)', + 'new Peeker($("#setting_subforumsindex"), $("#row_setting_subforumsstatusicons"), /[^0+|]/, false)', + 'new Peeker($(".setting_showsimilarthreads"), $("#row_setting_similarityrating"), /1/, true)', + 'new Peeker($(".setting_showsimilarthreads"), $("#row_setting_similarlimit"), /1/, true)', + 'new Peeker($(".setting_disableregs"), $("#row_setting_regtype"), /0/, true)', + 'new Peeker($(".setting_hiddencaptchaimage"), $("#row_setting_hiddencaptchaimagefield"), /1/, true)', + 'new Peeker($("#setting_failedlogincount"), $("#row_setting_failedlogintime"), /[^0+|]/, false)', + 'new Peeker($("#setting_failedlogincount"), $("#row_setting_failedlogintext"), /[^0+|]/, false)', + 'new Peeker($(".setting_postfloodcheck"), $("#row_setting_postfloodsecs"), /1/, true)', + 'new Peeker($("#setting_postmergemins"), $("#row_setting_postmergefignore"), /[^0+|]/, false)', + 'new Peeker($("#setting_postmergemins"), $("#row_setting_postmergeuignore"), /[^0+|]/, false)', + 'new Peeker($("#setting_postmergemins"), $("#row_setting_postmergesep"), /[^0+|][\d*]/, false)', + 'new Peeker($(".setting_enablememberlist"), $("#row_setting_membersperpage"), /1/, true)', + 'new Peeker($(".setting_enablememberlist"), $("#row_setting_default_memberlist_sortby"), /1/, true)', + 'new Peeker($(".setting_enablememberlist"), $("#row_setting_default_memberlist_order"), /1/, true)', + 'new Peeker($(".setting_enablereputation"), $("#row_setting_repsperpage"), /1/, true)', + 'new Peeker($(".setting_enablewarningsystem"), $("#row_setting_allowcustomwarnings"), /1/, true)', + 'new Peeker($(".setting_enablewarningsystem"), $("#row_setting_canviewownwarning"), /1/, true)', + 'new Peeker($(".setting_enablewarningsystem"), $("#row_setting_maxwarningpoints"), /1/, true)', + 'new Peeker($(".setting_enablepms"), $("#row_setting_pmsallowhtml"), /1/, true)', + 'new Peeker($(".setting_enablepms"), $("#row_setting_pmsallowmycode"), /1/, true)', + 'new Peeker($(".setting_enablepms"), $("#row_setting_pmsallowsmilies"), /1/, true)', + 'new Peeker($(".setting_enablepms"), $("#row_setting_pmsallowimgcode"), /1/, true)', + 'new Peeker($(".setting_enablepms"), $("#row_setting_pmsallowvideocode"), /1/, true)', + 'new Peeker($(".setting_smilieinserter"), $("#row_setting_smilieinsertertot"), /1/, true)', + 'new Peeker($(".setting_smilieinserter"), $("#row_setting_smilieinsertercols"), /1/, true)', + 'new Peeker($("#setting_mail_handler"), $("#row_setting_smtp_host"), /smtp/, false)', + 'new Peeker($("#setting_mail_handler"), $("#row_setting_smtp_port"), /smtp/, false)', + 'new Peeker($("#setting_mail_handler"), $("#row_setting_smtp_user"), /smtp/, false)', + 'new Peeker($("#setting_mail_handler"), $("#row_setting_smtp_pass"), /smtp/, false)', + 'new Peeker($("#setting_mail_handler"), $("#row_setting_secure_smtp"), /smtp/, false)', + 'new Peeker($("#setting_mail_handler"), $("#row_setting_mail_parameters"), /mail/, false)', + 'new Peeker($("#setting_captchaimage"), $("#row_setting_captchapublickey"), 2, false)', + 'new Peeker($("#setting_captchaimage"), $("#row_setting_captchaprivatekey"), 2, false)', + 'new Peeker($("#setting_captchaimage"), $("#row_setting_ayahpublisherkey"), 3, false)', + 'new Peeker($("#setting_captchaimage"), $("#row_setting_ayahscoringkey"), 3, false)', + 'new Peeker($(".setting_contact"), $("#row_setting_contact_guests"), /1/, true)', + 'new Peeker($(".setting_contact"), $("#row_setting_contact_badwords"), /1/, true)', + 'new Peeker($(".setting_contact"), $("#row_setting_contact_maxsubjectlength"), /1/, true)', + 'new Peeker($(".setting_contact"), $("#row_setting_contact_minmessagelength"), /1/, true)', + 'new Peeker($(".setting_contact"), $("#row_setting_contact_maxmessagelength"), /1/, true)', + ); + + $peekers = $plugins->run_hooks("admin_settings_print_peekers", $peekers); + + $setting_peekers = implode("\n ", $peekers); + + echo ' + '; +} \ No newline at end of file diff --git a/Upload/admin/modules/config/smilies.php b/Upload/admin/modules/config/smilies.php new file mode 100644 index 0000000..fe2fba7 --- /dev/null +++ b/Upload/admin/modules/config/smilies.php @@ -0,0 +1,757 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->smilies, "index.php?module=config-smilies"); + +$plugins->run_hooks("admin_config_smilies_begin"); + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_config_smilies_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_name; + } + + if(!trim($mybb->input['find'])) + { + $errors[] = $lang->error_missing_text_replacement; + } + + if(!trim($mybb->input['image'])) + { + $errors[] = $lang->error_missing_path; + } + + if(!trim($mybb->input['disporder'])) + { + $errors[] = $lang->error_missing_order; + } + else + { + $mybb->input['disporder'] = $mybb->get_input('disporder', 1); + $query = $db->simple_select('smilies', 'sid', 'disporder=\''.$mybb->input['disporder'].'\''); + $duplicate_disporder = $db->fetch_field($query, 'sid'); + + if($duplicate_disporder) + { + $errors[] = $lang->error_duplicate_order; + } + } + + if(!$errors) + { + $mybb->input['find'] = str_replace("\r\n", "\n", $mybb->input['find']); + $mybb->input['find'] = str_replace("\r", "\n", $mybb->input['find']); + $mybb->input['find'] = explode("\n", $mybb->input['find']); + foreach(array_merge(array_keys($mybb->input['find'], ""), array_keys($mybb->input['find'], " ")) as $key) + { + unset($mybb->input['find'][$key]); + } + $mybb->input['find'] = implode("\n", $mybb->input['find']); + + $new_smilie = array( + "name" => $db->escape_string($mybb->input['name']), + "find" => $db->escape_string($mybb->input['find']), + "image" => $db->escape_string($mybb->input['image']), + "disporder" => (int)$mybb->input['disporder'], + "showclickable" => $db->escape_string($mybb->input['showclickable']) + ); + + $sid = $db->insert_query("smilies", $new_smilie); + + $plugins->run_hooks("admin_config_smilies_add_commit"); + + $cache->update_smilies(); + + // Log admin action + log_admin_action($sid, $mybb->input['name']); + + flash_message($lang->success_smilie_added, 'success'); + admin_redirect("index.php?module=config-smilies"); + } + } + + $page->add_breadcrumb_item($lang->add_smilie); + $page->output_header($lang->smilies." - ".$lang->add_smilie); + + $sub_tabs['manage_smilies'] = array( + 'title' => $lang->manage_smilies, + 'link' => "index.php?module=config-smilies", + ); + $sub_tabs['add_smilie'] = array( + 'title' => $lang->add_smilie, + 'link' => "index.php?module=config-smilies&action=add", + 'description' => $lang->add_smilie_desc + ); + $sub_tabs['add_multiple_smilies'] = array( + 'title' => $lang->add_multiple_smilies, + 'link' => "index.php?module=config-smilies&action=add_multiple", + ); + $sub_tabs['mass_edit'] = array( + 'title' => $lang->mass_edit, + 'link' => "index.php?module=config-smilies&action=mass_edit" + ); + + $page->output_nav_tabs($sub_tabs, 'add_smilie'); + $form = new Form("index.php?module=config-smilies&action=add", "post", "add"); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['image'] = 'images/smilies/'; + $mybb->input['showclickable'] = 1; + } + + if(!$mybb->input['disporder']) + { + $query = $db->simple_select("smilies", "max(disporder) as dispordermax"); + $mybb->input['disporder'] = $db->fetch_field($query, "dispordermax")+1; + } + + $form_container = new FormContainer($lang->add_smilie); + $form_container->output_row($lang->name." *", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->text_replace." *", $lang->text_replace_desc, $form->generate_text_area('find', $mybb->input['find'], array('id' => 'find')), 'find'); + $form_container->output_row($lang->image_path." *", $lang->image_path_desc, $form->generate_text_box('image', $mybb->input['image'], array('id' => 'image')), 'image'); + $form_container->output_row($lang->display_order." *", $lang->display_order_desc, $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder')), 'disporder'); + $form_container->output_row($lang->show_clickable." *", $lang->show_clickable_desc, $form->generate_yes_no_radio('showclickable', $mybb->input['showclickable'])); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_smilie); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("smilies", "*", "sid='".$mybb->get_input('sid', 1)."'"); + $smilie = $db->fetch_array($query); + + // Does the smilie not exist? + if(!$smilie['sid']) + { + flash_message($lang->error_invalid_smilie, 'error'); + admin_redirect("index.php?module=config-smilies"); + } + + $plugins->run_hooks("admin_config_smilies_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_name; + } + + if(!trim($mybb->input['find'])) + { + $errors[] = $lang->error_missing_text_replacement; + } + + if(!trim($mybb->input['image'])) + { + $errors[] = $lang->error_missing_path; + } + + if(!trim($mybb->input['disporder'])) + { + $errors[] = $lang->error_missing_order; + } + else + { + $mybb->input['disporder'] = $mybb->get_input('disporder', 1); + $query = $db->simple_select("smilies", "sid", "disporder= '".$mybb->input['disporder']."' AND sid != '".$mybb->input['sid']."'"); + $duplicate_disporder = $db->fetch_field($query, 'sid'); + + if($duplicate_disporder) + { + $errors[] = $lang->error_duplicate_order; + } + } + + if(!$errors) + { + $mybb->input['find'] = str_replace("\r\n", "\n", $mybb->input['find']); + $mybb->input['find'] = str_replace("\r", "\n", $mybb->input['find']); + $mybb->input['find'] = explode("\n", $mybb->input['find']); + foreach(array_merge(array_keys($mybb->input['find'], ""), array_keys($mybb->input['find'], " ")) as $key) + { + unset($mybb->input['find'][$key]); + } + $mybb->input['find'] = implode("\n", $mybb->input['find']); + + $updated_smilie = array( + "name" => $db->escape_string($mybb->input['name']), + "find" => $db->escape_string($mybb->input['find']), + "image" => $db->escape_string($mybb->input['image']), + "disporder" => (int)$mybb->input['disporder'], + "showclickable" => $db->escape_string($mybb->input['showclickable']) + ); + + $plugins->run_hooks("admin_config_smilies_edit_commit"); + + $db->update_query("smilies", $updated_smilie, "sid = '".$mybb->get_input('sid', 1)."'"); + + $cache->update_smilies(); + + // Log admin action + log_admin_action($smilie['sid'], $mybb->input['name']); + + flash_message($lang->success_smilie_updated, 'success'); + admin_redirect("index.php?module=config-smilies"); + } + } + + $page->add_breadcrumb_item($lang->edit_smilie); + $page->output_header($lang->smilies." - ".$lang->edit_smilie); + + $sub_tabs['edit_smilie'] = array( + 'title' => $lang->edit_smilie, + 'link' => "index.php?module=config-smilies&action=edit", + 'description' => $lang->edit_smilie_desc + ); + $sub_tabs['mass_edit'] = array( + 'title' => $lang->mass_edit, + 'link' => "index.php?module=config-smilies&action=mass_edit", + ); + + $page->output_nav_tabs($sub_tabs, 'edit_smilie'); + $form = new Form("index.php?module=config-smilies&action=edit", "post", "edit"); + + echo $form->generate_hidden_field("sid", $smilie['sid']); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input = array_merge($mybb->input, $smilie); + } + + $form_container = new FormContainer($lang->edit_smilie); + $form_container->output_row($lang->name." *", "", $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->text_replace." *", $lang->text_replace_desc, $form->generate_text_area('find', $mybb->input['find'], array('id' => 'find')), 'find'); + $form_container->output_row($lang->image_path." *", $lang->image_path_desc, $form->generate_text_box('image', $mybb->input['image'], array('id' => 'image')), 'image'); + $form_container->output_row($lang->display_order." *", $lang->display_order_desc, $form->generate_numeric_field('disporder', $mybb->input['disporder'], array('id' => 'disporder')), 'disporder'); + $form_container->output_row($lang->show_clickable." *", $lang->show_clickable_desc, $form->generate_yes_no_radio('showclickable', $mybb->input['showclickable'])); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_smilie); + $buttons[] = $form->generate_reset_button($lang->reset); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("smilies", "*", "sid='".$mybb->get_input('sid', 1)."'"); + $smilie = $db->fetch_array($query); + + // Does the smilie not exist? + if(!$smilie['sid']) + { + flash_message($lang->error_invalid_smilie, 'error'); + admin_redirect("index.php?module=config-smilies"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-smilies"); + } + + $plugins->run_hooks("admin_config_smilies_delete"); + + if($mybb->request_method == "post") + { + // Delete the smilie + $db->delete_query("smilies", "sid='{$smilie['sid']}'"); + + $plugins->run_hooks("admin_config_smilies_delete_commit"); + + $cache->update_smilies(); + + // Log admin action + log_admin_action($smilie['sid'], $smilie['name']); + + flash_message($lang->success_smilie_updated, 'success'); + admin_redirect("index.php?module=config-smilies"); + } + else + { + $page->output_confirm_action("index.php?module=config-smilies&action=delete&sid={$smilie['sid']}", $lang->confirm_smilie_deletion); + }} + +if($mybb->input['action'] == "add_multiple") +{ + $plugins->run_hooks("admin_config_smilies_add_multiple"); + + if($mybb->request_method == "post") + { + if($mybb->input['step'] == 1) + { + $plugins->run_hooks("admin_config_smilies_add_multiple_step1"); + + if(!trim($mybb->input['pathfolder'])) + { + $errors[] = $lang->error_missing_path_multiple; + } + + $path = $mybb->input['pathfolder']; + $dir = @opendir(MYBB_ROOT.$path); + + if(!$dir) + { + $errors[] = $lang->error_invalid_path; + } + + if($path && !is_array($errors)) + { + if(substr($path, -1, 1) !== "/") + { + $path .= "/"; + } + + $query = $db->simple_select("smilies"); + + $asmilies = array(); + while($smilie = $db->fetch_array($query)) + { + $asmilies[$smilie['image']] = 1; + } + + $smilies = array(); + while($file = readdir($dir)) + { + if($file != ".." && $file != ".") + { + $ext = get_extension($file); + if($ext == "gif" || $ext == "jpg" || $ext == "jpeg" || $ext == "png" || $ext == "bmp") + { + if(!$asmilies[$path.$file]) + { + $smilies[] = $file; + } + } + } + } + closedir($dir); + + if(count($smilies) == 0) + { + $errors[] = $lang->error_no_smilies; + } + } + + if(!$errors) + { + $page->add_breadcrumb_item($lang->add_multiple_smilies); + $page->output_header($lang->smilies." - ".$lang->add_multiple_smilies); + + $sub_tabs['manage_smilies'] = array( + 'title' => $lang->manage_smilies, + 'link' => "index.php?module=config-smilies", + ); + $sub_tabs['add_smilie'] = array( + 'title' => $lang->add_smilie, + 'link' => "index.php?module=config-smilies&action=add" + ); + $sub_tabs['add_multiple_smilies'] = array( + 'title' => $lang->add_multiple_smilies, + 'link' => "index.php?module=config-smilies&action=add_multiple", + 'description' => $lang->add_multiple_smilies_desc + ); + $sub_tabs['mass_edit'] = array( + 'title' => $lang->mass_edit, + 'link' => "index.php?module=config-smilies&action=mass_edit" + ); + + $page->output_nav_tabs($sub_tabs, 'add_multiple_smilies'); + $form = new Form("index.php?module=config-smilies&action=add_multiple", "post", "add_multiple"); + echo $form->generate_hidden_field("step", "2"); + echo $form->generate_hidden_field("pathfolder", $path); + + $form_container = new FormContainer($lang->add_multiple_smilies); + $form_container->output_row_header($lang->image, array("class" => "align_center", 'width' => '10%')); + $form_container->output_row_header($lang->name); + $form_container->output_row_header($lang->text_replace, array('width' => '20%')); + $form_container->output_row_header($lang->include, array("class" => "align_center", 'width' => '5%')); + + foreach($smilies as $key => $file) + { + $ext = get_extension($file); + $find = str_replace(".".$ext, "", $file); + $name = ucfirst($find); + + $form_container->output_cell("\"\"
{$file}", array("class" => "align_center", "width" => 1)); + $form_container->output_cell($form->generate_text_box("name[{$file}]", $name, array('id' => 'name', 'style' => 'width: 98%'))); + $form_container->output_cell($form->generate_text_box("find[{$file}]", ":".$find.":", array('id' => 'find', 'style' => 'width: 95%'))); + $form_container->output_cell($form->generate_check_box("include[{$file}]", 1, "", array('checked' => 1)), array("class" => "align_center")); + $form_container->construct_row(); + } + + if($form_container->num_rows() == 0) + { + flash_message($lang->error_no_images, 'error'); + admin_redirect("index.php?module=config-smilies&action=add_multiple"); + } + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_smilies); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); + exit; + } + } + else + { + $plugins->run_hooks("admin_config_smilies_add_multiple_step2"); + + $path = $mybb->input['pathfolder']; + reset($mybb->input['include']); + $find = $mybb->input['find']; + $name = $mybb->input['name']; + + if(empty($mybb->input['include'])) + { + flash_message($lang->error_none_included, 'error'); + admin_redirect("index.php?module=config-smilies&action=add_multiple"); + } + + $query = $db->simple_select('smilies', 'MAX(disporder) as max_disporder'); + $disporder = $db->fetch_field($query, 'max_disporder'); + + foreach($mybb->input['include'] as $image => $insert) + { + $find[$image] = str_replace("\r\n", "\n", $find[$image]); + $find[$image] = str_replace("\r", "\n", $find[$image]); + $find[$image] = explode("\n", $find[$image]); + foreach(array_merge(array_keys($find[$image], ""), array_keys($find[$image], " ")) as $key) + { + unset($find[$image][$key]); + } + $find[$image] = implode("\n", $find[$image]); + + if($insert) + { + $new_smilie = array( + "name" => $db->escape_string($name[$image]), + "find" => $db->escape_string($find[$image]), + "image" => $db->escape_string($path.$image), + "disporder" => ++$disporder, + "showclickable" => 1 + ); + + $db->insert_query("smilies", $new_smilie); + } + } + + $plugins->run_hooks("admin_config_smilies_add_multiple_commit"); + + $cache->update_smilies(); + + // Log admin action + log_admin_action(); + + flash_message($lang->success_multiple_smilies_added, 'success'); + admin_redirect("index.php?module=config-smilies"); + } + } + + $page->add_breadcrumb_item($lang->add_multiple_smilies); + $page->output_header($lang->smilies." - ".$lang->add_multiple_smilies); + + $sub_tabs['manage_smilies'] = array( + 'title' => $lang->manage_smilies, + 'link' => "index.php?module=config-smilies", + ); + $sub_tabs['add_smilie'] = array( + 'title' => $lang->add_smilie, + 'link' => "index.php?module=config-smilies&action=add" + ); + $sub_tabs['add_multiple_smilies'] = array( + 'title' => $lang->add_multiple_smilies, + 'link' => "index.php?module=config-smilies&action=add_multiple", + 'description' => $lang->add_multiple_smilies_desc + ); + $sub_tabs['mass_edit'] = array( + 'title' => $lang->mass_edit, + 'link' => "index.php?module=config-smilies&action=mass_edit" + ); + + $page->output_nav_tabs($sub_tabs, 'add_multiple_smilies'); + $form = new Form("index.php?module=config-smilies&action=add_multiple", "post", "add_multiple"); + echo $form->generate_hidden_field("step", "1"); + + if($errors) + { + $page->output_inline_error($errors); + } + + $form_container = new FormContainer($lang->add_multiple_smilies); + $form_container->output_row($lang->path_to_images, $lang->path_to_images_desc, $form->generate_text_box('pathfolder', $mybb->input['pathfolder'], array('id' => 'pathfolder')), 'pathfolder'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->show_smilies); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "mass_edit") +{ + $plugins->run_hooks("admin_config_smilies_mass_edit"); + + if($mybb->request_method == "post") + { + foreach($mybb->input['name'] as $sid => $name) + { + $disporder = (int)$mybb->input['disporder'][$sid]; + + $sid = (int)$sid; + if($mybb->input['delete'][$sid] == 1) + { + // Dirty hack to get the disporder working. Note: this doesn't work in every case + unset($mybb->input['disporder'][$sid]); + + $db->delete_query("smilies", "sid = '{$sid}'", 1); + } + else + { + $smilie = array( + "name" => $db->escape_string($mybb->input['name'][$sid]), + "find" => $db->escape_string($mybb->input['find'][$sid]), + "showclickable" => $db->escape_string($mybb->input['showclickable'][$sid]) + ); + + // $test contains all disporders except the actual one so we can check whether we have multiple disporders + $test = $mybb->input['disporder']; + unset($test[$sid]); + if(!in_array($disporder, $test)) + { + $smilie['disporder'] = $disporder; + } + + $db->update_query("smilies", $smilie, "sid = '{$sid}'"); + } + + $disporder_list[$disporder] = $disporder; + } + + $plugins->run_hooks("admin_config_smilies_mass_edit_commit"); + + $cache->update_smilies(); + + // Log admin action + log_admin_action(); + + flash_message($lang->success_multiple_smilies_updated, 'success'); + admin_redirect("index.php?module=config-smilies"); + } + + $page->add_breadcrumb_item($lang->mass_edit); + $page->output_header($lang->smilies." - ".$lang->mass_edit); + + $sub_tabs['manage_smilies'] = array( + 'title' => $lang->manage_smilies, + 'link' => "index.php?module=config-smilies", + ); + $sub_tabs['add_smilie'] = array( + 'title' => $lang->add_smilie, + 'link' => "index.php?module=config-smilies&action=add", + ); + $sub_tabs['add_multiple_smilies'] = array( + 'title' => $lang->add_multiple_smilies, + 'link' => "index.php?module=config-smilies&action=add_multiple", + ); + $sub_tabs['mass_edit'] = array( + 'title' => $lang->mass_edit, + 'link' => "index.php?module=config-smilies&action=mass_edit", + 'description' => $lang->mass_edit_desc + ); + + $page->output_nav_tabs($sub_tabs, 'mass_edit'); + + $form = new Form("index.php?module=config-smilies&action=mass_edit", "post", "mass_edit"); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['path'] = 'images/smilies/'; + $mybb->input['showclickable'] = 1; + } + + if(!$mybb->input['disporder']) + { + $query = $db->simple_select("smilies", "max(disporder) as dispordermax"); + $mybb->input['disporder'] = $db->fetch_field($query, "dispordermax")+1; + } + + $form_container = new FormContainer($lang->manage_smilies); + $form_container->output_row_header($lang->image, array("class" => "align_center", 'width' => '1')); + $form_container->output_row_header($lang->name); + $form_container->output_row_header($lang->text_replace, array('width' => '20%')); + $form_container->output_row_header($lang->order, array('width' => '5%')); + $form_container->output_row_header($lang->mass_edit_show_clickable, array("width" => 165)); + $form_container->output_row_header($lang->smilie_delete, array("class" => "align_center", 'width' => '5%')); + + $query = $db->simple_select("smilies", "*", "", array('order_by' => 'disporder')); + while($smilie = $db->fetch_array($query)) + { + $smilie['image'] = str_replace("{theme}", "images", $smilie['image']); + if(my_strpos($smilie['image'], "p://") || substr($smilie['image'], 0, 1) == "/") + { + $image = $smilie['image']; + } + else + { + $image = "../".$smilie['image']; + } + + $smilie['find'] = implode(', ', explode("\n", $smilie['find'])); + + $form_container->output_cell("\"\"", array("class" => "align_center", "width" => 1)); + $form_container->output_cell($form->generate_text_box("name[{$smilie['sid']}]", $smilie['name'], array('id' => 'name', 'style' => 'width: 98%'))); + $form_container->output_cell($form->generate_text_area("find[{$smilie['sid']}]", $smilie['find'], array('id' => 'find', 'style' => 'width: 95%'))); + $form_container->output_cell($form->generate_numeric_field("disporder[{$smilie['sid']}]", $smilie['disporder'], array('id' => 'disporder', 'style' => 'width: 80%'))); + $form_container->output_cell($form->generate_yes_no_radio("showclickable[{$smilie['sid']}]", $smilie['showclickable']), array("class" => "align_center")); + $form_container->output_cell($form->generate_check_box("delete[{$smilie['sid']}]", 1, $mybb->input['delete']), array("class" => "align_center")); + $form_container->construct_row(); + } + + if($form_container->num_rows() == 0) + { + $form_container->output_cell($lang->no_smilies, array('colspan' => 6)); + $form_container->construct_row(); + } + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_smilies); + $buttons[] = $form->generate_reset_button($lang->reset); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_config_smilies_start"); + + $page->output_header($lang->manage_smilies); + + $sub_tabs['manage_smilies'] = array( + 'title' => $lang->manage_smilies, + 'link' => "index.php?module=config-smilies", + 'description' => $lang->manage_smilies_desc + ); + $sub_tabs['add_smilie'] = array( + 'title' => $lang->add_smilie, + 'link' => "index.php?module=config-smilies&action=add", + ); + $sub_tabs['add_multiple_smilies'] = array( + 'title' => $lang->add_multiple_smilies, + 'link' => "index.php?module=config-smilies&action=add_multiple", + ); + $sub_tabs['mass_edit'] = array( + 'title' => $lang->mass_edit, + 'link' => "index.php?module=config-smilies&action=mass_edit", + ); + + $page->output_nav_tabs($sub_tabs, 'manage_smilies'); + + $pagenum = $mybb->get_input('page', 1); + if($pagenum) + { + $start = ($pagenum-1) * 20; + } + else + { + $start = 0; + $pagenum = 1; + } + + + $table = new Table; + $table->construct_header($lang->image, array("class" => "align_center", "width" => 1)); + $table->construct_header($lang->name, array("width" => "35%")); + $table->construct_header($lang->text_replace, array("width" => "35%")); + $table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 2)); + + $query = $db->simple_select("smilies", "*", "", array('limit_start' => $start, 'limit' => 20, 'order_by' => 'disporder')); + while($smilie = $db->fetch_array($query)) + { + $smilie['image'] = str_replace("{theme}", "images", $smilie['image']); + if(my_strpos($smilie['image'], "p://") || substr($smilie['image'], 0, 1) == "/") + { + $image = $smilie['image']; + $smilie['image'] = str_replace("{theme}", "images", $smilie['image']); + } + else + { + $image = "../".$smilie['image']; + } + + $smilie['find'] = str_replace("\n", ", ", $smilie['find']); + + $table->construct_cell("\"\"", array("class" => "align_center")); + $table->construct_cell(htmlspecialchars_uni($smilie['name'])); + $table->construct_cell(htmlspecialchars_uni($smilie['find'])); + + $table->construct_cell("{$lang->edit}", array("class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_smilie_deletion}')\">{$lang->delete}", array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_smilies, array('colspan' => 5)); + $table->construct_row(); + } + + $table->output($lang->manage_smilies); + + $query = $db->simple_select("smilies", "COUNT(sid) as smilies"); + $total_rows = $db->fetch_field($query, "smilies"); + + echo "
".draw_admin_pagination($pagenum, "20", $total_rows, "index.php?module=config-smilies&page={page}"); + + $page->output_footer(); +} \ No newline at end of file diff --git a/Upload/admin/modules/config/spiders.php b/Upload/admin/modules/config/spiders.php new file mode 100644 index 0000000..10b963e --- /dev/null +++ b/Upload/admin/modules/config/spiders.php @@ -0,0 +1,307 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->spiders_bots, "index.php?module=config-spiders"); + +$plugins->run_hooks("admin_config_spiders_begin"); + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_config_spiders_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_name; + } + + if(!trim($mybb->input['useragent'])) + { + $errors[] = $lang->error_missing_agent; + } + + if(!$errors) + { + $new_spider = array( + "name" => $db->escape_string($mybb->input['name']), + "theme" => (int)$mybb->input['theme'], + "language" => $db->escape_string($mybb->input['language']), + "usergroup" => (int)$mybb->input['usergroup'], + "useragent" => $db->escape_string($mybb->input['useragent']), + "lastvisit" => 0 + ); + $sid = $db->insert_query("spiders", $new_spider); + + $plugins->run_hooks("admin_config_spiders_add_commit"); + + $cache->update_spiders(); + + // Log admin action + log_admin_action($sid, $mybb->input['name']); + + flash_message($lang->success_bot_created, 'success'); + admin_redirect("index.php?module=config-spiders"); + } + } + + $page->add_breadcrumb_item($lang->add_new_bot); + $page->output_header($lang->spiders_bots." - ".$lang->add_new_bot); + + $sub_tabs['spiders'] = array( + 'title' => $lang->spiders_bots, + 'link' => "index.php?module=config-spiders", + ); + $sub_tabs['add_spider'] = array( + 'title' => $lang->add_new_bot, + 'link' => "index.php?module=config-spiders&action=add", + 'description' => $lang->add_new_bot_desc + ); + + $page->output_nav_tabs($sub_tabs, "add_spider"); + + $form = new Form("index.php?module=config-spiders&action=add", "post"); + + if($errors) + { + $page->output_inline_error($errors); + } + + $form_container = new FormContainer($lang->add_new_bot); + $form_container->output_row($lang->name." *", $lang->name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->user_agent." *", $lang->user_agent_desc, $form->generate_text_box('useragent', $mybb->input['useragent'], array('id' => 'useragent')), 'useragent'); + + $languages = array('' => $lang->use_board_default); + $languages = array_merge($languages, $lang->get_languages()); + $form_container->output_row($lang->language_str, $lang->language_desc, $form->generate_select_box("language", $languages, $mybb->input['language'], array("id" => "language")), 'language'); + + $form_container->output_row($lang->theme, $lang->theme_desc, build_theme_select("theme", $mybb->input['theme'], 0, "", true, false, true)); + + $query = $db->simple_select("usergroups", "*", "", array("order_by" => "title", "order_dir" => "asc")); + + $usergroups = array(); + while($usergroup = $db->fetch_array($query)) + { + $usergroups[$usergroup['gid']] = $usergroup['title']; + } + if(!$mybb->input['usergroup']) + { + $mybb->input['usergroup'] = 1; + } + $form_container->output_row($lang->user_group, $lang->user_group_desc, $form->generate_select_box("usergroup", $usergroups, $mybb->input['usergroup'], array("id" => "usergroup")), 'usergroup'); + + + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->save_bot); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("spiders", "*", "sid='".$mybb->get_input('sid', 1)."'"); + $spider = $db->fetch_array($query); + + // Does the spider not exist? + if(!$spider['sid']) + { + flash_message($lang->error_invalid_bot, 'error'); + admin_redirect("index.php?module=config-spiders"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-spiders"); + } + + $plugins->run_hooks("admin_config_spiders_delete"); + + if($mybb->request_method == "post") + { + // Delete the spider + $db->delete_query("spiders", "sid='{$spider['sid']}'"); + + $plugins->run_hooks("admin_config_spiders_delete_commit"); + + $cache->update_spiders(); + + // Log admin action + log_admin_action($spider['sid'], $spider['name']); + + flash_message($lang->success_bot_deleted, 'success'); + admin_redirect("index.php?module=config-spiders"); + } + else + { + $page->output_confirm_action("index.php?module=config-spiders&action=delete&sid={$spider['sid']}", $lang->confirm_bot_deletion); + } +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("spiders", "*", "sid='".$mybb->get_input('sid', 1)."'"); + $spider = $db->fetch_array($query); + + // Does the spider not exist? + if(!$spider['sid']) + { + flash_message($lang->error_invalid_bot, 'error'); + admin_redirect("index.php?module=config-spiders"); + } + + $plugins->run_hooks("admin_config_spiders_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['name'])) + { + $errors[] = $lang->error_missing_name; + } + + if(!trim($mybb->input['useragent'])) + { + $errors[] = $lang->error_missing_agent; + } + + if(!$errors) + { + $updated_spider = array( + "name" => $db->escape_string($mybb->input['name']), + "theme" => (int)$mybb->input['theme'], + "language" => $db->escape_string($mybb->input['language']), + "usergroup" => (int)$mybb->input['usergroup'], + "useragent" => $db->escape_string($mybb->input['useragent']) + ); + + $plugins->run_hooks("admin_config_spiders_edit_commit"); + + $db->update_query("spiders", $updated_spider, "sid='{$spider['sid']}'"); + + $cache->update_spiders(); + + // Log admin action + log_admin_action($spider['sid'], $mybb->input['name']); + + flash_message($lang->success_bot_updated, 'success'); + admin_redirect("index.php?module=config-spiders"); + } + } + + $page->add_breadcrumb_item($lang->edit_bot); + $page->output_header($lang->spiders_bots." - ".$lang->edit_bot); + + $sub_tabs['edit_spider'] = array( + 'title' => $lang->edit_bot, + 'link' => "index.php?module=config-spiders&action=edit&sid={$spider['sid']}", + 'description' => $lang->edit_bot_desc + ); + + $page->output_nav_tabs($sub_tabs, "edit_spider"); + + $form = new Form("index.php?module=config-spiders&action=edit&sid={$spider['sid']}", "post"); + + if($errors) + { + $page->output_inline_error($errors); + $spider_data = $mybb->input; + } + else + { + $spider_data = $spider; + } + + $form_container = new FormContainer($lang->edit_bot); + $form_container->output_row($lang->name." *", $lang->name_desc, $form->generate_text_box('name', $spider_data['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->user_agent." *", $lang->user_agent_desc, $form->generate_text_box('useragent', $spider_data['useragent'], array('id' => 'useragent')), 'useragent'); + + $languages = array('' => $lang->use_board_default); + $languages = array_merge($languages, $lang->get_languages()); + $form_container->output_row($lang->language_str, $lang->language_desc, $form->generate_select_box("language", $languages, $spider_data['language'], array("id" => "language")), 'language'); + + $form_container->output_row($lang->theme, $lang->theme_desc, build_theme_select("theme", $spider_data['theme'], 0, "", true, false, true)); + + $query = $db->simple_select("usergroups", "*", "", array("order_by" => "title", "order_dir" => "asc")); + while($usergroup = $db->fetch_array($query)) + { + $usergroups[$usergroup['gid']] = $usergroup['title']; + } + if(!$spider_data['usergroup']) + { + $spider_data['usergroup'] = 1; + } + $form_container->output_row($lang->user_group, $lang->user_group_desc, $form->generate_select_box("usergroup", $usergroups, $spider_data['usergroup'], array("id" => "usergroup")), 'usergroup'); + + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->save_bot); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_config_spiders_start"); + + $page->output_header($lang->spiders_bots); + + $sub_tabs['spiders'] = array( + 'title' => $lang->spiders_bots, + 'link' => "index.php?module=config-spiders", + 'description' => $lang->spiders_bots_desc + ); + $sub_tabs['add_spider'] = array( + 'title' => $lang->add_new_bot, + 'link' => "index.php?module=config-spiders&action=add" + ); + + $page->output_nav_tabs($sub_tabs, "spiders"); + + $table = new Table; + $table->construct_header($lang->bot); + $table->construct_header($lang->last_visit, array("class" => "align_center", "width" => 200)); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 150, "colspan" => 2)); + + $query = $db->simple_select("spiders", "*", "", array("order_by" => "lastvisit", "order_dir" => "desc")); + while($spider = $db->fetch_array($query)) + { + $lastvisit = $lang->never; + $spider['name'] = htmlspecialchars_uni($spider['name']); + + if($spider['lastvisit']) + { + $lastvisit = my_date('relative', $spider['lastvisit']); + } + + $table->construct_cell("{$spider['name']}"); + $table->construct_cell($lastvisit, array("class" => "align_center", "width" => 200)); + $table->construct_cell("{$lang->edit}", array("class" => "align_center", "width" => 75)); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_bot_deletion}');\">{$lang->delete}", array("class" => "align_center", "width" => 75)); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_bots, array("colspan" => 4)); + $table->construct_row(); + } + + $table->output($lang->spiders_bots); + $page->output_footer(); +} diff --git a/Upload/admin/modules/config/thread_prefixes.php b/Upload/admin/modules/config/thread_prefixes.php new file mode 100644 index 0000000..9a6449f --- /dev/null +++ b/Upload/admin/modules/config/thread_prefixes.php @@ -0,0 +1,536 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->thread_prefixes, 'index.php?module=config-thread_prefixes'); + +$sub_tabs = array( + "thread_prefixes" => array( + 'title' => $lang->thread_prefixes, + 'link' => 'index.php?module=config-thread_prefixes', + 'description' => $lang->thread_prefixes_desc + ), + "add_prefix" => array( + 'title'=> $lang->add_new_thread_prefix, + 'link' => 'index.php?module=config-thread_prefixes&action=add_prefix', + 'description' => $lang->add_new_thread_prefix_desc + ) +); + +$plugins->run_hooks('admin_config_thread_prefixes_begin'); + +if($mybb->input['action'] == 'add_prefix') +{ + $plugins->run_hooks('admin_config_thread_prefixes_add_prefix'); + + if($mybb->request_method == 'post') + { + if(trim($mybb->input['prefix']) == '') + { + $errors[] = $lang->error_missing_prefix; + } + + if(trim($mybb->input['displaystyle']) == '') + { + $errors[] = $lang->error_missing_display_style; + } + + if($mybb->input['forum_type'] == 2) + { + if(count($mybb->input['forum_1_forums']) < 1) + { + $errors[] = $lang->error_no_forums_selected; + } + + $forum_checked[2] = "checked=\"checked\""; + } + else + { + $forum_checked[1] = "checked=\"checked\""; + $mybb->input['forum_1_forums'] = ''; + } + + if($mybb->input['group_type'] == 2) + { + if(count($mybb->input['group_1_groups']) < 1) + { + $errors[] = $lang->error_no_groups_selected; + } + + $group_checked[2] = "checked=\"checked\""; + } + else + { + $group_checked[1] = "checked=\"checked\""; + $mybb->input['group_1_forums'] = ''; + } + + if(!$errors) + { + $new_prefix = array( + 'prefix' => $db->escape_string($mybb->input['prefix']), + 'displaystyle' => $db->escape_string($mybb->input['displaystyle']) + ); + + if($mybb->input['forum_type'] == 2) + { + if(is_array($mybb->input['forum_1_forums'])) + { + $checked = array(); + foreach($mybb->input['forum_1_forums'] as $fid) + { + $checked[] = (int)$fid; + } + + $new_prefix['forums'] = implode(',', $checked); + } + } + else + { + $new_prefix['forums'] = '-1'; + } + + if($mybb->input['group_type'] == 2) + { + if(is_array($mybb->input['group_1_groups'])) + { + $checked = array(); + foreach($mybb->input['group_1_groups'] as $gid) + { + $checked[] = (int)$gid; + } + + $new_prefix['groups'] = implode(',', $checked); + } + } + else + { + $new_prefix['groups'] = '-1'; + } + + $pid = $db->insert_query('threadprefixes', $new_prefix); + + $plugins->run_hooks('admin_config_thread_prefixes_add_prefix_commit'); + + // Log admin action + log_admin_action($pid, $mybb->input['prefix']); + $cache->update_threadprefixes(); + + flash_message($lang->success_thread_prefix_created, 'success'); + admin_redirect('index.php?module=config-thread_prefixes'); + } + } + + $page->add_breadcrumb_item($lang->add_new_thread_prefix); + $page->output_header($lang->thread_prefixes." - ".$lang->add_new_thread_prefix); + $page->output_nav_tabs($sub_tabs, 'add_prefix'); + + $form = new Form('index.php?module=config-thread_prefixes&action=add_prefix', 'post'); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['prefix'] = ''; + $mybb->input['displaystyle'] = ''; + $mybb->input['forum_1_forums'] = ''; + $forum_checked[1] = "checked=\"checked\""; + $forum_checked[2] = ''; + $mybb->input['group_1_groups'] = ''; + $group_checked[1] = "checked=\"checked\""; + $group_checked[2] = ''; + } + + $form_container = new FormContainer($lang->prefix_options); + $form_container->output_row($lang->prefix.' *', $lang->prefix_desc, $form->generate_text_box('prefix', $mybb->input['prefix'], array('id' => 'prefix')), 'prefix'); + $form_container->output_row($lang->display_style.' *', $lang->display_style_desc, $form->generate_text_box('displaystyle', $mybb->input['displaystyle'], array('id' => 'displaystyle')), 'displaystyle'); + + $actions = " +
+
+
+
+ + + + + +
{$lang->forums_colon}".$form->generate_forum_select('forum_1_forums[]', $mybb->input['forum_1_forums'], array('multiple' => true, 'size' => 5))."
+
+
+ "; + $form_container->output_row($lang->available_in_forums.' *', '', $actions); + + $group_select = " +
+
+
+
+ + + + + +
{$lang->groups_colon}".$form->generate_group_select('group_1_groups[]', $mybb->input['group_1_groups'], array('multiple' => true, 'size' => 5))."
+
+
+ "; + $form_container->output_row($lang->available_to_groups." *", '', $group_select); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_thread_prefix); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == 'edit_prefix') +{ + $prefix = build_prefixes($mybb->input['pid']); + if(empty($prefix['pid'])) + { + flash_message($lang->error_invalid_prefix, 'error'); + admin_redirect('index.php?module=config-thread_prefixes'); + } + + $plugins->run_hooks('admin_config_thread_prefixes_edit_prefix_start'); + + if($mybb->request_method == 'post') + { + if(trim($mybb->input['prefix']) == '') + { + $errors[] = $lang->error_missing_prefix; + } + + if(trim($mybb->input['displaystyle']) == '') + { + $errors[] = $lang->error_missing_display_style; + } + + if($mybb->input['forum_type'] == 2) + { + if(count($mybb->input['forum_1_forums']) < 1) + { + $errors[] = $lang->error_no_forums_selected; + } + + $forum_checked[2] = "checked=\"checked\""; + } + else + { + $forum_checked[1] = "checked=\"checked\""; + $mybb->input['forum_1_forums'] = ''; + } + + if($mybb->input['group_type'] == 2) + { + if(count($mybb->input['group_1_groups']) < 1) + { + $errors[] = $lang->error_no_groups_selected; + } + + $group_checked[2] = "checked=\"checked\""; + } + else + { + $group_checked[1] = "checked=\"checked\""; + $mybb->input['group_1_forums'] = ''; + } + + if(!$errors) + { + $update_prefix = array( + 'prefix' => $db->escape_string($mybb->input['prefix']), + 'displaystyle' => $db->escape_string($mybb->input['displaystyle']) + ); + + if($mybb->input['forum_type'] == 2) + { + if(is_array($mybb->input['forum_1_forums'])) + { + $checked = array(); + foreach($mybb->input['forum_1_forums'] as $fid) + { + $checked[] = (int)$fid; + } + + $update_prefix['forums'] = implode(',', $checked); + } + } + else + { + $update_prefix['forums'] = '-1'; + } + + if($mybb->input['group_type'] == 2) + { + if(is_array($mybb->input['group_1_groups'])) + { + $checked = array(); + foreach($mybb->input['group_1_groups'] as $gid) + { + $checked[] = (int)$gid; + } + + $update_prefix['groups'] = implode(',', $checked); + } + } + else + { + $update_prefix['groups'] = '-1'; + } + + $plugins->run_hooks('admin_config_thread_prefixes_edit_prefix_commit'); + + $db->update_query('threadprefixes', $update_prefix, "pid='{$mybb->input['pid']}'"); + + // Log admin action + log_admin_action($mybb->input['pid'], $mybb->input['prefix']); + $cache->update_threadprefixes(); + + flash_message($lang->success_thread_prefix_updated, 'success'); + admin_redirect('index.php?module=config-thread_prefixes'); + } + } + + $page->add_breadcrumb_item($lang->edit_thread_prefix); + $page->output_header($lang->thread_prefixes.' - '.$lang->edit_thread_prefix); + + // Setup the edit prefix tab + unset($sub_tabs); + $sub_tabs['edit_prefix'] = array( + "title" => $lang->edit_prefix, + "link" => "index.php?module=config-thread_prefixes", + "description" => $lang->edit_prefix_desc + ); + $page->output_nav_tabs($sub_tabs, "edit_prefix"); + + $form = new Form('index.php?module=config-thread_prefixes&action=edit_prefix', 'post'); + echo $form->generate_hidden_field('pid', $mybb->input['pid']); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $query = $db->simple_select('threadprefixes', '*', "pid = '{$mybb->input['pid']}'"); + $threadprefix = $db->fetch_array($query); + + $mybb->input['prefix'] = $threadprefix['prefix']; + $mybb->input['displaystyle'] = $threadprefix['displaystyle']; + $mybb->input['forum_1_forums'] = explode(",", $threadprefix['forums']); + + if(!$threadprefix['forums'] || $threadprefix['forums'] == -1) + { + $forum_checked[1] = "checked=\"checked\""; + $forum_checked[2] = ''; + } + else + { + $forum_checked[1] = ''; + $forum_checked[2] = "checked=\"checked\""; + } + + $mybb->input['group_1_groups'] = explode(",", $threadprefix['groups']); + + if(!$threadprefix['groups'] || $threadprefix['groups'] == -1) + { + $group_checked[1] = "checked=\"checked\""; + $group_checked[2] = ''; + } + else + { + $group_checked[1] = ''; + $group_checked[2] = "checked=\"checked\""; + } + } + + $form_container = new FormContainer($lang->prefix_options); + $form_container->output_row($lang->prefix.' *', $lang->prefix_desc, $form->generate_text_box('prefix', $mybb->input['prefix'], array('id' => 'prefix')), 'prefix'); + $form_container->output_row($lang->display_style.' *', $lang->display_style_desc, $form->generate_text_box('displaystyle', $mybb->input['displaystyle'], array('id' => 'displaystyle')), 'displaystyle'); + + $actions = " +
+
+
+
+ + + + + +
{$lang->forums_colon}".$form->generate_forum_select('forum_1_forums[]', $mybb->input['forum_1_forums'], array('multiple' => true, 'size' => 5))."
+
+
+ "; + $form_container->output_row($lang->available_in_forums.' *', '', $actions); + + $group_select = " +
+
+
+
+ + + + + +
{$lang->groups_colon}".$form->generate_group_select('group_1_groups[]', $mybb->input['group_1_groups'], array('multiple' => true, 'size' => 5))."
+
+
+ "; + $form_container->output_row($lang->available_to_groups." *", '', $group_select); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_thread_prefix); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == 'delete_prefix') +{ + $prefix = build_prefixes($mybb->input['pid']); + if(empty($prefix['pid'])) + { + flash_message($lang->error_invalid_thread_prefix, 'error'); + admin_redirect('index.php?module=config-thread_prefixes'); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect('index.php?module=config-thread_prefixes'); + } + + $plugins->run_hooks('admin_config_thread_prefixes_delete_prefix'); + + if($mybb->request_method == 'post') + { + // Remove prefix from existing threads + $update_threads = array('prefix' => 0); + + // Delete prefix + $db->delete_query('threadprefixes', "pid='{$prefix['pid']}'"); + + $plugins->run_hooks('admin_config_thread_prefixes_delete_thread_prefix_commit'); + + $db->update_query('threads', $update_threads, "prefix='{$prefix['pid']}'"); + + // Log admin action + log_admin_action($prefix['pid'], $prefix['prefix']); + $cache->update_threadprefixes(); + + flash_message($lang->success_thread_prefix_deleted, 'success'); + admin_redirect('index.php?module=config-thread_prefixes'); + } + else + { + $page->output_confirm_action("index.php?module=config-thread_prefixes&action=delete_prefix&pid={$mybb->input['pid']}", $lang->confirm_thread_prefix_deletion); + } +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks('admin_config_thread_prefixes_start'); + + $page->output_header($lang->thread_prefixes); + $page->output_nav_tabs($sub_tabs, 'thread_prefixes'); + + $table = new Table; + $table->construct_header($lang->prefix); + $table->construct_header($lang->controls, array('class' => 'align_center', 'colspan' => 2)); + + $prefixes = build_prefixes(); + if(!empty($prefixes)) + { + foreach($prefixes as $prefix) + { + $table->construct_cell("".htmlspecialchars_uni($prefix['prefix']).""); + $table->construct_cell("{$lang->edit}", array('width' => 100, 'class' => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_thread_prefix_deletion}')\">{$lang->delete}", array('width' => 100, 'class' => 'align_center')); + $table->construct_row(); + } + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_thread_prefixes, array('colspan' => 3)); + $table->construct_row(); + } + + $table->output($lang->thread_prefixes); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/config/warning.php b/Upload/admin/modules/config/warning.php new file mode 100644 index 0000000..88089df --- /dev/null +++ b/Upload/admin/modules/config/warning.php @@ -0,0 +1,774 @@ +
Please make sure IN_MYBB is defined."); +} + +require_once MYBB_ROOT."inc/functions_warnings.php"; + +$page->add_breadcrumb_item($lang->warning_system, "index.php?module=config-warning"); + +if($mybb->input['action'] == "levels" || $mybb->input['action'] == "add_type" || $mybb->input['action'] == "add_level" || !$mybb->input['action']) +{ + $sub_tabs['manage_types'] = array( + 'title' => $lang->warning_types, + 'link' => "index.php?module=config-warning", + 'description' => $lang->warning_types_desc + ); + $sub_tabs['add_type'] = array( + 'title'=> $lang->add_warning_type, + 'link' => "index.php?module=config-warning&action=add_type", + 'description' => $lang->add_warning_type_desc + ); + $sub_tabs['manage_levels'] = array( + 'title' => $lang->warning_levels, + 'link' => "index.php?module=config-warning&action=levels", + 'description' => $lang->warning_levels_desc, + ); + $sub_tabs['add_level'] = array( + 'title'=> $lang->add_warning_level, + 'link' => "index.php?module=config-warning&action=add_level", + 'description' => $lang->add_warning_level_desc + ); +} + +$plugins->run_hooks("admin_config_warning_begin"); + +if($mybb->input['action'] == "add_level") +{ + $plugins->run_hooks("admin_config_warning_add_level"); + + if($mybb->request_method == "post") + { + if(!is_numeric($mybb->input['percentage']) || $mybb->input['percentage'] > 100 || $mybb->input['percentage'] < 0) + { + $errors[] = $lang->error_invalid_warning_percentage; + } + + if(!$mybb->input['action_type']) + { + $errors[] = $lang->error_missing_action_type; + } + + if(!$errors) + { + // Ban + if($mybb->input['action_type'] == 1) + { + $action = array( + "type" => 1, + "usergroup" => (int)$mybb->input['action_1_usergroup'], + "length" => fetch_time_length($mybb->input['action_1_time'], $mybb->input['action_1_period']) + ); + } + // Suspend posting + else if($mybb->input['action_type'] == 2) + { + $action = array( + "type" => 2, + "length" => fetch_time_length($mybb->input['action_2_time'], $mybb->input['action_2_period']) + ); + } + // Moderate posts + else if($mybb->input['action_type'] == 3) + { + $action = array( + "type" => 3, + "length" => fetch_time_length($mybb->input['action_3_time'], $mybb->input['action_3_period']) + ); + } + $new_level = array( + "percentage" => (int)$mybb->input['percentage'], + "action" => serialize($action) + ); + + $lid = $db->insert_query("warninglevels", $new_level); + + $plugins->run_hooks("admin_config_warning_add_level_commit"); + + // Log admin action + log_admin_action($lid, $mybb->input['percentage']); + + flash_message($lang->success_warning_level_created, 'success'); + admin_redirect("index.php?module=config-warning&action=levels"); + } + } + + $page->add_breadcrumb_item($lang->add_warning_level); + $page->output_header($lang->warning_levels." - ".$lang->add_warning_level); + + $page->output_nav_tabs($sub_tabs, 'add_level'); + $form = new Form("index.php?module=config-warning&action=add_level", "post"); + + + if($errors) + { + $page->output_inline_error($errors); + $action_checked[$mybb->input['action_type']] = "checked=\"checked\""; + } + + $form_container = new FormContainer($lang->add_warning_level); + $form_container->output_row($lang->warning_points_percentage, $lang->warning_points_percentage_desc, $form->generate_numeric_field('percentage', $mybb->input['percentage'], array('id' => 'percentage')), 'percentage'); + + $query = $db->simple_select("usergroups", "*", "isbannedgroup=1"); + while($group = $db->fetch_array($query)) + { + $banned_groups[$group['gid']] = $group['title']; + } + + $periods = array( + "hours" => $lang->expiration_hours, + "days" => $lang->expiration_days, + "weeks" => $lang->expiration_weeks, + "months" => $lang->expiration_months, + "never" => $lang->expiration_permanent + ); + + $actions = " +
+
+
+ + + + + + + + + +
{$lang->banned_group}".$form->generate_select_box('action_1_usergroup', $banned_groups, $mybb->input['action_1_usergroup'])."
{$lang->ban_length}".$form->generate_numeric_field('action_1_time', $mybb->input['action_1_time'], array('style' => 'width: 2em;'))." ".$form->generate_select_box('action_1_period', $periods, $mybb->input['action_1_period'])."
+
+
+
+ + + + + +
{$lang->suspension_length}".$form->generate_numeric_field('action_2_time', $mybb->input['action_2_time'], array('style' => 'width: 2em;'))." ".$form->generate_select_box('action_2_period', $periods, $mybb->input['action_2_period'])."
+
+
+
+ + + + + +
{$lang->moderation_length}".$form->generate_numeric_field('action_3_time', $mybb->input['action_3_time'], array('style' => 'width: 2em;'))." ".$form->generate_select_box('action_3_period', $periods, $mybb->input['action_3_period'])."
+
+
+ "; + $form_container->output_row($lang->action_to_be_taken, $lang->action_to_be_taken_desc, $actions); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_warning_level); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit_level") +{ + $query = $db->simple_select("warninglevels", "*", "lid='".(int)$mybb->input['lid']."'"); + $level = $db->fetch_array($query); + + // Does the warning level not exist? + if(!$level['lid']) + { + flash_message($lang->error_invalid_warning_level, 'error'); + admin_redirect("index.php?module=config-warning"); + } + + $plugins->run_hooks("admin_config_warning_edit_level"); + + if($mybb->request_method == "post") + { + if(!is_numeric($mybb->input['percentage']) || $mybb->input['percentage'] > 100 || $mybb->input['percentage'] < 0) + { + $errors[] = $lang->error_invalid_warning_percentage; + } + + if(!$mybb->input['action_type']) + { + $errors[] = $lang->error_missing_action_type; + } + + if(!$errors) + { + // Ban + if($mybb->input['action_type'] == 1) + { + $action = array( + "type" => 1, + "usergroup" => (int)$mybb->input['action_1_usergroup'], + "length" => fetch_time_length($mybb->input['action_1_time'], $mybb->input['action_1_period']) + ); + } + // Suspend posting + else if($mybb->input['action_type'] == 2) + { + $action = array( + "type" => 2, + "length" => fetch_time_length($mybb->input['action_2_time'], $mybb->input['action_2_period']) + ); + } + // Moderate posts + else if($mybb->input['action_type'] == 3) + { + $action = array( + "type" => 3, + "length" => fetch_time_length($mybb->input['action_3_time'], $mybb->input['action_3_period']) + ); + } + $updated_level = array( + "percentage" => (int)$mybb->input['percentage'], + "action" => serialize($action) + ); + + $plugins->run_hooks("admin_config_warning_edit_level_commit"); + + $db->update_query("warninglevels", $updated_level, "lid='{$level['lid']}'"); + + // Log admin action + log_admin_action($level['lid'], $mybb->input['percentage']); + + flash_message($lang->success_warning_level_updated, 'success'); + admin_redirect("index.php?module=config-warning&action=levels"); + } + } + + $page->add_breadcrumb_item($lang->edit_warning_level); + $page->output_header($lang->warning_levels." - ".$lang->edit_warning_level); + + $sub_tabs['edit_level'] = array( + 'link' => "index.php?module=config-warning&action=edit_level&lid={$level['lid']}", + 'title' => $lang->edit_warning_level, + 'description' => $lang->edit_warning_level_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_level'); + $form = new Form("index.php?module=config-warning&action=edit_level&lid={$level['lid']}", "post"); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input = array_merge($mybb->input, array( + "percentage" => $level['percentage'], + ) + ); + $action = my_unserialize($level['action']); + if($action['type'] == 1) + { + $mybb->input['action_1_usergroup'] = $action['usergroup']; + $length = fetch_friendly_expiration($action['length']); + $mybb->input['action_1_time'] = $length['time']; + $mybb->input['action_1_period'] = $length['period']; + } + else if($action['type'] == 2) + { + $length = fetch_friendly_expiration($action['length']); + $mybb->input['action_2_time'] = $length['time']; + $mybb->input['action_2_period'] = $length['period']; + } + else if($action['type'] == 3) + { + $length = fetch_friendly_expiration($action['length']); + $mybb->input['action_3_time'] = $length['time']; + $mybb->input['action_3_period'] = $length['period']; + } + $action_checked[$action['type']] = "checked=\"checked\""; + } + + $form_container = new FormContainer($lang->edit_warning_level); + $form_container->output_row($lang->warning_points_percentage, $lang->warning_points_percentage_desc, $form->generate_numeric_field('percentage', $mybb->input['percentage'], array('id' => 'percentage')), 'percentage'); + + $query = $db->simple_select("usergroups", "*", "isbannedgroup=1"); + while($group = $db->fetch_array($query)) + { + $banned_groups[$group['gid']] = $group['title']; + } + + $periods = array( + "hours" => $lang->expiration_hours, + "days" => $lang->expiration_days, + "weeks" => $lang->expiration_weeks, + "months" => $lang->expiration_months, + "never" => $lang->expiration_permanent + ); + + $actions = " +
+
+
+ + + + + + + + + +
{$lang->banned_group}".$form->generate_select_box('action_1_usergroup', $banned_groups, $mybb->input['action_1_usergroup'])."
{$lang->ban_length}".$form->generate_numeric_field('action_1_time', $mybb->input['action_1_time'], array('style' => 'width: 2em;'))." ".$form->generate_select_box('action_1_period', $periods, $mybb->input['action_1_period'])."
+
+
+
+ + + + + +
{$lang->suspension_length}".$form->generate_numeric_field('action_2_time', $mybb->input['action_2_time'], array('style' => 'width: 2em;'))." ".$form->generate_select_box('action_2_period', $periods, $mybb->input['action_2_period'])."
+
+
+
+ + + + + +
{$lang->moderation_length}".$form->generate_numeric_field('action_3_time', $mybb->input['action_3_time'], array('style' => 'width: 2em;'))." ".$form->generate_select_box('action_3_period', $periods, $mybb->input['action_3_period'])."
+
+
+ "; + $form_container->output_row($lang->action_to_be_taken, $lang->action_to_be_taken_desc, $actions); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_warning_level); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete_level") +{ + $query = $db->simple_select("warninglevels", "*", "lid='".(int)$mybb->input['lid']."'"); + $level = $db->fetch_array($query); + + // Does the warning level not exist? + if(!$level['lid']) + { + flash_message($lang->error_invalid_warning_level, 'error'); + admin_redirect("index.php?module=config-warning"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-warning"); + } + + $plugins->run_hooks("admin_config_warning_delete_level"); + + if($mybb->request_method == "post") + { + // Delete the level + $db->delete_query("warninglevels", "lid='{$level['lid']}'"); + + $plugins->run_hooks("admin_config_warning_delete_level_commit"); + + // Log admin action + log_admin_action($level['lid'], $level['percentage']); + + flash_message($lang->success_warning_level_deleted, 'success'); + admin_redirect("index.php?module=config-warning"); + } + else + { + $page->output_confirm_action("index.php?module=config-warning&action=delete_level&lid={$level['lid']}", $lang->confirm_warning_level_deletion); + } +} + +if($mybb->input['action'] == "add_type") +{ + $plugins->run_hooks("admin_config_warning_add_type"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_type_title; + } + + if(!is_numeric($mybb->input['points']) || $mybb->input['points'] > $mybb->settings['maxwarningpoints'] || $mybb->input['points'] <= 0) + { + $errors[] = $lang->sprintf($lang->error_missing_type_points, $mybb->settings['maxwarningpoints']); + } + + if(!$errors) + { + $new_type = array( + "title" => $db->escape_string($mybb->input['title']), + "points" => (int)$mybb->input['points'], + "expirationtime" => fetch_time_length($mybb->input['expire_time'], $mybb->input['expire_period']) + ); + + $tid = $db->insert_query("warningtypes", $new_type); + + $plugins->run_hooks("admin_config_warning_add_type_commit"); + + // Log admin action + log_admin_action($tid, $mybb->input['title']); + + flash_message($lang->success_warning_type_created, 'success'); + admin_redirect("index.php?module=config-warning"); + } + } + else + { + $mybb->input = array_merge($mybb->input, array( + "points" => "2", + "expire_time" => 1, + "expire_period" => "days" + ) + ); + } + + $page->add_breadcrumb_item($lang->add_warning_type); + $page->output_header($lang->warning_types." - ".$lang->add_warning_type); + + $page->output_nav_tabs($sub_tabs, 'add_type'); + $form = new Form("index.php?module=config-warning&action=add_type", "post"); + + + if($errors) + { + $page->output_inline_error($errors); + } + + $form_container = new FormContainer($lang->add_warning_type); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->points_to_add." *", $lang->points_to_add_desc, $form->generate_numeric_field('points', $mybb->input['points'], array('id' => 'points')), 'points'); + $expiration_periods = array( + "hours" => $lang->expiration_hours, + "days" => $lang->expiration_days, + "weeks" => $lang->expiration_weeks, + "months" => $lang->expiration_months, + "never" => $lang->expiration_never + ); + $form_container->output_row($lang->warning_expiry, $lang->warning_expiry_desc, $form->generate_numeric_field('expire_time', $mybb->input['expire_time'], array('id' => 'expire_time'))." ".$form->generate_select_box('expire_period', $expiration_periods, $mybb->input['expire_period'], array('id' => 'expire_period')), 'expire_time'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_warning_type); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit_type") +{ + $query = $db->simple_select("warningtypes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $type = $db->fetch_array($query); + + // Does the warning type not exist? + if(!$type['tid']) + { + flash_message($lang->error_invalid_warning_type, 'error'); + admin_redirect("index.php?module=config-warning"); + } + + $plugins->run_hooks("admin_config_warning_edit_type"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_type_title; + } + + if(!is_numeric($mybb->input['points']) || $mybb->input['points'] > $mybb->settings['maxwarningpoints'] || $mybb->input['points'] < 0) + { + $errors[] = $lang->sprintf($lang->error_missing_type_points, $mybb->settings['maxwarningpoints']); + } + + if(!$errors) + { + $updated_type = array( + "title" => $db->escape_string($mybb->input['title']), + "points" => (int)$mybb->input['points'], + "expirationtime" => fetch_time_length($mybb->input['expire_time'], $mybb->input['expire_period']) + ); + + $plugins->run_hooks("admin_config_warning_edit_type_commit"); + + $db->update_query("warningtypes", $updated_type, "tid='{$type['tid']}'"); + + // Log admin action + log_admin_action($type['tid'], $mybb->input['title']); + + flash_message($lang->success_warning_type_updated, 'success'); + admin_redirect("index.php?module=config-warning"); + } + } + else + { + $expiration = fetch_friendly_expiration($type['expirationtime']); + $mybb->input = array_merge($mybb->input, array( + "title" => $type['title'], + "points" => $type['points'], + "expire_time" => $expiration['time'], + "expire_period" => $expiration['period'] + ) + ); + } + + $page->add_breadcrumb_item($lang->edit_warning_type); + $page->output_header($lang->warning_types." - ".$lang->edit_warning_type); + + $sub_tabs['edit_type'] = array( + 'link' => "index.php?module=config-warning&action=edit_type&tid={$type['tid']}", + 'title' => $lang->edit_warning_type, + 'description' => $lang->edit_warning_type_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_type'); + $form = new Form("index.php?module=config-warning&action=edit_type&tid={$type['tid']}", "post"); + + + if($errors) + { + $page->output_inline_error($errors); + } + + $form_container = new FormContainer($lang->edit_warning_type); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->points_to_add." *", $lang->points_to_add_desc, $form->generate_numeric_field('points', $mybb->input['points'], array('id' => 'points')), 'points'); + $expiration_periods = array( + "hours" => $lang->expiration_hours, + "days" => $lang->expiration_days, + "weeks" => $lang->expiration_weeks, + "months" => $lang->expiration_months, + "never" => $lang->expiration_never + ); + $form_container->output_row($lang->warning_expiry, $lang->warning_expiry_desc, $form->generate_numeric_field('expire_time', $mybb->input['expire_time'], array('id' => 'expire_time'))." ".$form->generate_select_box('expire_period', $expiration_periods, $mybb->input['expire_period'], array('id' => 'expire_period')), 'expire_time'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_warning_type); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete_type") +{ + $query = $db->simple_select("warningtypes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $type = $db->fetch_array($query); + + // Does the warning type not exist? + if(!$type['tid']) + { + flash_message($lang->error_invalid_warning_type, 'error'); + admin_redirect("index.php?module=config-warning"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=config-warning"); + } + + $plugins->run_hooks("admin_config_warning_delete_type"); + + if($mybb->request_method == "post") + { + // Delete the type + $db->delete_query("warningtypes", "tid='{$type['tid']}'"); + + $plugins->run_hooks("admin_config_warning_delete_type_commit"); + + // Log admin action + log_admin_action($type['tid'], $type['title']); + + flash_message($lang->success_warning_type_deleted, 'success'); + admin_redirect("index.php?module=config-warning"); + } + else + { + $page->output_confirm_action("index.php?module=config-warning&action=delete_type&tid={$type['tid']}", $lang->confirm_warning_type_deletion); + } +} + +if($mybb->input['action'] == "levels") +{ + $plugins->run_hooks("admin_config_warning_levels"); + + $page->output_header($lang->warning_levels); + + $page->output_nav_tabs($sub_tabs, 'manage_levels'); + + $table = new Table; + $table->construct_header($lang->percentage, array('width' => '5%', 'class' => 'align_center')); + $table->construct_header($lang->action_to_take); + $table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 2)); + + $query = $db->simple_select("warninglevels", "*", "", array('order_by' => 'percentage')); + while($level = $db->fetch_array($query)) + { + $table->construct_cell("{$level['percentage']}%", array("class" => "align_center")); + $action = my_unserialize($level['action']); + $period = fetch_friendly_expiration($action['length']); + + // Get the right language for the ban period + $lang_str = "expiration_".$period['period']; + $period_str = $lang->$lang_str; + + if($action['type'] == 1) + { + $type = "move_banned_group"; + $group_name = $groupscache[$action['usergroup']]['title']; + } + elseif($action['type'] == 2) + { + $type = "suspend_posting"; + } + elseif($action['type'] == 3) + { + $type = "moderate_new_posts"; + } + + if($period['period'] == "never") + { + $type .= "_permanent"; + + if($group_name) + { + // Permanently banned? Oh noes... switch group to the first sprintf replacement... + $period['time'] = $group_name; + } + } + + // If this level is permanently in place, then $period_str and $group_name do not apply below... + $type = $lang->sprintf($lang->$type, $period['time'], $period_str, $group_name); + + $table->construct_cell($type); + $table->construct_cell("{$lang->edit}", array("width" => 100, "class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_warning_level_deletion}')\">{$lang->delete}", array("width" => 100, "class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_warning_levels, array('colspan' => 4)); + $table->construct_row(); + $no_results = true; + } + + $table->output($lang->warning_levels); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_config_warning_start"); + + $page->output_header($lang->warning_types); + + $page->output_nav_tabs($sub_tabs, 'manage_types'); + + $table = new Table; + $table->construct_header($lang->warning_type); + $table->construct_header($lang->points, array('width' => '5%', 'class' => 'align_center')); + $table->construct_header($lang->expires_after, array('width' => '25%', 'class' => 'align_center')); + $table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 2)); + + $query = $db->simple_select("warningtypes", "*", "", array('order_by' => 'title')); + while($type = $db->fetch_array($query)) + { + $type['name'] = htmlspecialchars_uni($type['title']); + $table->construct_cell("{$type['title']}"); + $table->construct_cell("{$type['points']}", array("class" => "align_center")); + $expiration = fetch_friendly_expiration($type['expirationtime']); + $lang_str = "expiration_".$expiration['period']; + if($type['expirationtime'] > 0) + { + $table->construct_cell("{$expiration['time']} {$lang->$lang_str}", array("class" => "align_center")); + } + else + { + $table->construct_cell($lang->never, array("class" => "align_center")); + } + $table->construct_cell("{$lang->edit}", array("width" => 100, "class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_warning_type_deletion}')\">{$lang->delete}", array("width" => 100, "class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_warning_types, array('colspan' => 5)); + $table->construct_row(); + $no_results = true; + } + + $table->output($lang->warning_types); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/forum/announcements.php b/Upload/admin/modules/forum/announcements.php new file mode 100644 index 0000000..3870281 --- /dev/null +++ b/Upload/admin/modules/forum/announcements.php @@ -0,0 +1,947 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->forum_announcements, "index.php?module=forum-announcements"); + +if($mybb->input['action'] == "add" || !$mybb->input['action']) +{ + $sub_tabs['forum_announcements'] = array( + 'title' => $lang->forum_announcements, + 'link' => "index.php?module=forum-announcements", + 'description' => $lang->forum_announcements_desc + ); + + $sub_tabs['add_announcement'] = array( + 'title' => $lang->add_announcement, + 'link' => "index.php?module=forum-announcements&action=add", + 'description' => $lang->add_announcement_desc + ); +} +else if($mybb->input['action'] == "edit") +{ + $sub_tabs['forum_announcements'] = array( + 'title' => $lang->forum_announcements, + 'link' => "index.php?module=forum-announcements", + 'description' => $lang->forum_announcements_desc + ); + + $sub_tabs['update_announcement'] = array( + 'title' => $lang->update_announcement, + 'link' => "index.php?module=forum-announcements&action=add", + 'description' => $lang->update_announcement_desc + ); +} + +$plugins->run_hooks("admin_forum_announcements_begin"); + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_forum_announcements_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + if(!trim($mybb->input['message'])) + { + $errors[] = $lang->error_missing_message; + } + + if(!trim($mybb->input['fid'])) + { + $errors[] = $lang->error_missing_forum; + } + + if(!checkdate((int)$mybb->input['starttime_month'], (int)$mybb->input['starttime_day'], (int)$mybb->input['starttime_year'])) + { + $errors[] = $lang->error_invalid_start_date; + } + + // End before startdate? + $startdate = @explode(" ", $mybb->input['starttime_time']); + $startdate = @explode(":", $startdate[0]); + $enddate = @explode(" ", $mybb->input['endtime_time']); + $enddate = @explode(":", $enddate[0]); + + if(stristr($mybb->input['starttime_time'], "pm")) + { + $startdate[0] = 12+$startdate[0]; + if($startdate[0] >= 24) + { + $startdate[0] = "00"; + } + } + + if(stristr($mybb->input['endtime_time'], "pm")) + { + $enddate[0] = 12+$enddate[0]; + if($enddate[0] >= 24) + { + $enddate[0] = "00"; + } + } + + $startdate = gmmktime((int)$startdate[0], (int)$startdate[1], 0, (int)$mybb->input['starttime_month'], (int)$mybb->input['starttime_day'], (int)$mybb->input['starttime_year']); + + if($mybb->input['endtime_type'] != "2") + { + $enddate = gmmktime((int)$enddate[0], (int)$enddate[1], 0, (int)$mybb->input['endtime_month'], (int)$mybb->input['endtime_day'], (int)$mybb->input['endtime_year']); + if(!checkdate((int)$mybb->input['endtime_month'], (int)$mybb->input['endtime_day'], (int)$mybb->input['endtime_year'])) + { + $errors[] = $lang->error_invalid_end_date; + } + if($enddate <= $startdate) + { + $errors[] = $lang->error_end_before_start; + } + } + + if(!$errors) + { + if(isset($mybb->input['preview'])) + { + $parser_options = array(); + $parser_options['allow_html'] = (int)$mybb->input['allowhtml']; + $parser_options['allow_mycode'] = (int)$mybb->input['allowmycode']; + $parser_options['allow_smilies'] = (int)$mybb->input['allowsmilies']; + $parser_options['allow_imgcode'] = 1; + $parser_options['allow_videocode'] = 1; + $parser_options['me_username'] = htmlspecialchars_uni($mybb->user['username']); + $parser_options['filter_badwords'] = 1; + + // Set up the message parser if it doesn't already exist. + if(!is_object($parser)) + { + require_once MYBB_ROOT."inc/class_parser.php"; + $parser = new postParser; + } + + $preview['message'] = $parser->parse_message($mybb->input['message'], $parser_options); + $preview['subject'] = htmlspecialchars_uni($mybb->input['title']); + } + else + { + $months = array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'); + if(!in_array($mybb->input['starttime_month'], $months)) + { + $mybb->input['starttime_month'] = 1; + } + + if($mybb->input['endtime_type'] == "2") + { + $enddate = '0'; + } + else + { + if(!in_array($mybb->input['endtime_month'], $months)) + { + $mybb->input['endtime_month'] = 1; + } + } + + $insert_announcement = array( + "fid" => $mybb->input['fid'], + "uid" => $mybb->user['uid'], + "subject" => $db->escape_string($mybb->input['title']), + "message" => $db->escape_string($mybb->input['message']), + "startdate" => $startdate, + "enddate" => $enddate, + "allowhtml" => $db->escape_string($mybb->input['allowhtml']), + "allowmycode" => $db->escape_string($mybb->input['allowmycode']), + "allowsmilies" => $db->escape_string($mybb->input['allowsmilies']), + ); + + $aid = $db->insert_query("announcements", $insert_announcement); + + $plugins->run_hooks("admin_forum_announcements_add_commit"); + + // Log admin action + log_admin_action($aid, $mybb->input['title']); + $cache->update_forumsdisplay(); + + flash_message($lang->success_added_announcement, 'success'); + admin_redirect("index.php?module=forum-announcements"); + } + } + } + + $page->add_breadcrumb_item($lang->add_an_announcement); + $page->output_header($lang->add_an_announcement); + $page->output_nav_tabs($sub_tabs, "add_announcement"); + + $form = new Form("index.php?module=forum-announcements&action=add", "post"); + if($errors) + { + $page->output_inline_error($errors); + } + + $default_options = array( + 'starttime_time', + 'starttime_day', + 'starttime_month', + 'starttime_year', + 'endtime_type', + 'endtime_time', + 'endtime_day', + 'endtime_month', + 'endtime_year', + 'title', + 'message', + 'fid', + 'allowhtml', + 'allowmycode', + 'allowsmilies' + ); + + foreach($default_options as $option) + { + if(!isset($mybb->input[$option])) + { + $mybb->input[$option] = ''; + } + } + + if($mybb->input['endtime_type'] == "1") + { + $endtime_checked[1] = "checked=\"checked\""; + $endtime_checked[2] = ""; + } + else + { + $endtime_checked[1] = ""; + $endtime_checked[2] = "checked=\"checked\""; + } + + if(!$mybb->input['starttime_time']) + { + $start_time = explode("-", gmdate("g-i-a", TIME_NOW)); + $mybb->input['starttime_time'] = $start_time[0].":".$start_time[1]." ".$start_time[2]; + } + + if(!$mybb->input['endtime_time']) + { + $end_time = explode("-", gmdate("g-i-a", TIME_NOW)); + $mybb->input['endtime_time'] = $end_time[0].":".$end_time[1]." ".$end_time[2]; + } + + if($mybb->input['starttime_day']) + { + $startday = (int)$mybb->input['starttime_day']; + } + else + { + $startday = gmdate("j", TIME_NOW); + } + + if($mybb->input['endtime_day']) + { + $endday = (int)$mybb->input['endtime_day']; + } + else + { + $endday = gmdate("j", TIME_NOW); + } + + $startdateday = $enddateday = $startdatemonth = $enddatemonth = ''; + + // Days + for($i = 1; $i <= 31; ++$i) + { + if($startday == $i) + { + $startdateday .= "\n"; + } + else + { + $startdateday .= "\n"; + } + + if($endday == $i) + { + $enddateday .= "\n"; + } + else + { + $enddateday .= "\n"; + } + } + + // Months + for($i = 1; $i <= 12; ++$i) + { + $endmonthsel[$i] = $startmonthsel[$i] = ''; + } + + if($mybb->input['starttime_month']) + { + $startmonth = (int)$mybb->input['starttime_month']; + $startmonthsel[$startmonth] = "selected=\"selected\""; + } + else + { + $startmonth = gmdate("m", TIME_NOW); + $startmonthsel[$startmonth] = "selected=\"selected\""; + } + + if($mybb->input['endtime_month']) + { + $endmonth = (int)$mybb->input['endtime_month']; + $endmonthsel[$endmonth] = "selected=\"selected\""; + } + else + { + $endmonth = gmdate("m", TIME_NOW); + $endmonthsel[$endmonth] = "selected=\"selected\""; + } + + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + + if($mybb->input['starttime_year']) + { + $startdateyear = (int)$mybb->input['starttime_year']; + } + else + { + $startdateyear = gmdate("Y", TIME_NOW); + } + + if($mybb->input['endtime_year']) + { + $enddateyear = (int)$mybb->input['endtime_year']; + } + else + { + $enddateyear = gmdate("Y", TIME_NOW) + 1; + } + + if(isset($preview)) + { + $form_container = new FormContainer($lang->announcement_preview); + $form_container->output_row($preview['subject'], "", $preview['message'], 'preview'); + $form_container->end(); + } + + $form_container = new FormContainer($lang->add_an_announcement); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->start_date." *", $lang->start_date_desc, "\n   \n\n   \n\n - {$lang->time} ".$form->generate_text_box('starttime_time', $mybb->input['starttime_time'], array('id' => 'starttime_time', 'style' => 'width: 50px;'))); + + $actions = " +
+
+
+ + + + +
\n   \n\n   \n\n - {$lang->time} ".$form->generate_text_box('endtime_time', $mybb->input['endtime_time'], array('id' => 'endtime_time', 'style' => 'width: 50px;'))."
+
+
+
+ "; + $form_container->output_row($lang->end_date." *", $lang->end_date_desc, $actions); + + $form_container->output_row($lang->message." *", "", $form->generate_text_area('message', $mybb->input['message'], array('id' => 'message')), 'message'); + + $form_container->output_row($lang->forums_to_appear_in." *", $lang->forums_to_appear_in_desc, $form->generate_forum_select('fid', $mybb->input['fid'], array('size' => 5, 'main_option' => $lang->all_forums))); + + $form_container->output_row($lang->allow_html." *", "", $form->generate_yes_no_radio('allowhtml', $mybb->input['allowhtml'], array('style' => 'width: 2em;'))); + + $form_container->output_row($lang->allow_mycode." *", "", $form->generate_yes_no_radio('allowmycode', $mybb->input['allowmycode'], array('style' => 'width: 2em;'))); + + $form_container->output_row($lang->allow_smilies." *", "", $form->generate_yes_no_radio('allowsmilies', $mybb->input['allowsmilies'], array('style' => 'width: 2em;'))); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_announcement); + $buttons[] = $form->generate_submit_button($lang->preview_announcement, array('name' => 'preview')); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit") +{ + if(!trim($mybb->input['aid'])) + { + flash_message($lang->error_invalid_announcement, 'error'); + admin_redirect("index.php?module=forum-announcements"); + } + + $plugins->run_hooks("admin_forum_announcements_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + if(!trim($mybb->input['message'])) + { + $errors[] = $lang->error_missing_message; + } + + if(!trim($mybb->input['fid'])) + { + $errors[] = $lang->error_missing_forum; + } + + if(!checkdate((int)$mybb->input['starttime_month'], (int)$mybb->input['starttime_day'], (int)$mybb->input['starttime_year'])) + { + $errors[] = $lang->error_invalid_start_date; + } + + // End before startdate? + $startdate = @explode(" ", $mybb->input['starttime_time']); + $startdate = @explode(":", $startdate[0]); + $enddate = @explode(" ", $mybb->input['endtime_time']); + $enddate = @explode(":", $enddate[0]); + + if(stristr($mybb->input['starttime_time'], "pm")) + { + $startdate[0] = 12+$startdate[0]; + if($startdate[0] >= 24) + { + $startdate[0] = "00"; + } + } + + if(stristr($mybb->input['endtime_time'], "pm")) + { + $enddate[0] = 12+$enddate[0]; + if($enddate[0] >= 24) + { + $enddate[0] = "00"; + } + } + + $startdate = gmmktime((int)$startdate[0], (int)$startdate[1], 0, (int)$mybb->input['starttime_month'], (int)$mybb->input['starttime_day'], (int)$mybb->input['starttime_year']); + + if($mybb->input['endtime_type'] != "2") + { + $enddate = gmmktime((int)$enddate[0], (int)$enddate[1], 0, (int)$mybb->input['endtime_month'], (int)$mybb->input['endtime_day'], (int)$mybb->input['endtime_year']); + if(!checkdate((int)$mybb->input['endtime_month'], (int)$mybb->input['endtime_day'], (int)$mybb->input['endtime_year'])) + { + $errors[] = $lang->error_invalid_end_date; + } + if($enddate <= $startdate) + { + $errors[] = $lang->error_end_before_start; + } + } + + if(!$errors) + { + if(isset($mybb->input['preview'])) + { + $parser_options = array(); + $parser_options['allow_html'] = (int)$mybb->input['allowhtml']; + $parser_options['allow_mycode'] = (int)$mybb->input['allowmycode']; + $parser_options['allow_smilies'] = (int)$mybb->input['allowsmilies']; + $parser_options['allow_imgcode'] = 1; + $parser_options['allow_videocode'] = 1; + $parser_options['me_username'] = htmlspecialchars_uni($mybb->user['username']); + $parser_options['filter_badwords'] = 1; + + // Set up the message parser if it doesn't already exist. + if(!is_object($parser)) + { + require_once MYBB_ROOT."inc/class_parser.php"; + $parser = new postParser; + } + + $preview = array(); + $preview['message'] = $parser->parse_message($mybb->input['message'], $parser_options); + $preview['subject'] = htmlspecialchars_uni($mybb->input['title']); + } + else + { + $months = array('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'); + if(!in_array($mybb->input['starttime_month'], $months)) + { + $mybb->input['starttime_month'] = 1; + } + + if($mybb->input['endtime_type'] == "2") + { + $enddate = '0'; + } + else + { + if(!in_array($mybb->input['endtime_month'], $months)) + { + $mybb->input['endtime_month'] = 1; + } + } + + $update_announcement = array( + "fid" => $mybb->input['fid'], + "subject" => $db->escape_string($mybb->input['title']), + "message" => $db->escape_string($mybb->input['message']), + "startdate" => $startdate, + "enddate" => $enddate, + "allowhtml" => $db->escape_string($mybb->input['allowhtml']), + "allowmycode" => $db->escape_string($mybb->input['allowmycode']), + "allowsmilies" => $db->escape_string($mybb->input['allowsmilies']), + ); + + $plugins->run_hooks("admin_forum_announcements_edit_commit"); + + $db->update_query("announcements", $update_announcement, "aid='{$mybb->input['aid']}'"); + + // Log admin action + log_admin_action($mybb->input['aid'], $mybb->input['title']); + $cache->update_forumsdisplay(); + + flash_message($lang->success_updated_announcement, 'success'); + admin_redirect("index.php?module=forum-announcements"); + } + } + } + + $page->add_breadcrumb_item($lang->update_an_announcement); + $page->output_header($lang->update_an_announcement); + $page->output_nav_tabs($sub_tabs, "update_announcement"); + + $form = new Form("index.php?module=forum-announcements&action=edit", "post"); + echo $form->generate_hidden_field("aid", $mybb->input['aid']); + + if($errors) + { + $page->output_inline_error($errors); + + // Gather start and end date data + $startday = $mybb->input['starttime_day']; + $start_time = $mybb->input['starttime_time']; + $startmonth = $mybb->input['starttime_month']; + $startmonthsel[$startmonth] = 'selected="selected"'; + $startdateyear = $mybb->input['starttime_year']; + + if($mybb->input['endtime_type'] == 1) + { + // Set time + $endtime_checked[1] = 'checked="checked"'; + $endtime_checked[2] = ''; + + $endday = $mybb->input['endtime_day']; + $endtime = $mybb->input['endtime_time']; + $endmonth = $mybb->input['endtime_month']; + $endmonthsel[$endmonth] = 'selected'; + $enddateyear = $mybb->input['endtime_year']; + } + else + { + // Never + $endtime_checked[1] = ''; + $endtime_checked[2] = 'checked="checked"'; + + $endday = $startday; + $endmonth = $startmonth; + $endmonthsel[$endmonth] = 'selected'; + $enddateyear = $startdateyear + 1; + } + } + elseif(!isset($mybb->input['preview'])) + { + $query = $db->simple_select("announcements", "*", "aid='{$mybb->input['aid']}'"); + $announcement = $db->fetch_array($query); + + if(!$announcement) + { + flash_message($lang->error_invalid_announcement, 'error'); + admin_redirect("index.php?module=forum-announcements"); + } + + $start_time = explode("-", gmdate("g-i-a", $announcement['startdate'])); + $mybb->input['starttime_time'] = $start_time[0].":".$start_time[1]." ".$start_time[2]; + + $startday = gmdate("j", $announcement['startdate']); + + $startmonth = gmdate("m", $announcement['startdate']); + $startmonthsel[$startmonth] = "selected=\"selected\""; + + $startdateyear = gmdate("Y", $announcement['startdate']); + + $mybb->input['title'] = $announcement['subject']; + $mybb->input['message'] = $announcement['message']; + $mybb->input['allowhtml'] = $announcement['allowhtml']; + $mybb->input['allowsmilies'] = $announcement['allowsmilies']; + $mybb->input['allowmycode'] = $announcement['allowmycode']; + $mybb->input['fid'] = $announcement['fid']; + + if($announcement['enddate']) + { + $endtime_checked[1] = "checked=\"checked\""; + $endtime_checked[2] = ""; + + $end_time = explode("-", gmdate("g-i-a", $announcement['enddate'])); + $mybb->input['endtime_time'] = $end_time[0].":".$end_time[1]." ".$end_time[2]; + + $endday = gmdate("j", $announcement['enddate']); + + $endmonth = gmdate("m", $announcement['enddate']); + $endmonthsel[$endmonth] = "selected"; + + $enddateyear = gmdate("Y", $announcement['enddate']); + } + else + { + $endtime_checked[1] = ""; + $endtime_checked[2] = "checked=\"checked\""; + + $mybb->input['endtime_time'] = $mybb->input['starttime_time']; + $endday = $startday; + $endmonth = $startmonth; + $enddateyear = $startdateyear+1; + } + } + + for($i = 1; $i <= 31; ++$i) + { + if($startday == $i) + { + $startdateday .= "\n"; + } + else + { + $startdateday .= "\n"; + } + + if($endday == $i) + { + $enddateday .= "\n"; + } + else + { + $enddateday .= "\n"; + } + } + + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + $startdatemonth .= "\n"; + $enddatemonth .= "\n"; + + if(isset($preview)) + { + $form_container = new FormContainer($lang->announcement_preview); + $form_container->output_row($preview['subject'], "", $preview['message'], 'preview'); + $form_container->end(); + } + + $form_container = new FormContainer($lang->add_an_announcement); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->start_date." *", $lang->start_date_desc, "\n   \n\n   \n\n - {$lang->time} ".$form->generate_text_box('starttime_time', $mybb->input['starttime_time'], array('id' => 'starttime_time', 'style' => 'width: 50px;'))); + + $actions = " +
+
+
+ + + + +
\n   \n\n   \n\n - {$lang->time} ".$form->generate_text_box('endtime_time', $mybb->input['endtime_time'], array('id' => 'endtime_time', 'style' => 'width: 50px;'))."
+
+
+
+ "; + $form_container->output_row($lang->end_date." *", $lang->end_date_desc, $actions); + + $form_container->output_row($lang->message." *", "", $form->generate_text_area('message', $mybb->input['message'], array('id' => 'message')), 'message'); + + $form_container->output_row($lang->forums_to_appear_in." *", $lang->forums_to_appear_in_desc, $form->generate_forum_select('fid', $mybb->input['fid'], array('size' => 5, 'main_option' => $lang->all_forums))); + + $form_container->output_row($lang->allow_html." *", "", $form->generate_yes_no_radio('allowhtml', $mybb->input['allowhtml'], array('style' => 'width: 2em;'))); + + $form_container->output_row($lang->allow_mycode." *", "", $form->generate_yes_no_radio('allowmycode', $mybb->input['allowmycode'], array('style' => 'width: 2em;'))); + + $form_container->output_row($lang->allow_smilies." *", "", $form->generate_yes_no_radio('allowsmilies', $mybb->input['allowsmilies'], array('style' => 'width: 2em;'))); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_announcement); + $buttons[] = $form->generate_submit_button($lang->preview_announcement, array('name' => 'preview')); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("announcements", "*", "aid='{$mybb->input['aid']}'"); + $announcement = $db->fetch_array($query); + + // Does the announcement not exist? + if(!$announcement['aid']) + { + flash_message($lang->error_invalid_announcement, 'error'); + admin_redirect("index.php?module=forum-announcements"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=forum-announcements"); + } + + $plugins->run_hooks("admin_forum_announcements_delete"); + + if($mybb->request_method == "post") + { + $db->delete_query("announcements", "aid='{$announcement['aid']}'"); + + $plugins->run_hooks("admin_forum_announcements_delete_commit"); + + // Log admin action + log_admin_action($announcement['aid'], $announcement['subject']); + $cache->update_forumsdisplay(); + + flash_message($lang->success_announcement_deleted, 'success'); + admin_redirect("index.php?module=forum-announcements"); + } + else + { + $page->output_confirm_action("index.php?module=forum-announcements&action=delete&aid={$announcement['aid']}", $lang->confirm_announcement_deletion); + } +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_forum_announcements_start"); + + $page->output_header($lang->forum_announcements); + + $page->output_nav_tabs($sub_tabs, "forum_announcements"); + + // Fetch announcements into their proper arrays + $global_announcements = $announcements = array(); + $query = $db->simple_select("announcements", "aid, fid, subject, enddate"); + while($announcement = $db->fetch_array($query)) + { + if($announcement['fid'] == -1) + { + $global_announcements[$announcement['aid']] = $announcement; + continue; + } + $announcements[$announcement['fid']][$announcement['aid']] = $announcement; + } + + if(!empty($global_announcements)) + { + $table = new Table; + $table->construct_header($lang->announcement); + $table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 2, "width" => 150)); + + // Get the global announcements + foreach($global_announcements as $aid => $announcement) + { + if($announcement['enddate'] < TIME_NOW && $announcement['enddate'] != 0) + { + $icon = "style}/images/icons/bullet_off.png\" alt=\"(Expired)\" title=\"Expired Announcement\" style=\"vertical-align: middle;\" /> "; + } + else + { + $icon = "style}/images/icons/bullet_on.png\" alt=\"(Active)\" title=\"Active Announcement\" style=\"vertical-align: middle;\" /> "; + } + + $table->construct_cell($icon."".htmlspecialchars_uni($announcement['subject']).""); + $table->construct_cell("{$lang->edit}", array("class" => "align_center", "width" => 75)); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_announcement_deletion}')\">{$lang->delete}", array("class" => "align_center", "width" => 75)); + $table->construct_row(); + } + $table->output($lang->global_announcements); + } + + $table = new Table; + $table->construct_header($lang->announcement); + $table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 2, "width" => 200)); + + fetch_forum_announcements($table); + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_forums, array("colspan" => "3")); + $table->construct_row(); + } + + $table->output($lang->forum_announcements); + + $page->output_footer(); +} + +function fetch_forum_announcements(&$table, $pid=0, $depth=1) +{ + global $mybb, $db, $lang, $announcements, $page; + static $forums_by_parent; + + if(!is_array($forums_by_parent)) + { + $forum_cache = cache_forums(); + + foreach($forum_cache as $forum) + { + $forums_by_parent[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum; + } + } + + if(!is_array($forums_by_parent[$pid])) + { + return; + } + + foreach($forums_by_parent[$pid] as $children) + { + foreach($children as $forum) + { + $forum['name'] = htmlspecialchars_uni($forum['name']); + if($forum['active'] == 0) + { + $forum['name'] = "".$forum['name'].""; + } + + if($forum['type'] == "c") + { + $forum['name'] = "".$forum['name'].""; + } + + $table->construct_cell("
{$forum['name']}
"); + $table->construct_cell("{$lang->add_announcement}", array("class" => "align_center", "colspan" => 2)); + $table->construct_row(); + + if(isset($announcements[$forum['fid']])) + { + foreach($announcements[$forum['fid']] as $aid => $announcement) + { + if($announcement['enddate'] < TIME_NOW && $announcement['enddate'] != 0) + { + $icon = "style}/images/icons/bullet_off.png\" alt=\"(Expired)\" title=\"Expired Announcement\" style=\"vertical-align: middle;\" /> "; + } + else + { + $icon = "style}/images/icons/bullet_on.png\" alt=\"(Active)\" title=\"Active Announcement\" style=\"vertical-align: middle;\" /> "; + } + + $table->construct_cell(""); + $table->construct_cell("{$lang->edit}", array("class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_announcement_deletion}')\">{$lang->delete}", array("class" => "align_center")); + $table->construct_row(); + } + } + + // Build the list for any sub forums of this forum + if(isset($forums_by_parent[$forum['fid']])) + { + fetch_forum_announcements($table, $forum['fid'], $depth+1); + } + } + } +} + diff --git a/Upload/admin/modules/forum/attachments.php b/Upload/admin/modules/forum/attachments.php new file mode 100644 index 0000000..8cabd1d --- /dev/null +++ b/Upload/admin/modules/forum/attachments.php @@ -0,0 +1,945 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->attachments, "index.php?module=forum-attachments"); + +if($mybb->input['action'] == "stats" || $mybb->input['action'] == "orphans" || !$mybb->input['action']) +{ + $sub_tabs['find_attachments'] = array( + 'title' => $lang->find_attachments, + 'link' => "index.php?module=forum-attachments", + 'description' => $lang->find_attachments_desc + ); + + $sub_tabs['find_orphans'] = array( + 'title' => $lang->find_orphans, + 'link' => "index.php?module=forum-attachments&action=orphans", + 'description' => $lang->find_orphans_desc + ); + + $sub_tabs['stats'] = array( + 'title' => $lang->attachment_stats, + 'link' => "index.php?module=forum-attachments&action=stats", + 'description' => $lang->attachment_stats_desc + ); +} + +$plugins->run_hooks("admin_forum_attachments_begin"); + +if($mybb->input['action'] == "delete") +{ + $plugins->run_hooks("admin_forum_attachments_delete"); + + if(!is_array($mybb->input['aids'])) + { + $mybb->input['aids'] = array((int)$mybb->input['aid']); + } + else + { + $mybb->input['aids'] = array_map("intval", $mybb->input['aids']); + } + + if(count($mybb->input['aids']) < 1) + { + flash_message($lang->error_nothing_selected, 'error'); + admin_redirect("index.php?module=forum-attachments"); + } + + if($mybb->request_method == "post") + { + require_once MYBB_ROOT."inc/functions_upload.php"; + + $query = $db->simple_select("attachments", "aid,pid,posthash, filename", "aid IN (".implode(",", $mybb->input['aids']).")"); + while($attachment = $db->fetch_array($query)) + { + if(!$attachment['pid']) + { + remove_attachment(null, $attachment['posthash'], $attachment['aid']); + // Log admin action + log_admin_action($attachment['aid'], $attachment['filename']); + } + else + { + remove_attachment($attachment['pid'], null, $attachment['aid']); + // Log admin action + log_admin_action($attachment['aid'], $attachment['filename'], $attachment['pid']); + } + } + + $plugins->run_hooks("admin_forum_attachments_delete_commit"); + + flash_message($lang->success_deleted, 'success'); + admin_redirect("index.php?module=forum-attachments"); + } + else + { + $aids = array(); + foreach($mybb->input['aids'] as $aid) + { + $aids .= "&aids[]=$aid"; + } + $page->output_confirm_action("index.php?module=forum-attachments&action=delete&aids={$aids}", $lang->confirm_delete); + } +} + +if($mybb->input['action'] == "stats") +{ + $plugins->run_hooks("admin_forum_attachments_stats"); + + $query = $db->simple_select("attachments", "COUNT(*) AS total_attachments, SUM(filesize) as disk_usage, SUM(downloads*filesize) as bandwidthused", "visible='1'"); + $attachment_stats = $db->fetch_array($query); + + $page->add_breadcrumb_item($lang->stats); + $page->output_header($lang->stats_attachment_stats); + + $page->output_nav_tabs($sub_tabs, 'stats'); + + if($attachment_stats['total_attachments'] == 0) + { + $page->output_inline_error(array($lang->error_no_attachments)); + $page->output_footer(); + exit; + } + + $table = new Table; + + $table->construct_cell($lang->num_uploaded, array('width' => '25%')); + $table->construct_cell(my_number_format($attachment_stats['total_attachments']), array('width' => '25%')); + $table->construct_cell($lang->space_used, array('width' => '200')); + $table->construct_cell(get_friendly_size($attachment_stats['disk_usage']), array('width' => '200')); + $table->construct_row(); + + $table->construct_cell($lang->bandwidth_used, array('width' => '25%')); + $table->construct_cell(get_friendly_size(round($attachment_stats['bandwidthused'])), array('width' => '25%')); + $table->construct_cell($lang->average_size, array('width' => '25%')); + $table->construct_cell(get_friendly_size(round($attachment_stats['disk_usage']/$attachment_stats['total_attachments'])), array('width' => '25%')); + $table->construct_row(); + + $table->output($lang->general_stats); + + // Fetch the most popular attachments + $table = new Table; + $table->construct_header($lang->attachments, array('colspan' => 2)); + $table->construct_header($lang->size, array('width' => '10%', 'class' => 'align_center')); + $table->construct_header($lang->posted_by, array('width' => '20%', 'class' => 'align_center')); + $table->construct_header($lang->thread, array('width' => '25%', 'class' => 'align_center')); + $table->construct_header($lang->downloads, array('width' => '10%', 'class' => 'align_center')); + $table->construct_header($lang->date_uploaded, array("class" => "align_center")); + + $query = $db->query(" + SELECT a.*, p.tid, p.fid, t.subject, p.uid, p.username, u.username AS user_username + FROM ".TABLE_PREFIX."attachments a + LEFT JOIN ".TABLE_PREFIX."posts p ON (p.pid=a.pid) + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=a.uid) + ORDER BY a.downloads DESC + LIMIT 5 + "); + while($attachment = $db->fetch_array($query)) + { + build_attachment_row($attachment, $table); + } + $table->output($lang->popular_attachments); + + // Fetch the largest attachments + $table = new Table; + $table->construct_header($lang->attachments, array('colspan' => 2)); + $table->construct_header($lang->size, array('width' => '10%', 'class' => 'align_center')); + $table->construct_header($lang->posted_by, array('width' => '20%', 'class' => 'align_center')); + $table->construct_header($lang->thread, array('width' => '25%', 'class' => 'align_center')); + $table->construct_header($lang->downloads, array('width' => '10%', 'class' => 'align_center')); + $table->construct_header($lang->date_uploaded, array("class" => "align_center")); + + $query = $db->query(" + SELECT a.*, p.tid, p.fid, t.subject, p.uid, p.username, u.username AS user_username + FROM ".TABLE_PREFIX."attachments a + LEFT JOIN ".TABLE_PREFIX."posts p ON (p.pid=a.pid) + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=a.uid) + ORDER BY a.filesize DESC + LIMIT 5 + "); + while($attachment = $db->fetch_array($query)) + { + build_attachment_row($attachment, $table); + } + $table->output($lang->largest_attachments); + + // Fetch users who've uploaded the most attachments + $table = new Table; + $table->construct_header($lang->username); + $table->construct_header($lang->total_size, array('width' => '20%', 'class' => 'align_center')); + + switch($db->type) + { + case "pgsql": + $query = $db->query(" + SELECT a.*, u.uid AS useruid, u.username, SUM(a.filesize) as totalsize + FROM ".TABLE_PREFIX."attachments a + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=a.uid) + GROUP BY ".$db->build_fields_string("attachments", "a.").",u.uid,u.username + ORDER BY totalsize DESC + LIMIT 5 + "); + break; + default: + $query = $db->query(" + SELECT a.*, u.uid AS useruid, u.username, SUM(a.filesize) as totalsize + FROM ".TABLE_PREFIX."attachments a + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=a.uid) + GROUP BY a.uid + ORDER BY totalsize DESC + LIMIT 5 + "); + } + while($user = $db->fetch_array($query)) + { + if(!$user['useruid']) + { + $user['username'] = $lang->na; + } + $table->construct_cell(build_profile_link($user['username'], $user['useruid'], "_blank")); + $table->construct_cell("".get_friendly_size($user['totalsize'])."", array('class' => 'align_center')); + $table->construct_row(); + } + $table->output($lang->users_diskspace); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete_orphans" && $mybb->request_method == "post") +{ + $plugins->run_hooks("admin_forum_attachments_delete_orphans"); + + // Deleting specific attachments from uploads directory + if(is_array($mybb->input['orphaned_files'])) + { + function clean_filename($string) + { + return str_replace(array(".."), "", $string); + } + $mybb->input['orphaned_files'] = array_map("clean_filename", $mybb->input['orphaned_files']); + foreach($mybb->input['orphaned_files'] as $file) + { + if(!@unlink(MYBB_ROOT.$mybb->settings['uploadspath']."/".$file)) + { + $error = true; + } + } + } + + // Deleting physical attachments which exist in database + if(is_array($mybb->input['orphaned_attachments'])) + { + $mybb->input['orphaned_attachments'] = array_map("intval", $mybb->input['orphaned_attachments']); + require_once MYBB_ROOT."inc/functions_upload.php"; + + $query = $db->simple_select("attachments", "aid,pid,posthash", "aid IN (".implode(",", $mybb->input['orphaned_attachments']).")"); + while($attachment = $db->fetch_array($query)) + { + if(!$attachment['pid']) + { + remove_attachment(null, $attachment['posthash'], $attachment['aid']); + } + else + { + remove_attachment($attachment['pid'], null, $attachment['aid']); + } + } + } + + $plugins->run_hooks("admin_forum_attachments_delete_orphans_commit"); + + // Log admin action + log_admin_action(); + + if($error == true) + { + flash_message($lang->error_not_all_removed, 'error'); + } + else + { + flash_message($lang->success_orphan_deleted, 'success'); + } + admin_redirect("index.php?module=forum-attachments"); +} + +if($mybb->input['action'] == "orphans") +{ + $plugins->run_hooks("admin_forum_attachments_orphans"); + + // Oprhans are defined as: + // - Uploaded files in the uploads directory that don't exist in the database + // - Attachments for which the uploaded file is missing + // - Attachments for which the thread or post has been deleted + // - Files uploaded > 24h ago not attached to a real post + + // This process is quite intensive so we split it up in to 2 steps, one which scans the file system and the other which scans the database. + + // Finished second step, show results + if($mybb->input['step'] == 3) + { + $plugins->run_hooks("admin_forum_attachments_step3"); + + $reults = 0; + // Incoming attachments which exist as files but not in database + if($mybb->input['bad_attachments']) + { + $bad_attachments = my_unserialize($mybb->input['bad_attachments']); + $results = count($bad_attachments); + } + + $aids = array(); + if($mybb->input['missing_attachment_files']) + { + $missing_attachment_files = my_unserialize($mybb->input['missing_attachment_files']); + $aids = array_merge($aids, $missing_attachment_files); + } + + if($mybb->input['missing_threads']) + { + $missing_threads = my_unserialize($mybb->input['missing_threads']); + $aids = array_merge($aids, $missing_threads); + } + + if($mybb->input['incomplete_attachments']) + { + $incomplete_attachments = my_unserialize($mybb->input['incomplete_attachments']); + $aids = array_merge($aids, $incomplete_attachments); + } + + foreach($aids as $key => $aid) + { + $aids[$key] = (int)$aid; + } + + $results += count($aids); + + if($results == 0) + { + flash_message($lang->success_no_orphans, 'success'); + admin_redirect("index.php?module=forum-attachments"); + } + + $page->output_header($lang->orphan_results); + $page->output_nav_tabs($sub_tabs, 'find_orphans'); + + $form = new Form("index.php?module=forum-attachments&action=delete_orphans", "post"); + + $table = new Table; + $table->construct_header($form->generate_check_box('checkall', '1', '', array('class' => 'checkall')), array( 'width' => 1)); + $table->construct_header($lang->size_attachments, array('colspan' => 2)); + $table->construct_header($lang->reason_orphaned, array('width' => '20%', 'class' => 'align_center')); + $table->construct_header($lang->date_uploaded, array("class" => "align_center")); + + if(is_array($bad_attachments)) + { + foreach($bad_attachments as $file) + { + $file_path = MYBB_ROOT.$mybb->settings['uploadspath']."/".$file; + $filesize = get_friendly_size(filesize($file_path)); + $table->construct_cell($form->generate_check_box('orphaned_files[]', $file, '', array('checked' => true))); + $table->construct_cell(get_attachment_icon(get_extension($attachment['filename'])), array('width' => 1)); + $table->construct_cell("{$filesize}{$file}"); + $table->construct_cell($lang->reason_not_in_table, array('class' => 'align_center')); + $table->construct_cell(my_date('relative', filemtime($file_path)), array('class' => 'align_center')); + $table->construct_row(); + } + } + + if(count($aids) > 0) + { + $query = $db->simple_select("attachments", "*", "aid IN (".implode(",", $aids).")"); + while($attachment = $db->fetch_array($query)) + { + $attachment['filename'] = htmlspecialchars_uni($attachment['filename']); + + if($missing_attachment_files[$attachment['aid']]) + { + $reason = $lang->reason_file_missing; + } + else if($missing_threads[$attachment['aid']]) + { + $reason = $lang->reason_thread_deleted; + } + else if($incomplete_attachments[$attachment['aid']]) + { + $reason = $lang->reason_post_never_made; + } + $table->construct_cell($form->generate_check_box('orphaned_attachments[]', $attachment['aid'], '', array('checked' => true))); + $table->construct_cell(get_attachment_icon(get_extension($attachment['filename'])), array('width' => 1)); + $table->construct_cell("".get_friendly_size($attachment['filesize'])."{$attachment['filename']}", array('class' => $cell_class)); + $table->construct_cell($reason, array('class' => 'align_center')); + if($attachment['dateuploaded']) + { + $table->construct_cell(my_date('relative', $attachment['dateuploaded']), array('class' => 'align_center')); + } + else + { + $table->construct_cell($lang->unknown, array('class' => 'align_center')); + } + $table->construct_row(); + } + } + + $table->output("{$lang->orphan_attachments_search} - {$results} {$lang->results}"); + + $buttons[] = $form->generate_submit_button($lang->button_delete_orphans); + $form->output_submit_wrapper($buttons); + $form->end(); + $page->output_footer(); + } + + // Running second step - scan the database + else if($mybb->input['step'] == 2) + { + $plugins->run_hooks("admin_forum_attachments_orphans_step2"); + + $page->output_header("{$lang->orphan_attachments_search} - {$lang->step2}"); + + $page->output_nav_tabs($sub_tabs, 'find_orphans'); + echo "

{$lang->step2of2}

"; + echo "

{$lang->step2of2_line1}

"; + echo "

{$lang->step_line2}

"; + echo "

style}/images/spinner_big.gif\" alt=\"{$lang->scanning}\" id=\"spinner\" />

"; + + $page->output_footer(false); + flush(); + + $missing_attachment_files = array(); + $missing_threads = array(); + $incomplete_attachments = array(); + + $query = $db->query(" + SELECT a.*, a.pid AS attachment_pid, p.pid + FROM ".TABLE_PREFIX."attachments a + LEFT JOIN ".TABLE_PREFIX."posts p ON (p.pid=a.pid) + ORDER BY a.aid"); + while($attachment = $db->fetch_array($query)) + { + // Check if the attachment exists in the file system + if(!file_exists(MYBB_ROOT.$mybb->settings['uploadspath']."/{$attachment['attachname']}")) + { + $missing_attachment_files[$attachment['aid']] = $attachment['aid']; + } + // Check if the thread/post for this attachment is missing + else if(!$attachment['pid'] && $attachment['attachment_pid']) + { + $missing_threads[$attachment['aid']] = $attachment['aid']; + } + // Check if the attachment was uploaded > 24 hours ago but not assigned to a thread + else if(!$attachment['attachment_pid'] && $attachment['dateuploaded'] < TIME_NOW-60*60*24 && $attachment['dateuploaded'] != 0) + { + $incomplete_attachments[$attachment['aid']] = $attachment['aid']; + } + } + + // Now send the user to the final page + $form = new Form("index.php?module=forum-attachments&action=orphans&step=3", "post", "redirect_form", 0, ""); + // Scan complete + if($mybb->input['bad_attachments']) + { + echo $form->generate_hidden_field("bad_attachments", $mybb->input['bad_attachments']); + } + if(is_array($missing_attachment_files) && count($missing_attachment_files) > 0) + { + $missing_attachment_files = serialize($missing_attachment_files); + echo $form->generate_hidden_field("missing_attachment_files", $missing_attachment_files); + } + if(is_array($missing_threads) && count($missing_threads) > 0) + { + $missing_threads = serialize($missing_threads); + echo $form->generate_hidden_field("missing_threads", $missing_threads); + } + if(is_array($incomplete_attachments) && count($incomplete_attachments) > 0) + { + $incomplete_attachments = serialize($incomplete_attachments); + echo $form->generate_hidden_field("incomplete_attachments", $incomplete_attachments); + } + $form->end(); + echo ""; + exit; + } + // Running first step, scan the file system + else + { + $plugins->run_hooks("admin_forum_attachments_orphans_step1"); + + function scan_attachments_directory($dir="") + { + global $db, $mybb, $bad_attachments, $attachments_to_check; + + $real_dir = MYBB_ROOT.$mybb->settings['uploadspath']; + $false_dir = ""; + if($dir) + { + $real_dir .= "/".$dir; + $false_dir = $dir."/"; + } + + if($dh = opendir($real_dir)) + { + while(false !== ($file = readdir($dh))) + { + if($file == "." || $file == ".." || $file == ".svn") + { + continue; + } + + if(is_dir($real_dir.'/'.$file)) + { + scan_attachments_directory($false_dir.$file); + } + else if(my_substr($file, -7, 7) == ".attach") + { + $attachments_to_check["$false_dir$file"] = $false_dir.$file; + // In allotments of 20, query the database for these attachments + if(count($attachments_to_check) >= 20) + { + $attachments_to_check = array_map(array($db, "escape_string"), $attachments_to_check); + $attachment_names = "'".implode("','", $attachments_to_check)."'"; + $query = $db->simple_select("attachments", "aid, attachname", "attachname IN ($attachment_names)"); + while($attachment = $db->fetch_array($query)) + { + unset($attachments_to_check[$attachment['attachname']]); + } + + // Now anything left is bad! + if(count($attachments_to_check) > 0) + { + if($bad_attachments) + { + $bad_attachments = @array_merge($bad_attachments, $attachments_to_check); + } + else + { + $bad_attachments = $attachments_to_check; + } + } + $attachments_to_check = array(); + } + } + } + closedir($dh); + // Any reamining to check? + if(count($attachments_to_check) > 0) + { + $attachments_to_check = array_map(array($db, "escape_string"), $attachments_to_check); + $attachment_names = "'".implode("','", $attachments_to_check)."'"; + $query = $db->simple_select("attachments", "aid, attachname", "attachname IN ($attachment_names)"); + while($attachment = $db->fetch_array($query)) + { + unset($attachments_to_check[$attachment['attachname']]); + } + + // Now anything left is bad! + if(count($attachments_to_check) > 0) + { + if($bad_attachments) + { + $bad_attachments = @array_merge($bad_attachments, $attachments_to_check); + } + else + { + $bad_attachments = $attachments_to_check; + } + } + } + } + } + + $page->output_header("{$lang->orphan_attachments_search} - {$lang->step1}"); + + $page->output_nav_tabs($sub_tabs, 'find_orphans'); + echo "

{$lang->step1of2}

"; + echo "

{$lang->step1of2_line1}

"; + echo "

{$lang->step_line2}

"; + echo "

style}/images/spinner_big.gif\" alt=\"{$lang->scanning}\" id=\"spinner\" />

"; + + $page->output_footer(false); + + flush(); + + scan_attachments_directory(); + global $bad_attachments; + + $form = new Form("index.php?module=forum-attachments&action=orphans&step=2", "post", "redirect_form", 0, ""); + // Scan complete + if(is_array($bad_attachments) && count($bad_attachments) > 0) + { + $bad_attachments = serialize($bad_attachments); + echo $form->generate_hidden_field("bad_attachments", $bad_attachments); + } + $form->end(); + echo ""; + exit; + } +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_forum_attachments_start"); + + if($mybb->request_method == "post" || $mybb->input['results'] == 1) + { + $search_sql = '1=1'; + + // Build the search SQL for users + + // List of valid LIKE search fields + $user_like_fields = array("filename", "filetype"); + foreach($user_like_fields as $search_field) + { + if($mybb->input[$search_field]) + { + $search_sql .= " AND a.{$search_field} LIKE '%".$db->escape_string_like($mybb->input[$search_field])."%'"; + } + } + + $errors = array(); + + // Username matching + if($mybb->input['username']) + { + $user = get_user_by_username($mybb->input['username']); + + if(!$user['uid']) + { + $errors[] = $lang->error_invalid_username; + } + else + { + $search_sql .= " AND a.uid='{$user['uid']}'"; + } + } + + $forum_cache = cache_forums(); + + // Searching for attachments in a specific forum, we need to fetch all child forums too + if($mybb->input['forum']) + { + if(!is_array($mybb->input['forum'])) + { + $mybb->input['forum'] = array($mybb->input['forum']); + } + + $fid_in = array(); + foreach($mybb->input['forum'] as $fid) + { + if(!$forum_cache[$fid]) + { + $errors[] = $lang->error_invalid_forums; + break; + } + $child_forums = get_child_list($fid); + $child_forums[] = $fid; + $fid_in = array_merge($fid_in, $child_forums); + } + + if(count($fid_in) > 0) + { + $search_sql .= " AND p.fid IN (".implode(",", $fid_in).")"; + } + } + + // LESS THAN or GREATER THAN + if($mybb->input['dateuploaded'] && $mybb->request_method == "post") + { + $mybb->input['dateuploaded'] = TIME_NOW-$mybb->input['dateuploaded']*60*60*24; + } + if($mybb->input['filesize'] && $mybb->request_method == "post") + { + $mybb->input['filesize'] *= 1024; + } + + $direction_fields = array("dateuploaded", "filesize", "downloads"); + foreach($direction_fields as $search_field) + { + $direction_field = $search_field."_dir"; + if($mybb->input[$search_field] && $mybb->input[$direction_field]) + { + switch($mybb->input[$direction_field]) + { + case "greater_than": + $direction = ">"; + break; + case "less_than": + $direction = "<"; + break; + default: + $direction = "="; + } + $search_sql .= " AND a.{$search_field}{$direction}'".$db->escape_string($mybb->input[$search_field])."'"; + } + } + if(!$errors) + { + // Lets fetch out how many results we have + $query = $db->query(" + SELECT COUNT(a.aid) AS num_results + FROM ".TABLE_PREFIX."attachments a + LEFT JOIN ".TABLE_PREFIX."posts p ON (p.pid=a.pid) + WHERE {$search_sql} + "); + $num_results = $db->fetch_field($query, "num_results"); + + // No matching results then show an error + if(!$num_results) + { + $errors[] = $lang->error_no_results; + } + } + + // Now we fetch the results if there were 100% no errors + if(!$errors) + { + $mybb->input['perpage'] = $mybb->get_input('perpage', 1); + if(!$mybb->input['perpage']) + { + $mybb->input['perpage'] = 20; + } + + $mybb->input['page'] = $mybb->get_input('page', 1); + if($mybb->input['page']) + { + $start = ($mybb->input['page'] - 1) * $mybb->input['perpage']; + } + else + { + $start = 0; + $mybb->input['page'] = 1; + } + + switch($mybb->input['sortby']) + { + case "filesize": + $sort_field = "a.filesize"; + break; + case "downloads": + $sort_field = "a.downloads"; + break; + case "dateuploaded": + $sort_field = "a.dateuploaded"; + break; + case "username": + $sort_field = "u.username"; + break; + default: + $sort_field = "a.filename"; + $mybb->input['sortby'] = "filename"; + } + + if($mybb->input['order'] != "desc") + { + $mybb->input['order'] = "asc"; + } + + $page->add_breadcrumb_item($lang->results); + $page->output_header($lang->index_find_attachments); + + $page->output_nav_tabs($sub_tabs, 'find_attachments'); + + $form = new Form("index.php?module=forum-attachments&action=delete", "post"); + + $table = new Table; + $table->construct_header($form->generate_check_box('checkall', '1', '', array('class' => 'checkall')), array( 'width' => 1)); + $table->construct_header($lang->attachments, array('colspan' => 2)); + $table->construct_header($lang->size, array('width' => '10%', 'class' => 'align_center')); + $table->construct_header($lang->posted_by, array('width' => '20%', 'class' => 'align_center')); + $table->construct_header($lang->thread, array('width' => '25%', 'class' => 'align_center')); + $table->construct_header($lang->downloads, array('width' => '10%', 'class' => 'align_center')); + $table->construct_header($lang->date_uploaded, array("class" => "align_center")); + + // Fetch matching attachments + $query = $db->query(" + SELECT a.*, p.tid, p.fid, t.subject, p.uid, p.username, u.username AS user_username + FROM ".TABLE_PREFIX."attachments a + LEFT JOIN ".TABLE_PREFIX."posts p ON (p.pid=a.pid) + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=a.uid) + WHERE {$search_sql} + ORDER BY {$sort_field} {$mybb->input['order']} + LIMIT {$start}, {$mybb->input['perpage']} + "); + while($attachment = $db->fetch_array($query)) + { + build_attachment_row($attachment, $table, true); + } + + // Need to draw pagination for this result set + if($num_results > $mybb->input['perpage']) + { + $pagination_url = "index.php?module=forum-attachments&results=1"; + $pagination_vars = array('perpage', 'sortby', 'order', 'filename', 'mimetype', 'username', 'fid', 'downloads', 'downloads_dir', 'dateuploaded', 'dateuploaded_dir', 'filesize', 'filesize_dir'); + foreach($pagination_vars as $var) + { + if($mybb->input[$var]) + { + $pagination_url .= "&{$var}=".urlencode($mybb->input[$var]); + } + } + $pagination = draw_admin_pagination($mybb->input['page'], $mybb->input['perpage'], $num_results, $pagination_url); + } + + echo $pagination; + $table->output($lang->results); + echo $pagination; + + $buttons[] = $form->generate_submit_button($lang->button_delete_attachments); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); + } + } + + $page->output_header($lang->find_attachments); + + $page->output_nav_tabs($sub_tabs, 'find_attachments'); + + // If we have any error messages, show them + if($errors) + { + $page->output_inline_error($errors); + } + + $form = new Form("index.php?module=forum-attachments", "post"); + + $form_container = new FormContainer($lang->find_where); + $form_container->output_row($lang->name_contains, $lang->name_contains_desc, $form->generate_text_box('filename', $mybb->input['filename'], array('id' => 'filename')), 'filename'); + $form_container->output_row($lang->type_contains, "", $form->generate_text_box('mimetype', $mybb->input['mimetype'], array('id' => 'mimetype')), 'mimetype'); + $form_container->output_row($lang->forum_is, "", $form->generate_forum_select('forum[]', $mybb->input['forum'], array('multiple' => true, 'size' => 5, 'id' => 'forum')), 'forum'); + $form_container->output_row($lang->username_is, "", $form->generate_text_box('username', $mybb->input['username'], array('id' => 'username')), 'username'); + + $more_options = array( + "less_than" => $lang->more_than, + "greater_than" => $lang->less_than + ); + + $greater_options = array( + "greater_than" => $lang->greater_than, + "is_exactly" => $lang->is_exactly, + "less_than" => $lang->less_than + ); + + $form_container->output_row($lang->date_posted_is, "", $form->generate_select_box('dateuploaded_dir', $more_options, $mybb->input['dateuploaded_dir'], array('id' => 'dateuploaded_dir'))." ".$form->generate_numeric_field('dateuploaded', $mybb->input['dateuploaded'], array('id' => 'dateuploaded'))." {$lang->days_ago}", 'dateuploaded'); + $form_container->output_row($lang->file_size_is, "", $form->generate_select_box('filesize_dir', $greater_options, $mybb->input['filesize_dir'], array('id' => 'filesize_dir'))." ".$form->generate_numeric_field('filesize', $mybb->input['filesize'], array('id' => 'filesize'))." {$lang->kb}", 'dateuploaded'); + $form_container->output_row($lang->download_count_is, "", $form->generate_select_box('downloads_dir', $greater_options, $mybb->input['downloads_dir'], array('id' => 'downloads_dir'))." ".$form->generate_numeric_field('downloads', $mybb->input['downloads'], array('id' => 'downloads'))."", 'dateuploaded'); + $form_container->end(); + + $form_container = new FormContainer($lang->display_options); + $sort_options = array( + "filename" => $lang->filename, + "filesize" => $lang->filesize, + "downloads" => $lang->download_count, + "dateuploaded" => $lang->date_uploaded, + "username" => $lang->post_username + ); + $sort_directions = array( + "asc" => $lang->asc, + "desc" => $lang->desc + ); + $form_container->output_row($lang->sort_results_by, "", $form->generate_select_box('sortby', $sort_options, $mybb->input['sortby'], array('id' => 'sortby'))." {$lang->in} ".$form->generate_select_box('order', $sort_directions, $mybb->input['order'], array('id' => 'order')), 'sortby'); + $form_container->output_row($lang->results_per_page, "", $form->generate_numeric_field('perpage', $mybb->input['perpage'], array('id' => 'perpage')), 'perpage'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->button_find_attachments); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +function build_attachment_row($attachment, &$table, $use_form=false) +{ + global $mybb, $form; + $attachment['filename'] = htmlspecialchars_uni($attachment['filename']); + + // Here we do a bit of detection, we want to automatically check for removal any missing attachments and any not assigned to a post uploaded > 24hours ago + // Check if the attachment exists in the file system + $checked = false; + $title = $cell_class = ''; + if(!file_exists(MYBB_ROOT.$mybb->settings['uploadspath']."/{$attachment['attachname']}")) + { + $cell_class = "bad_attachment"; + $title = $lang->error_not_found; + $checked = true; + } + elseif(!$attachment['pid'] && $attachment['dateuploaded'] < TIME_NOW-60*60*24 && $attachment['dateuploaded'] != 0) + { + $cell_class = "bad_attachment"; + $title = $lang->error_not_attached; + $checked = true; + } + else if(!$attachment['tid'] && $attachment['pid']) + { + $cell_class = "bad_attachment"; + $title = $lang->error_does_not_exist; + $checked = true; + } + else if($attachment['visible'] == 0) + { + $cell_class = "invisible_attachment"; + } + + if($cell_class) + { + $cell_class .= " align_center"; + } + else + { + $cell_class = "align_center"; + } + + if($use_form == true && is_object($form)) + { + $table->construct_cell($form->generate_check_box('aids[]', $attachment['aid'], '', array('checked' => $checked))); + } + $table->construct_cell(get_attachment_icon(get_extension($attachment['filename'])), array('width' => 1)); + $table->construct_cell("{$attachment['filename']}"); + $table->construct_cell(get_friendly_size($attachment['filesize']), array('class' => $cell_class)); + + if($attachment['user_username']) + { + $attachment['username'] = $attachment['username']; + } + $table->construct_cell(build_profile_link($attachment['username'], $attachment['uid'], "_blank"), array("class" => "align_center")); + $table->construct_cell("".htmlspecialchars_uni($attachment['subject'])."", array("class" => "align_center")); + $table->construct_cell(my_number_format($attachment['downloads']), array("class" => "align_center")); + if($attachment['dateuploaded'] > 0) + { + $date = my_date('relative', $attachment['dateuploaded']); + } + else + { + $date = $lang->unknown; + } + $table->construct_cell($date, array("class" => "align_center")); + $table->construct_row(); +} diff --git a/Upload/admin/modules/forum/index.html b/Upload/admin/modules/forum/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/modules/forum/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/modules/forum/management.php b/Upload/admin/modules/forum/management.php new file mode 100644 index 0000000..5d936f6 --- /dev/null +++ b/Upload/admin/modules/forum/management.php @@ -0,0 +1,2894 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->forum_management, "index.php?module=forum-management"); + +if($mybb->input['action'] == "add" || $mybb->input['action'] == "edit" || $mybb->input['action'] == "copy" || $mybb->input['action'] == "permissions" || !$mybb->input['action']) +{ + if(!empty($mybb->input['fid']) && ($mybb->input['action'] == "management" || $mybb->input['action'] == "edit" || $mybb->input['action'] == "copy" || !$mybb->input['action'])) + { + $sub_tabs['view_forum'] = array( + 'title' => $lang->view_forum, + 'link' => "index.php?module=forum-management&fid=".$mybb->input['fid'], + 'description' => $lang->view_forum_desc + ); + + $sub_tabs['add_child_forum'] = array( + 'title' => $lang->add_child_forum, + 'link' => "index.php?module=forum-management&action=add&pid=".$mybb->input['fid'], + 'description' => $lang->view_forum_desc + ); + + $sub_tabs['edit_forum_settings'] = array( + 'title' => $lang->edit_forum_settings, + 'link' => "index.php?module=forum-management&action=edit&fid=".$mybb->input['fid'], + 'description' => $lang->edit_forum_settings_desc + ); + + $sub_tabs['copy_forum'] = array( + 'title' => $lang->copy_forum, + 'link' => "index.php?module=forum-management&action=copy&fid=".$mybb->input['fid'], + 'description' => $lang->copy_forum_desc + ); + } + else + { + $sub_tabs['forum_management'] = array( + 'title' => $lang->forum_management, + 'link' => "index.php?module=forum-management", + 'description' => $lang->forum_management_desc + ); + + $sub_tabs['add_forum'] = array( + 'title' => $lang->add_forum, + 'link' => "index.php?module=forum-management&action=add", + 'description' => $lang->add_forum_desc + ); + } +} + +$plugins->run_hooks("admin_forum_management_begin"); + +if($mybb->input['action'] == "copy") +{ + $plugins->run_hooks("admin_forum_management_copy"); + + if($mybb->request_method == "post") + { + $from = (int)$mybb->input['from']; + $to = (int)$mybb->input['to']; + + // Find the source forum + $query = $db->simple_select("forums", '*', "fid='{$from}'"); + $from_forum = $db->fetch_array($query); + if(!$db->num_rows($query)) + { + $errors[] = $lang->error_invalid_source_forum; + } + + if($to == -1) + { + // Create a new forum + if(empty($mybb->input['title'])) + { + $errors[] = $lang->error_new_forum_needs_name; + } + + if($mybb->input['pid'] == -1 && $mybb->input['type'] == 'f') + { + $errors[] = $lang->error_no_parent; + } + + if(!$errors) + { + $new_forum = $from_forum; + unset($new_forum['fid'], $new_forum['threads'], $new_forum['posts'], $new_forum['lastpost'], $new_forum['lastposter'], $new_forum['lastposteruid'], $new_forum['lastposttid'], $new_forum['lastpostsubject'], $new_forum['unapprovedthreads'], $new_forum['unapprovedposts']); + $new_forum['name'] = $db->escape_string($mybb->input['title']); + $new_forum['description'] = $db->escape_string($mybb->input['description']); + $new_forum['type'] = $db->escape_string($mybb->input['type']); + $new_forum['pid'] = $mybb->get_input('pid', 1); + $new_forum['rulestitle'] = $db->escape_string($new_forum['rulestitle']); + $new_forum['rules'] = $db->escape_string($new_forum['rules']); + $new_forum['parentlist'] = ''; + + $to = $db->insert_query("forums", $new_forum); + + // Generate parent list + $parentlist = make_parent_list($to); + $updatearray = array( + 'parentlist' => $parentlist + ); + $db->update_query("forums", $updatearray, "fid='{$to}'"); + } + } + elseif($mybb->input['copyforumsettings'] == 1) + { + // Copy settings to existing forum + $query = $db->simple_select("forums", '*', "fid='{$to}'"); + $to_forum = $db->fetch_array($query); + if(!$db->num_rows($query)) + { + $errors[] = $lang->error_invalid_destination_forum; + } + + if(!$errors) + { + $new_forum = $from_forum; + unset($new_forum['fid'], $new_forum['threads'], $new_forum['posts'], $new_forum['lastpost'], $new_forum['lastposter'], $new_forum['lastposteruid'], $new_forum['lastposttid'], $new_forum['lastpostsubject'], $new_forum['unapprovedthreads'], $new_forum['unapprovedposts']); + $new_forum['name'] = $db->escape_string($to_forum['name']); + $new_forum['description'] = $db->escape_string($to_forum['description']); + $new_forum['pid'] = $db->escape_string($to_forum['pid']); + $new_forum['parentlist'] = $db->escape_string($to_forum['parentlist']); + $new_forum['rulestitle'] = $db->escape_string($new_forum['rulestitle']); + $new_forum['rules'] = $db->escape_string($new_forum['rules']); + + $db->update_query("forums", $new_forum, "fid='{$to}'"); + } + } + + if(!$errors) + { + // Copy permissions + if(is_array($mybb->input['copygroups']) && count($mybb->input['copygroups'] > 0)) + { + foreach($mybb->input['copygroups'] as $gid) + { + $groups[] = (int)$gid; + } + $groups = implode(',', $groups); + $query = $db->simple_select("forumpermissions", '*', "fid='{$from}' AND gid IN ({$groups})"); + $db->delete_query("forumpermissions", "fid='{$to}' AND gid IN ({$groups})", 1); + while($permissions = $db->fetch_array($query)) + { + unset($permissions['pid']); + $permissions['fid'] = $to; + + $db->insert_query("forumpermissions", $permissions); + } + + // Log admin action + log_admin_action($from, $from_forum['name'], $to, $new_forum['name'], $groups); + } + else + { + // Log admin action (no group permissions) + log_admin_action($from, $from_forum['name'], $to, $new_forum['name']); + } + + $plugins->run_hooks("admin_forum_management_copy_commit"); + + $cache->update_forums(); + $cache->update_forumpermissions(); + + flash_message($lang->success_forum_copied, 'success'); + admin_redirect("index.php?module=forum-management&action=edit&fid={$to}"); + } + } + + $page->add_breadcrumb_item($lang->copy_forum); + $page->output_header($lang->copy_forum); + $page->output_nav_tabs($sub_tabs, 'copy_forum'); + + $form = new Form("index.php?module=forum-management&action=copy", "post"); + + if($errors) + { + $page->output_inline_error($errors); + $copy_data = $mybb->input; + } + else + { + $copy_data['type'] = "f"; + $copy_data['title'] = ""; + $copy_data['description'] = ""; + + if(!$mybb->input['pid']) + { + $copy_data['pid'] = "-1"; + } + else + { + $copy_data['pid'] = $mybb->get_input('pid', 1); + } + $copy_data['disporder'] = "1"; + $copy_data['from'] = $mybb->input['fid']; + $copy_data['copyforumsettings'] = 0; + $copy_data['pid'] = 0; + } + + $types = array( + 'f' => $lang->forum, + 'c' => $lang->category + ); + + $create_a_options_f = array( + 'id' => 'forum' + ); + + $create_a_options_c = array( + 'id' => 'category' + ); + + if($copy_data['type'] == "f") + { + $create_a_options_f['checked'] = true; + } + else + { + $create_a_options_c['checked'] = true; + } + + $usergroups = array(); + + $query = $db->simple_select("usergroups", "gid, title", "gid != '1'", array('order_by' => 'title')); + while($usergroup = $db->fetch_array($query)) + { + $usergroups[$usergroup['gid']] = $usergroup['title']; + } + + $form_container = new FormContainer($lang->copy_forum); + $form_container->output_row($lang->source_forum." *", $lang->source_forum_desc, $form->generate_forum_select('from', $copy_data['from'], array('id' => 'from')), 'from'); + $form_container->output_row($lang->destination_forum." *", $lang->destination_forum_desc, $form->generate_forum_select('to', $copy_data['to'], array('id' => 'to', 'main_option' => $lang->copy_to_new_forum)), 'to'); + $form_container->output_row($lang->copy_settings_and_properties, $lang->copy_settings_and_properties_desc, $form->generate_yes_no_radio('copyforumsettings', $copy_data['copyforumsettings'])); + $form_container->output_row($lang->copy_user_group_permissions, $lang->copy_user_group_permissions_desc, $form->generate_select_box('copygroups[]', $usergroups, $mybb->input['copygroups'], array('id' => 'copygroups', 'multiple' => true, 'size' => 5)), 'copygroups'); + + $form_container->end(); + + $form_container = new FormContainer($lang->new_forum_settings); + $form_container->output_row($lang->forum_type, $lang->forum_type_desc, $form->generate_radio_button('type', 'f', $lang->forum, $create_a_options_f)."
\n".$form->generate_radio_button('type', 'c', $lang->category, $create_a_options_c)); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $copy_data['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->description, "", $form->generate_text_area('description', $copy_data['description'], array('id' => 'description')), 'description'); + $form_container->output_row($lang->parent_forum." *", $lang->parent_forum_desc, $form->generate_forum_select('pid', $copy_data['pid'], array('id' => 'pid', 'main_option' => $lang->none)), 'pid'); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->copy_forum); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "editmod") +{ + $query = $db->simple_select("moderators", "*", "mid='".$mybb->get_input('mid', 1)."'"); + $mod_data = $db->fetch_array($query); + + if(!$mod_data['id']) + { + flash_message($lang->error_incorrect_moderator, 'error'); + admin_redirect("index.php?module=forum-management"); + } + + $plugins->run_hooks("admin_forum_management_editmod"); + + if($mod_data['isgroup']) + { + $fieldname = "title"; + } + else + { + $fieldname = "username"; + } + + if($mybb->request_method == "post") + { + $mid = $mybb->get_input('mid', 1); + if(!$mid) + { + flash_message($lang->error_incorrect_moderator, 'error'); + admin_redirect("index.php?module=forum-management"); + } + + if(!$errors) + { + $fid = $mybb->get_input('fid', 1); + $forum = get_forum($fid); + if($mod_data['isgroup']) + { + $mod = $groupscache[$mod_data['id']]; + } + else + { + $mod = get_user($mod_data['id']); + } + $update_array = array( + 'fid' => (int)$fid, + 'caneditposts' => (int)$mybb->input['caneditposts'], + 'cansoftdeleteposts' => (int)$mybb->input['cansoftdeleteposts'], + 'canrestoreposts' => (int)$mybb->input['canrestoreposts'], + 'candeleteposts' => (int)$mybb->input['candeleteposts'], + 'cansoftdeletethreads' => (int)$mybb->input['cansoftdeletethreads'], + 'canrestorethreads' => (int)$mybb->input['canrestorethreads'], + 'candeletethreads' => (int)$mybb->input['candeletethreads'], + 'canviewips' => (int)$mybb->input['canviewips'], + 'canviewunapprove' => (int)$mybb->input['canviewunapprove'], + 'canviewdeleted' => (int)$mybb->input['canviewdeleted'], + 'canopenclosethreads' => (int)$mybb->input['canopenclosethreads'], + 'canstickunstickthreads' => (int)$mybb->input['canstickunstickthreads'], + 'canapproveunapprovethreads' => (int)$mybb->input['canapproveunapprovethreads'], + 'canapproveunapproveposts' => (int)$mybb->input['canapproveunapproveposts'], + 'canapproveunapproveattachs' => (int)$mybb->input['canapproveunapproveattachs'], + 'canmanagethreads' => (int)$mybb->input['canmanagethreads'], + 'canmanagepolls' => (int)$mybb->input['canmanagepolls'], + 'canpostclosedthreads' => (int)$mybb->input['canpostclosedthreads'], + 'canmovetononmodforum' => (int)$mybb->input['canmovetononmodforum'], + 'canusecustomtools' => (int)$mybb->input['canusecustomtools'], + 'canmanageannouncements' => (int)$mybb->input['canmanageannouncements'], + 'canmanagereportedposts' => (int)$mybb->input['canmanagereportedposts'], + 'canviewmodlog' => (int)$mybb->input['canviewmodlog'] + ); + + $plugins->run_hooks("admin_forum_management_editmod_commit"); + + $db->update_query("moderators", $update_array, "mid='".$mybb->get_input('mid', 1)."'"); + + $cache->update_moderators(); + + // Log admin action + log_admin_action($fid, $forum['name'], $mid, $mod[$fieldname]); + + flash_message($lang->success_moderator_updated, 'success'); + admin_redirect("index.php?module=forum-management&fid=".$mybb->get_input('fid', 1)."#tab_moderators"); + } + } + + if($mod_data['isgroup']) + { + $query = $db->simple_select("usergroups", "title", "gid='{$mod_data['id']}'"); + $mod_data[$fieldname] = $db->fetch_field($query, 'title'); + } + else + { + $query = $db->simple_select("users", "username", "uid='{$mod_data['id']}'"); + $mod_data[$fieldname] = $db->fetch_field($query, 'username'); + } + + $sub_tabs = array(); + + $sub_tabs['edit_mod'] = array( + 'title' => $lang->edit_mod, + 'link' => "index.php?module=forum-management&action=editmod&mid=".$mybb->input['mid'], + 'description' => $lang->edit_mod_desc + ); + + $page->add_breadcrumb_item($lang->forum_moderators, "index.php?module=forum-management&fid={$mod_data['fid']}#tab_moderators"); + $page->add_breadcrumb_item($lang->edit_forum); + $page->output_header($lang->edit_mod); + $page->output_nav_tabs($sub_tabs, 'edit_mod'); + + $form = new Form("index.php?module=forum-management&action=editmod", "post"); + echo $form->generate_hidden_field("mid", $mod_data['mid']); + + if($errors) + { + $page->output_inline_error($errors); + $mod_data = $mybb->input; + } + + $form_container = new FormContainer($lang->sprintf($lang->edit_mod_for, $mod_data[$fieldname])); + $form_container->output_row($lang->forum, $lang->forum_desc, $form->generate_forum_select('fid', $mod_data['fid'], array('id' => 'fid')), 'fid'); + + $moderator_permissions = array( + $form->generate_check_box('caneditposts', 1, $lang->can_edit_posts, array('checked' => $mod_data['caneditposts'], 'id' => 'caneditposts')), + $form->generate_check_box('cansoftdeleteposts', 1, $lang->can_soft_delete_posts, array('checked' => $mod_data['cansoftdeleteposts'], 'id' => 'cansoftdeleteposts')), + $form->generate_check_box('canrestoreposts', 1, $lang->can_restore_posts, array('checked' => $mod_data['canrestoreposts'], 'id' => 'canrestoreposts')), + $form->generate_check_box('candeleteposts', 1, $lang->can_delete_posts, array('checked' => $mod_data['candeleteposts'], 'id' => 'candeleteposts')), + $form->generate_check_box('cansoftdeletethreads', 1, $lang->can_soft_delete_threads, array('checked' => $mod_data['cansoftdeletethreads'], 'id' => 'cansoftdeletethreads')), + $form->generate_check_box('canrestorethreads', 1, $lang->can_restore_threads, array('checked' => $mod_data['canrestorethreads'], 'id' => 'canrestorethreads')), + $form->generate_check_box('candeletethreads', 1, $lang->can_delete_threads, array('checked' => $mod_data['candeletethreads'], 'id' => 'candeletethreads')), + $form->generate_check_box('canviewips', 1, $lang->can_view_ips, array('checked' => $mod_data['canviewips'], 'id' => 'canviewips')), + $form->generate_check_box('canviewunapprove', 1, $lang->can_view_unapprove, array('checked' => $mod_data['canviewunapprove'], 'id' => 'canviewunapprove')), + $form->generate_check_box('canviewdeleted', 1, $lang->can_view_deleted, array('checked' => $mod_data['canviewdeleted'], 'id' => 'canviewdeleted')), + $form->generate_check_box('canopenclosethreads', 1, $lang->can_open_close_threads, array('checked' => $mod_data['canopenclosethreads'], 'id' => 'canopenclosethreads')), + $form->generate_check_box('canstickunstickthreads', 1, $lang->can_stick_unstick_threads, array('checked' => $mod_data['canstickunstickthreads'], 'id' => 'canstickunstickthreads')), + $form->generate_check_box('canapproveunapprovethreads', 1, $lang->can_approve_unapprove_threads, array('checked' => $mod_data['canapproveunapprovethreads'], 'id' => 'canapproveunapprovethreads')), + $form->generate_check_box('canapproveunapproveposts', 1, $lang->can_approve_unapprove_posts, array('checked' => $mod_data['canapproveunapproveposts'], 'id' => 'canapproveunapproveposts')), + $form->generate_check_box('canapproveunapproveattachs', 1, $lang->can_approve_unapprove_attachments, array('checked' => $mod_data['canapproveunapproveattachs'], 'id' => 'canapproveunapproveattachs')), + $form->generate_check_box('canmanagethreads', 1, $lang->can_manage_threads, array('checked' => $mod_data['canmanagethreads'], 'id' => 'canmanagethreads')), + $form->generate_check_box('canmanagepolls', 1, $lang->can_manage_polls, array('checked' => $mod_data['canmanagepolls'], 'id' => 'canmanagepolls')), + $form->generate_check_box('canpostclosedthreads', 1, $lang->can_post_closed_threads, array('checked' => $mod_data['canpostclosedthreads'], 'id' => 'canpostclosedthreads')), + $form->generate_check_box('canmovetononmodforum', 1, $lang->can_move_to_other_forums, array('checked' => $mod_data['canmovetononmodforum'], 'id' => 'canmovetononmodforum')), + $form->generate_check_box('canusecustomtools', 1, $lang->can_use_custom_tools, array('checked' => $mod_data['canusecustomtools'], 'id' => 'canusecustomtools')) + ); + $form_container->output_row($lang->moderator_permissions, "", "
".implode("
", $moderator_permissions)."
"); + + $moderator_cp_permissions = array( + $form->generate_check_box('canmanageannouncements', 1, $lang->can_manage_announcements, array('checked' => $mod_data['canmanageannouncements'], 'id' => 'canmanageannouncements')), + $form->generate_check_box('canmanagereportedposts', 1, $lang->can_manage_reported_posts, array('checked' => $mod_data['canmanagereportedposts'], 'id' => 'canmanagereportedposts')), + $form->generate_check_box('canviewmodlog', 1, $lang->can_view_mod_log, array('checked' => $mod_data['canviewmodlog'], 'id' => 'canviewmodlog')) + ); + $form_container->output_row($lang->moderator_cp_permissions, $lang->moderator_cp_permissions_desc, "
".implode("
", $moderator_cp_permissions)."
"); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_mod); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "clear_permission") +{ + $pid = $mybb->get_input('pid', 1); + $fid = $mybb->get_input('fid', 1); + $gid = (int)$mybb->input['gid']; + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=forum-management&fid={$fid}"); + } + + $plugins->run_hooks("admin_forum_management_deletemod"); + + if($mybb->request_method == "post") + { + if((!$fid || !$gid) && $pid) + { + $query = $db->simple_select("forumpermissions", "fid, gid", "pid='{$pid}'"); + $result = $db->fetch_array($query); + $fid = $result['fid']; + $gid = $result['gid']; + } + + if($pid) + { + $db->delete_query("forumpermissions", "pid='{$pid}'"); + } + else + { + $db->delete_query("forumpermissions", "gid='{$gid}' AND fid='{$fid}'"); + } + + $cache->update_forumpermissions(); + + flash_message($lang->success_custom_permission_cleared, 'success'); + admin_redirect("index.php?module=forum-management&fid={$fid}#tab_permissions"); + } + else + { + $page->output_confirm_action("index.php?module=forum-management&action=clear_permission&pid={$pid}&gid={$gid}&fid={$fid}", $lang->confirm_clear_custom_permission); + } +} + +if($mybb->input['action'] == "permissions") +{ + $plugins->run_hooks("admin_forum_management_permissions"); + + if($mybb->request_method == "post") + { + $pid = $mybb->get_input('pid', 1); + $fid = $mybb->get_input('fid', 1); + $gid = (int)$mybb->input['gid']; + $forum = get_forum($fid); + + if((!$fid || !$gid) && $pid) + { + $query = $db->simple_select("forumpermissions", "fid, gid", "pid='{$pid}'"); + $result = $db->fetch_array($query); + $fid = $result['fid']; + $gid = $result['gid']; + $forum = get_forum($fid); + } + + $field_list = array(); + $fields_array = $db->show_fields_from("forumpermissions"); + if(is_array($mybb->input['permissions'])) + { + // User has set permissions for this group... + foreach($fields_array as $field) + { + if(strpos($field['Field'], 'can') !== false || strpos($field['Field'], 'mod') !== false) + { + if(array_key_exists($field['Field'], $mybb->input['permissions'])) + { + $update_array[$db->escape_string($field['Field'])] = (int)$mybb->input['permissions'][$field['Field']]; + } + else + { + $update_array[$db->escape_string($field['Field'])] = 0; + } + } + } + } + else + { + // Else, we assume that the group has no permissions... + foreach($fields_array as $field) + { + if(strpos($field['Field'], 'can') !== false || strpos($field['Field'], 'mod') !== false) + { + $update_array[$db->escape_string($field['Field'])] = 0; + } + } + } + + if($fid && !$pid) + { + $update_array['fid'] = $fid; + $update_array['gid'] = (int)$mybb->input['gid']; + $db->insert_query("forumpermissions", $update_array); + } + + $plugins->run_hooks("admin_forum_management_permissions_commit"); + + if(!($fid && !$pid)) + { + $db->update_query("forumpermissions", $update_array, "pid='{$pid}'"); + } + + $cache->update_forumpermissions(); + + // Log admin action + log_admin_action($fid, $forum['name']); + + if($mybb->input['ajax'] == 1) + { + echo json_encode(""); + die; + } + else + { + flash_message($lang->success_forum_permissions_saved, 'success'); + admin_redirect("index.php?module=forum-management&fid={$fid}#tab_permissions"); + } + } + + if($mybb->input['ajax'] != 1) + { + $sub_tabs = array(); + + if($mybb->input['fid'] && $mybb->input['gid']) + { + $sub_tabs['edit_permissions'] = array( + 'title' => $lang->forum_permissions, + 'link' => "index.php?module=forum-management&action=permissions&fid=".$mybb->input['fid']."&gid=".$mybb->input['gid'], + 'description' => $lang->forum_permissions_desc + ); + + $page->add_breadcrumb_item($lang->forum_permissions2, "index.php?module=forum-management&fid=".$mybb->input['fid']."#tab_permissions"); + } + else + { + $query = $db->simple_select("forumpermissions", "fid", "pid='".$mybb->get_input('pid', 1)."'"); + $mybb->input['fid'] = $db->fetch_field($query, "fid"); + + $sub_tabs['edit_permissions'] = array( + 'title' => $lang->forum_permissions, + 'link' => "index.php?module=forum-management&action=permissions&pid=".$mybb->get_input('pid', 1), + 'description' => $lang->forum_permissions_desc + ); + + $page->add_breadcrumb_item($lang->forum_permissions2, "index.php?module=forum-management&fid=".$mybb->input['fid']."#tab_permissions"); + } + + $page->add_breadcrumb_item($lang->forum_permissions); + $page->output_header($lang->forum_permissions); + $page->output_nav_tabs($sub_tabs, 'edit_permissions'); + } + else + { + echo " +
+ \n + +
"; + } + + if($mybb->input['pid'] || ($mybb->input['gid'] && $mybb->input['fid'])) + { + if($mybb->input['ajax'] != 1) + { + $form = new Form("index.php?module=forum-management&action=permissions", "post"); + } + else + { + $form = new Form("index.php?module=forum-management&action=permissions&ajax=1&pid=".$mybb->get_input('pid', 1)."&gid=".(int)$mybb->input['gid']."&fid=".(int)$mybb->input['gid'], "post", "modal_form"); + } + echo $form->generate_hidden_field("usecustom", "1"); + + if($errors) + { + $page->output_inline_error($errors); + $permission_data = $mybb->input; + + $query = $db->simple_select("usergroups", "*", "gid='{$permission_data['gid']}'"); + $usergroup = $db->fetch_array($query); + + $query = $db->simple_select("forums", "*", "fid='{$permission_data['fid']}'"); + $forum = $db->fetch_array($query); + } + else + { + $pid = $mybb->get_input('pid', 1); + $gid = (int)$mybb->input['gid']; + $fid = $mybb->get_input('fid', 1); + + if($pid) + { + $query = $db->simple_select("forumpermissions", "*", "pid='{$pid}'"); + } + else + { + $query = $db->simple_select("forumpermissions", "*", "fid='{$fid}' AND gid='{$gid}'", array('limit' => 1)); + } + + $permission_data = $db->fetch_array($query); + + if(!$fid) + { + $fid = $permission_data['fid']; + } + + if(!$gid) + { + $gid = $permission_data['gid']; + } + + if(!$pid) + { + $pid = $permission_data['pid']; + } + + $query = $db->simple_select("usergroups", "*", "gid='$gid'"); + $usergroup = $db->fetch_array($query); + + $query = $db->simple_select("forums", "*", "fid='$fid'"); + $forum = $db->fetch_array($query); + + $sperms = $permission_data; + + $sql = build_parent_list($fid); + $query = $db->simple_select("forumpermissions", "*", "$sql AND gid='$gid'"); + $customperms = $db->fetch_array($query); + + if($permission_data['pid']) + { + $permission_data['usecustom'] = 1; + echo $form->generate_hidden_field("pid", $pid); + } + else + { + echo $form->generate_hidden_field("fid", $fid); + echo $form->generate_hidden_field("gid", $gid); + if(!$customperms['pid']) + { + $permission_data = usergroup_permissions($gid); + } + else + { + $permission_data = forum_permissions($fid, 0, $gid); + } + } + } + + $groups = array( + 'canviewthreads' => 'viewing', + 'canview' => 'viewing', + 'canonlyviewownthreads' => 'viewing', + 'candlattachments' => 'viewing', + + 'canpostthreads' => 'posting_rating', + 'canpostreplys' => 'posting_rating', + 'canonlyreplyownthreads' => 'posting_rating', + 'canpostattachments' => 'posting_rating', + 'canratethreads' => 'posting_rating', + + 'caneditposts' => 'editing', + 'candeleteposts' => 'editing', + 'candeletethreads' => 'editing', + 'caneditattachments' => 'editing', + + 'modposts' => 'moderate', + 'modthreads' => 'moderate', + 'modattachments' => 'moderate', + 'mod_edit_posts' => 'moderate', + + 'canpostpolls' => 'polls', + 'canvotepolls' => 'polls', + 'cansearch' => 'misc', + ); + + $groups = $plugins->run_hooks("admin_forum_management_permission_groups", $groups); + + $tabs = array(); + foreach(array_unique(array_values($groups)) as $group) + { + $lang_group = "group_".$group; + $tabs[$group] = $lang->$lang_group; + } + + if($mybb->input['ajax'] == 1) + { + $page->output_tab_control($tabs, false, "tabs2"); + } + else + { + $page->output_tab_control($tabs); + } + + $field_list = array(); + $fields_array = $db->show_fields_from("forumpermissions"); + foreach($fields_array as $field) + { + if(strpos($field['Field'], 'can') !== false || strpos($field['Field'], 'mod') !== false) + { + if(array_key_exists($field['Field'], $groups)) + { + $field_list[$groups[$field['Field']]][] = $field['Field']; + } + else + { + $field_list['misc'][] = $field['Field']; + } + } + } + + foreach(array_unique(array_values($groups)) as $group) + { + $lang_group = "group_".$group; + echo "
\n"; + $form_container = new FormContainer("\"".htmlspecialchars_uni($usergroup['title'])."\" {$lang->custom_permissions_for} \"".htmlspecialchars_uni($forum['name'])."\""); + $fields = array(); + foreach($field_list[$group] as $field) + { + $lang_field = $group."_field_".$field; + $fields[] = $form->generate_check_box("permissions[{$field}]", 1, $lang->$lang_field, array('checked' => $permission_data[$field], 'id' => $field)); + } + $form_container->output_row("", "", "
".implode("
", $fields)."
"); + $form_container->end(); + echo "
"; + } + + if($mybb->input['ajax'] == 1) + { + $buttons[] = $form->generate_submit_button($lang->cancel, array('onclick' => '$.modal.close(); return false;')); + $buttons[] = $form->generate_submit_button($lang->save_permissions, array('id' => 'savePermissions')); + $form->output_submit_wrapper($buttons); + $form->end(); + echo "
"; + echo "
"; + } + else + { + $buttons[] = $form->generate_submit_button($lang->save_permissions); + $form->output_submit_wrapper($buttons); + + $form->end(); + } + } + + if($mybb->input['ajax'] != 1) + { + $page->output_footer(); + } +} + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_forum_management_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + $pid = $mybb->get_input('pid', 1); + $type = $mybb->input['type']; + + if($pid <= 0 && $type == "f") + { + $errors[] = $lang->error_no_parent; + } + + if(!$errors) + { + if($pid < 0) + { + $pid = 0; + } + $insert_array = array( + "name" => $db->escape_string($mybb->input['title']), + "description" => $db->escape_string($mybb->input['description']), + "linkto" => $db->escape_string($mybb->input['linkto']), + "type" => $db->escape_string($type), + "pid" => $pid, + "parentlist" => '', + "disporder" => (int)$mybb->input['disporder'], + "active" => (int)$mybb->input['active'], + "open" => (int)$mybb->input['open'], + "allowhtml" => (int)$mybb->input['allowhtml'], + "allowmycode" => (int)$mybb->input['allowmycode'], + "allowsmilies" => (int)$mybb->input['allowsmilies'], + "allowimgcode" => (int)$mybb->input['allowimgcode'], + "allowvideocode" => (int)$mybb->input['allowvideocode'], + "allowpicons" => (int)$mybb->input['allowpicons'], + "allowtratings" => (int)$mybb->input['allowtratings'], + "usepostcounts" => (int)$mybb->input['usepostcounts'], + "usethreadcounts" => (int)$mybb->input['usethreadcounts'], + "requireprefix" => (int)$mybb->input['requireprefix'], + "password" => $db->escape_string($mybb->input['password']), + "showinjump" => (int)$mybb->input['showinjump'], + "style" => (int)$mybb->input['style'], + "overridestyle" => (int)$mybb->input['overridestyle'], + "rulestype" => (int)$mybb->input['rulestype'], + "rulestitle" => $db->escape_string($mybb->input['rulestitle']), + "rules" => $db->escape_string($mybb->input['rules']), + "defaultdatecut" => (int)$mybb->input['defaultdatecut'], + "defaultsortby" => $db->escape_string($mybb->input['defaultsortby']), + "defaultsortorder" => $db->escape_string($mybb->input['defaultsortorder']), + ); + $fid = $db->insert_query("forums", $insert_array); + + $parentlist = make_parent_list($fid); + $db->update_query("forums", array("parentlist" => $parentlist), "fid='$fid'"); + + $inherit = $mybb->input['default_permissions']; + + foreach($mybb->input as $id => $permission) + { + if(strpos($id, 'fields_') === false) + { + continue; + } + + list(, $gid) = explode('fields_', $id); + + // If it isn't an array then it came from the javascript form + if(!is_array($permission)) + { + $permission = explode(',', $permission); + $permission = array_flip($permission); + foreach($permission as $name => $value) + { + $permission[$name] = 1; + } + } + + foreach(array('canview','canpostthreads','canpostreplys','canpostpolls') as $name) + { + if(in_array($name, $permission) || $permission[$name]) + { + $permissions[$name][$gid] = 1; + } + else + { + $permissions[$name][$gid] = 0; + } + } + } + + $canview = $permissions['canview']; + $canpostthreads = $permissions['canpostthreads']; + $canpostpolls = $permissions['canpostpolls']; + $canpostattachments = $permissions['canpostattachments']; + $canpostreplies = $permissions['canpostreplys']; + save_quick_perms($fid); + + $plugins->run_hooks("admin_forum_management_add_commit"); + + $cache->update_forums(); + + // Log admin action + log_admin_action($fid, $insert_array['name']); + + flash_message($lang->success_forum_added, 'success'); + admin_redirect("index.php?module=forum-management"); + } + } + + $page->extra_header .= "\n"; + + $page->add_breadcrumb_item($lang->add_forum); + $page->output_header($lang->add_forum); + $page->output_nav_tabs($sub_tabs, 'add_forum'); + + $form = new Form("index.php?module=forum-management&action=add", "post"); + + if($errors) + { + $page->output_inline_error($errors); + $forum_data = $mybb->input; + } + else + { + $forum_data['type'] = "f"; + $forum_data['title'] = ""; + $forum_data['description'] = ""; + + if(!$mybb->input['pid']) + { + $forum_data['pid'] = "-1"; + } + else + { + $forum_data['pid'] = $mybb->get_input('pid', 1); + } + $forum_data['disporder'] = "1"; + $forum_data['linkto'] = ""; + $forum_data['password'] = ""; + $forum_data['active'] = 1; + $forum_data['open'] = 1; + $forum_data['overridestyle'] = ""; + $forum_data['style'] = ""; + $forum_data['rulestype'] = ""; + $forum_data['rulestitle'] = ""; + $forum_data['rules'] = ""; + $forum_data['defaultdatecut'] = ""; + $forum_data['defaultsortby'] = ""; + $forum_data['defaultsortorder'] = ""; + $forum_data['allowhtml'] = ""; + $forum_data['allowmycode'] = 1; + $forum_data['allowsmilies'] = 1; + $forum_data['allowimgcode'] = 1; + $forum_data['allowvideocode'] = 1; + $forum_data['allowpicons'] = 1; + $forum_data['allowtratings'] = 1; + $forum_data['showinjump'] = 1; + $forum_data['usepostcounts'] = 1; + $forum_data['usethreadcounts'] = 1; + $forum_data['requireprefix'] = 0; + } + + $types = array( + 'f' => $lang->forum, + 'c' => $lang->category + ); + + $create_a_options_f = array( + 'id' => 'forum' + ); + + $create_a_options_c = array( + 'id' => 'category' + ); + + if($forum_data['type'] == "f") + { + $create_a_options_f['checked'] = true; + } + else + { + $create_a_options_c['checked'] = true; + } + + $form_container = new FormContainer($lang->add_forum); + $form_container->output_row($lang->forum_type, $lang->forum_type_desc, $form->generate_radio_button('type', 'f', $lang->forum, $create_a_options_f)."
\n".$form->generate_radio_button('type', 'c', $lang->category, $create_a_options_c)); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $forum_data['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->description, "", $form->generate_text_area('description', $forum_data['description'], array('id' => 'description')), 'description'); + $form_container->output_row($lang->parent_forum." *", $lang->parent_forum_desc, $form->generate_forum_select('pid', $forum_data['pid'], array('id' => 'pid', 'main_option' => $lang->none)), 'pid'); + $form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $forum_data['disporder'], array('id' => 'disporder')), 'disporder'); + $form_container->end(); + + echo ""; + echo "
"; + $form_container = new FormContainer("".$lang->additional_forum_options); + $form_container->output_row($lang->forum_link, $lang->forum_link_desc, $form->generate_text_box('linkto', $forum_data['linkto'], array('id' => 'linkto')), 'linkto'); + $form_container->output_row($lang->forum_password, $lang->forum_password_desc, $form->generate_text_box('password', $forum_data['password'], array('id' => 'password')), 'password'); + + $access_options = array( + $form->generate_check_box('active', 1, $lang->forum_is_active."
\n{$lang->forum_is_active_desc}", array('checked' => $forum_data['active'], 'id' => 'active')), + $form->generate_check_box('open', 1, $lang->forum_is_open."
\n{$lang->forum_is_open_desc}", array('checked' => $forum_data['open'], 'id' => 'open')) + ); + + $form_container->output_row($lang->access_options, "", "
".implode("
", $access_options)."
"); + + $styles = array( + '0' => $lang->use_default + ); + + $query = $db->simple_select("themes", "tid,name", "name!='((master))' AND name!='((master-backup))'", array('order_by' => 'name')); + while($style = $db->fetch_array($query)) + { + $styles[$style['tid']] = htmlspecialchars_uni($style['name']); + } + + $style_options = array( + $form->generate_check_box('overridestyle', 1, $lang->override_user_style, array('checked' => $forum_data['overridestyle'], 'id' => 'overridestyle')), + $lang->forum_specific_style."
\n".$form->generate_select_box('style', $styles, $forum_data['style'], array('id' => 'style')) + ); + + $form_container->output_row($lang->style_options, "", "
".implode("
", $style_options)."
"); + + $display_methods = array( + '0' => $lang->dont_display_rules, + '1' => $lang->display_rules_inline, + '3' => $lang->display_rules_inline_new, + '2' => $lang->display_rules_link + ); + + $forum_rules = array( + $lang->display_method."
\n".$form->generate_select_box('rulestype', $display_methods, $forum_data['rulestype'], array('checked' => $forum_data['rulestype'], 'id' => 'rulestype')), + $lang->title."
\n".$form->generate_text_box('rulestitle', $forum_data['rulestitle'], array('checked' => $forum_data['rulestitle'], 'id' => 'rulestitle')), + $lang->rules."
\n".$form->generate_text_area('rules', $forum_data['rules'], array('checked' => $forum_data['rules'], 'id' => 'rules')) + ); + + $form_container->output_row($lang->forum_rules, "", "
".implode("
", $forum_rules)."
"); + + $default_date_cut = array( + 0 => $lang->board_default, + 1 => $lang->datelimit_1day, + 5 => $lang->datelimit_5days, + 10 => $lang->datelimit_10days, + 20 => $lang->datelimit_20days, + 50 => $lang->datelimit_50days, + 75 => $lang->datelimit_75days, + 100 => $lang->datelimit_100days, + 365 => $lang->datelimit_lastyear, + 9999 => $lang->datelimit_beginning, + ); + + $default_sort_by = array( + "" => $lang->board_default, + "subject" => $lang->sort_by_subject, + "lastpost" => $lang->sort_by_lastpost, + "starter" => $lang->sort_by_starter, + "started" => $lang->sort_by_started, + "rating" => $lang->sort_by_rating, + "replies" => $lang->sort_by_replies, + "views" => $lang->sort_by_views, + ); + + $default_sort_order = array( + "" => $lang->board_default, + "asc" => $lang->sort_order_asc, + "desc" => $lang->sort_order_desc, + ); + + $view_options = array( + $lang->default_date_cut."
\n".$form->generate_select_box('defaultdatecut', $default_date_cut, $forum_data['defaultdatecut'], array('checked' => $forum_data['defaultdatecut'], 'id' => 'defaultdatecut')), + $lang->default_sort_by."
\n".$form->generate_select_box('defaultsortby', $default_sort_by, $forum_data['defaultsortby'], array('checked' => $forum_data['defaultsortby'], 'id' => 'defaultsortby')), + $lang->default_sort_order."
\n".$form->generate_select_box('defaultsortorder', $default_sort_order, $forum_data['defaultsortorder'], array('checked' => $forum_data['defaultsortorder'], 'id' => 'defaultsortorder')), + ); + + $form_container->output_row($lang->default_view_options, "", "
".implode("
", $view_options)."
"); + + $misc_options = array( + $form->generate_check_box('allowhtml', 1, $lang->allow_html, array('checked' => $forum_data['allowhtml'], 'id' => 'allowhtml')), + $form->generate_check_box('allowmycode', 1, $lang->allow_mycode, array('checked' => $forum_data['allowmycode'], 'id' => 'allowmycode')), + $form->generate_check_box('allowsmilies', 1, $lang->allow_smilies, array('checked' => $forum_data['allowsmilies'], 'id' => 'allowsmilies')), + $form->generate_check_box('allowimgcode', 1, $lang->allow_img_code, array('checked' => $forum_data['allowimgcode'], 'id' => 'allowimgcode')), + $form->generate_check_box('allowvideocode', 1, $lang->allow_video_code, array('checked' => $forum_data['allowvideocode'], 'id' => 'allowvideocode')), + $form->generate_check_box('allowpicons', 1, $lang->allow_post_icons, array('checked' => $forum_data['allowpicons'], 'id' => 'allowpicons')), + $form->generate_check_box('allowtratings', 1, $lang->allow_thread_ratings, array('checked' => $forum_data['allowtratings'], 'id' => 'allowtratings')), + $form->generate_check_box('showinjump', 1, $lang->show_forum_jump, array('checked' => $forum_data['showinjump'], 'id' => 'showinjump')), + $form->generate_check_box('usepostcounts', 1, $lang->use_postcounts, array('checked' => $forum_data['usepostcounts'], 'id' => 'usepostcounts')), + $form->generate_check_box('usethreadcounts', 1, $lang->use_threadcounts, array('checked' => $forum_data['usethreadcounts'], 'id' => 'usethreadcounts')), + $form->generate_check_box('requireprefix', 1, $lang->require_thread_prefix, array('checked' => $forum_data['requireprefix'], 'id' => 'requireprefix')) + ); + + $form_container->output_row($lang->misc_options, "", "
".implode("
", $misc_options)."
"); + $form_container->end(); + echo "
"; + + $query = $db->simple_select("usergroups", "*", "", array("order" => "name")); + while($usergroup = $db->fetch_array($query)) + { + $usergroups[$usergroup['gid']] = $usergroup; + } + + $cached_forum_perms = $cache->read("forumpermissions"); + $field_list = array( + 'canview' => $lang->permissions_canview, + 'canpostthreads' => $lang->permissions_canpostthreads, + 'canpostreplys' => $lang->permissions_canpostreplys, + 'canpostpolls' => $lang->permissions_canpostpolls, + ); + + $field_list2 = array( + 'canview' => $lang->perm_drag_canview, + 'canpostthreads' => $lang->perm_drag_canpostthreads, + 'canpostreplys' => $lang->perm_drag_canpostreplys, + 'canpostpolls' => $lang->perm_drag_canpostpolls, + ); + + $ids = array(); + + $form_container = new FormContainer($lang->forum_permissions); + $form_container->output_row_header($lang->permissions_group, array("class" => "align_center", 'style' => 'width: 40%')); + $form_container->output_row_header($lang->overview_allowed_actions, array("class" => "align_center")); + $form_container->output_row_header($lang->overview_disallowed_actions, array("class" => "align_center")); + + if($mybb->request_method == "post") + { + foreach($usergroups as $usergroup) + { + if(isset($mybb->input['fields_'.$usergroup['gid']])) + { + $input_permissions = $mybb->input['fields_'.$usergroup['gid']]; + if(!is_array($input_permissions)) + { + // Convering the comma separated list from Javascript form into a variable + $input_permissions = explode(',' , $input_permissions); + } + foreach($input_permissions as $input_permission) + { + $mybb->input['permissions'][$usergroup['gid']][$input_permission] = 1; + } + } + } + } + + foreach($usergroups as $usergroup) + { + $perms = array(); + if(isset($mybb->input['default_permissions']) && $mybb->input['default_permissions'][$usergroup['gid']]) + { + if(is_array($existing_permissions) && $existing_permissions[$usergroup['gid']]) + { + $perms = $existing_permissions[$usergroup['gid']]; + $default_checked = false; + } + elseif(is_array($cached_forum_perms) && $cached_forum_perms[$forum_data['fid']][$usergroup['gid']]) + { + $perms = $cached_forum_perms[$forum_data['fid']][$usergroup['gid']]; + $default_checked = true; + } + else if(is_array($cached_forum_perms) && $cached_forum_perms[$forum_data['pid']][$usergroup['gid']]) + { + $perms = $cached_forum_perms[$forum_data['pid']][$usergroup['gid']]; + $default_checked = true; + } + } + + if(!$perms) + { + $perms = $usergroup; + $default_checked = true; + } + + foreach($field_list as $forum_permission => $forum_perm_title) + { + if(isset($mybb->input['permissions'])) + { + if($mybb->input['default_permissions'][$usergroup['gid']]) + { + $default_checked = true; + } + else + { + $default_checked = false; + } + + if($mybb->input['permissions'][$usergroup['gid']][$forum_permission]) + { + $perms_checked[$forum_permission] = 1; + } + else + { + $perms_checked[$forum_permission] = 0; + } + } + else + { + if($perms[$forum_permission] == 1) + { + $perms_checked[$forum_permission] = 1; + } + else + { + $perms_checked[$forum_permission] = 0; + } + } + } + $usergroup['title'] = htmlspecialchars_uni($usergroup['title']); + + if($default_checked) + { + $inherited_text = $lang->inherited_permission; + } + else + { + $inherited_text = $lang->custom_permission; + } + + $form_container->output_cell("{$usergroup['title']}
".$form->generate_check_box("default_permissions[{$usergroup['gid']}]", 1, "", array("id" => "default_permissions_{$usergroup['gid']}", "checked" => $default_checked, "onclick" => $default_click))." "); + + $field_select = "
\n"; + $field_select .= "
    \n"; + foreach($perms_checked as $perm => $value) + { + if($value == 1) + { + $field_select .= "
  • {$field_list2[$perm]}
  • "; + } + } + $field_select .= "
\n"; + $field_select .= "
    \n"; + foreach($perms_checked as $perm => $value) + { + if($value == 0) + { + $field_select .= "
  • {$field_list2[$perm]}
  • "; + } + } + $field_select .= "
\n"; + $field_select .= $form->generate_hidden_field("fields_".$usergroup['gid'], @implode(",", @array_keys($perms_checked, '1')), array('id' => 'fields_'.$usergroup['gid'])); + $field_select = str_replace("'", "\\'", $field_select); + $field_select = str_replace("\n", "", $field_select); + + $field_select = "\n"; + + $field_selected = array(); + foreach($field_list as $forum_permission => $permission_title) + { + $field_options[$forum_permission] = $permission_title; + if($perms_checked[$forum_permission]) + { + $field_selected[] = $forum_permission; + } + } + + $field_select .= "\n"; + $form_container->output_cell($field_select, array('colspan' => 2)); + + $form_container->construct_row(); + + $ids[] = $usergroup['gid']; + } + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_forum); + $form->output_submit_wrapper($buttons); + $form->end(); + + // Write in our JS based field selector + echo "\n"; + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit") +{ + if(!$mybb->input['fid']) + { + flash_message($lang->error_invalid_fid, 'error'); + admin_redirect("index.php?module=forum-management"); + } + + $query = $db->simple_select("forums", "*", "fid='{$mybb->input['fid']}'"); + $forum_data = $db->fetch_array($query); + if(!$forum_data) + { + flash_message($lang->error_invalid_fid, 'error'); + admin_redirect("index.php?module=forum-management"); + } + + $fid = $mybb->get_input('fid', 1); + + $plugins->run_hooks("admin_forum_management_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + $pid = $mybb->get_input('pid', 1); + + if($pid == $mybb->input['fid']) + { + $errors[] = $lang->error_forum_parent_itself; + } + else + { + $query = $db->simple_select("forums", "*", "pid='{$mybb->input['fid']}'"); + while($child = $db->fetch_array($query)) + { + if($child['fid'] == $pid) + { + $errors[] = $lang->error_forum_parent_child; + break; + } + } + } + + $type = $mybb->input['type']; + + if($pid <= 0 && $type == "f") + { + $errors[] = $lang->error_no_parent; + } + + if($type == 'c' && $forum_data['type'] == 'f') + { + $query = $db->simple_select('threads', 'COUNT(tid) as num_threads', "fid = '{$fid}'"); + if($db->fetch_field($query, "num_threads") > 0) + { + $errors[] = $lang->error_not_empty; + } + } + + if(!empty($mybb->input['linkto']) && empty($forum_data['linkto'])) + { + $query = $db->simple_select('threads', 'COUNT(tid) as num_threads', "fid = '{$fid}'", array("limit" => 1)); + if($db->fetch_field($query, "num_threads") > 0) + { + $errors[] = $lang->error_forum_link_not_empty; + } + } + + if(!$errors) + { + if($pid < 0) + { + $pid = 0; + } + $update_array = array( + "name" => $db->escape_string($mybb->input['title']), + "description" => $db->escape_string($mybb->input['description']), + "linkto" => $db->escape_string($mybb->input['linkto']), + "type" => $db->escape_string($type), + "pid" => $pid, + "disporder" => (int)$mybb->input['disporder'], + "active" => (int)$mybb->input['active'], + "open" => (int)$mybb->input['open'], + "allowhtml" => (int)$mybb->input['allowhtml'], + "allowmycode" => (int)$mybb->input['allowmycode'], + "allowsmilies" => (int)$mybb->input['allowsmilies'], + "allowimgcode" => (int)$mybb->input['allowimgcode'], + "allowvideocode" => (int)$mybb->input['allowvideocode'], + "allowpicons" => (int)$mybb->input['allowpicons'], + "allowtratings" => (int)$mybb->input['allowtratings'], + "usepostcounts" => (int)$mybb->input['usepostcounts'], + "usethreadcounts" => (int)$mybb->input['usethreadcounts'], + "requireprefix" => (int)$mybb->input['requireprefix'], + "password" => $db->escape_string($mybb->input['password']), + "showinjump" => (int)$mybb->input['showinjump'], + "style" => (int)$mybb->input['style'], + "overridestyle" => (int)$mybb->input['overridestyle'], + "rulestype" => (int)$mybb->input['rulestype'], + "rulestitle" => $db->escape_string($mybb->input['rulestitle']), + "rules" => $db->escape_string($mybb->input['rules']), + "defaultdatecut" => (int)$mybb->input['defaultdatecut'], + "defaultsortby" => $db->escape_string($mybb->input['defaultsortby']), + "defaultsortorder" => $db->escape_string($mybb->input['defaultsortorder']), + ); + $db->update_query("forums", $update_array, "fid='{$fid}'"); + if($pid != $forum_data['pid']) + { + // Update the parentlist of this forum. + $db->update_query("forums", array("parentlist" => make_parent_list($fid)), "fid='{$fid}'"); + + // Rebuild the parentlist of all of the subforums of this forum + switch($db->type) + { + case "sqlite": + case "pgsql": + $query = $db->simple_select("forums", "fid", "','||parentlist||',' LIKE '%,$fid,%'"); + break; + default: + $query = $db->simple_select("forums", "fid", "CONCAT(',',parentlist,',') LIKE '%,$fid,%'"); + } + + while($child = $db->fetch_array($query)) + { + $db->update_query("forums", array("parentlist" => make_parent_list($child['fid'])), "fid='{$child['fid']}'"); + } + } + + $inherit = $mybb->input['default_permissions']; + + foreach($mybb->input as $id => $permission) + { + // Make sure we're only skipping inputs that don't start with "fields_" and aren't fields_default_ or fields_inherit_ + if(strpos($id, 'fields_') === false || (strpos($id, 'fields_default_') !== false || strpos($id, 'fields_inherit_') !== false)) + { + continue; + } + + list(, $gid) = explode('fields_', $id); + + if($mybb->input['fields_default_'.$gid] == $permission && $mybb->input['fields_inherit_'.$gid] == 1) + { + $inherit[$gid] = 1; + continue; + } + $inherit[$gid] = 0; + + // If it isn't an array then it came from the javascript form + if(!is_array($permission)) + { + $permission = explode(',', $permission); + $permission = array_flip($permission); + foreach($permission as $name => $value) + { + $permission[$name] = 1; + } + } + + foreach(array('canview','canpostthreads','canpostreplys','canpostpolls') as $name) + { + if(in_array($name, $permission) || $permission[$name]) + { + $permissions[$name][$gid] = 1; + } + else + { + $permissions[$name][$gid] = 0; + } + } + } + + $cache->update_forums(); + + $canview = $permissions['canview']; + $canpostthreads = $permissions['canpostthreads']; + $canpostpolls = $permissions['canpostpolls']; + $canpostattachments = $permissions['canpostattachments']; + $canpostreplies = $permissions['canpostreplys']; + + save_quick_perms($fid); + + $plugins->run_hooks("admin_forum_management_edit_commit"); + + // Log admin action + log_admin_action($fid, $mybb->input['title']); + + flash_message($lang->success_forum_updated, 'success'); + admin_redirect("index.php?module=forum-management&fid={$fid}"); + } + } + + $page->extra_header .= "\n"; + + $page->add_breadcrumb_item($lang->edit_forum); + $page->output_header($lang->edit_forum); + + $page->output_nav_tabs($sub_tabs, 'edit_forum_settings'); + + $form = new Form("index.php?module=forum-management&action=edit", "post"); + echo $form->generate_hidden_field("fid", $fid); + + if($errors) + { + $page->output_inline_error($errors); + $forum_data = $mybb->input; + } + else + { + $forum_data['title'] = $forum_data['name']; + } + + $query = $db->simple_select("usergroups", "*", "", array("order_dir" => "name")); + while($usergroup = $db->fetch_array($query)) + { + $usergroups[$usergroup['gid']] = $usergroup; + } + + $query = $db->simple_select("forumpermissions", "*", "fid='{$fid}'"); + while($existing = $db->fetch_array($query)) + { + $existing_permissions[$existing['gid']] = $existing; + } + + $types = array( + 'f' => $lang->forum, + 'c' => $lang->category + ); + + $create_a_options_f = array( + 'id' => 'forum' + ); + + $create_a_options_c = array( + 'id' => 'category' + ); + + if($forum_data['type'] == "f") + { + $create_a_options_f['checked'] = true; + } + else + { + $create_a_options_c['checked'] = true; + } + + $form_container = new FormContainer($lang->edit_forum); + $form_container->output_row($lang->forum_type, $lang->forum_type_desc, $form->generate_radio_button('type', 'f', $lang->forum, $create_a_options_f)."
\n".$form->generate_radio_button('type', 'c', $lang->category, $create_a_options_c)); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $forum_data['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->description, "", $form->generate_text_area('description', $forum_data['description'], array('id' => 'description')), 'description'); + $form_container->output_row($lang->parent_forum." *", $lang->parent_forum_desc, $form->generate_forum_select('pid', $forum_data['pid'], array('id' => 'pid', 'main_option' => $lang->none)), 'pid'); + $form_container->output_row($lang->display_order, "", $form->generate_numeric_field('disporder', $forum_data['disporder'], array('id' => 'disporder')), 'disporder'); + $form_container->end(); + + $form_container = new FormContainer($lang->additional_forum_options); + $form_container->output_row($lang->forum_link, $lang->forum_link_desc, $form->generate_text_box('linkto', $forum_data['linkto'], array('id' => 'linkto')), 'linkto'); + $form_container->output_row($lang->forum_password, $lang->forum_password_desc, $form->generate_text_box('password', $forum_data['password'], array('id' => 'password')), 'password'); + + $access_options = array( + $form->generate_check_box('active', 1, $lang->forum_is_active."
\n{$lang->forum_is_active_desc}", array('checked' => $forum_data['active'], 'id' => 'active')), + $form->generate_check_box('open', 1, $lang->forum_is_open."
\n{$lang->forum_is_open_desc}", array('checked' => $forum_data['open'], 'id' => 'open')) + ); + + $form_container->output_row($lang->access_options, "", "
".implode("
", $access_options)."
"); + + $styles = array( + '0' => $lang->use_default + ); + + $query = $db->simple_select("themes", "tid,name", "name!='((master))' AND name!='((master-backup))'", array('order_by' => 'name')); + while($style = $db->fetch_array($query)) + { + $styles[$style['tid']] = $style['name']; + } + + $style_options = array( + $form->generate_check_box('overridestyle', 1, $lang->override_user_style, array('checked' => $forum_data['overridestyle'], 'id' => 'overridestyle')), + $lang->forum_specific_style."
\n".$form->generate_select_box('style', $styles, $forum_data['style'], array('id' => 'style')) + ); + + $form_container->output_row($lang->style_options, "", "
".implode("
", $style_options)."
"); + + $display_methods = array( + '0' => $lang->dont_display_rules, + '1' => $lang->display_rules_inline, + '3' => $lang->display_rules_inline_new, + '2' => $lang->display_rules_link + ); + + $forum_rules = array( + $lang->display_method."
\n".$form->generate_select_box('rulestype', $display_methods, $forum_data['rulestype'], array('checked' => $forum_data['rulestype'], 'id' => 'rulestype')), + $lang->title."
\n".$form->generate_text_box('rulestitle', $forum_data['rulestitle'], array('checked' => $forum_data['rulestitle'], 'id' => 'rulestitle')), + $lang->rules."
\n".$form->generate_text_area('rules', $forum_data['rules'], array('checked' => $forum_data['rules'], 'id' => 'rules')) + ); + + $form_container->output_row($lang->forum_rules, "", "
".implode("
", $forum_rules)."
"); + + $default_date_cut = array( + 0 => $lang->board_default, + 1 => $lang->datelimit_1day, + 5 => $lang->datelimit_5days, + 10 => $lang->datelimit_10days, + 20 => $lang->datelimit_20days, + 50 => $lang->datelimit_50days, + 75 => $lang->datelimit_75days, + 100 => $lang->datelimit_100days, + 365 => $lang->datelimit_lastyear, + 9999 => $lang->datelimit_beginning, + ); + + $default_sort_by = array( + "" => $lang->board_default, + "subject" => $lang->sort_by_subject, + "lastpost" => $lang->sort_by_lastpost, + "starter" => $lang->sort_by_starter, + "started" => $lang->sort_by_started, + "rating" => $lang->sort_by_rating, + "replies" => $lang->sort_by_replies, + "views" => $lang->sort_by_views, + ); + + $default_sort_order = array( + "" => $lang->board_default, + "asc" => $lang->sort_order_asc, + "desc" => $lang->sort_order_desc, + ); + + $view_options = array( + $lang->default_date_cut."
\n".$form->generate_select_box('defaultdatecut', $default_date_cut, $forum_data['defaultdatecut'], array('checked' => $forum_data['defaultdatecut'], 'id' => 'defaultdatecut')), + $lang->default_sort_by."
\n".$form->generate_select_box('defaultsortby', $default_sort_by, $forum_data['defaultsortby'], array('checked' => $forum_data['defaultsortby'], 'id' => 'defaultsortby')), + $lang->default_sort_order."
\n".$form->generate_select_box('defaultsortorder', $default_sort_order, $forum_data['defaultsortorder'], array('checked' => $forum_data['defaultsortorder'], 'id' => 'defaultsortorder')), + ); + + $form_container->output_row($lang->default_view_options, "", "
".implode("
", $view_options)."
"); + + $misc_options = array( + $form->generate_check_box('allowhtml', 1, $lang->allow_html, array('checked' => $forum_data['allowhtml'], 'id' => 'allowhtml')), + $form->generate_check_box('allowmycode', 1, $lang->allow_mycode, array('checked' => $forum_data['allowmycode'], 'id' => 'allowmycode')), + $form->generate_check_box('allowsmilies', 1, $lang->allow_smilies, array('checked' => $forum_data['allowsmilies'], 'id' => 'allowsmilies')), + $form->generate_check_box('allowimgcode', 1, $lang->allow_img_code, array('checked' => $forum_data['allowimgcode'], 'id' => 'allowimgcode')), + $form->generate_check_box('allowvideocode', 1, $lang->allow_video_code, array('checked' => $forum_data['allowvideocode'], 'id' => 'allowvideocode')), + $form->generate_check_box('allowpicons', 1, $lang->allow_post_icons, array('checked' => $forum_data['allowpicons'], 'id' => 'allowpicons')), + $form->generate_check_box('allowtratings', 1, $lang->allow_thread_ratings, array('checked' => $forum_data['allowtratings'], 'id' => 'allowtratings')), + $form->generate_check_box('showinjump', 1, $lang->show_forum_jump, array('checked' => $forum_data['showinjump'], 'id' => 'showinjump')), + $form->generate_check_box('usepostcounts', 1, $lang->use_postcounts, array('checked' => $forum_data['usepostcounts'], 'id' => 'usepostcounts')), + $form->generate_check_box('usethreadcounts', 1, $lang->use_threadcounts, array('checked' => $forum_data['usethreadcounts'], 'id' => 'usethreadcounts')), + $form->generate_check_box('requireprefix', 1, $lang->require_thread_prefix, array('checked' => $forum_data['requireprefix'], 'id' => 'requireprefix')) + ); + + $form_container->output_row($lang->misc_options, "", "
".implode("
", $misc_options)."
"); + $form_container->end(); + + $cached_forum_perms = $cache->read("forumpermissions"); + $field_list = array( + 'canview' => $lang->permissions_canview, + 'canpostthreads' => $lang->permissions_canpostthreads, + 'canpostreplys' => $lang->permissions_canpostreplys, + 'canpostpolls' => $lang->permissions_canpostpolls, + ); + + $field_list2 = array( + 'canview' => $lang->perm_drag_canview, + 'canpostthreads' => $lang->perm_drag_canpostthreads, + 'canpostreplys' => $lang->perm_drag_canpostreplys, + 'canpostpolls' => $lang->perm_drag_canpostpolls, + ); + + $ids = array(); + + $form_container = new FormContainer($lang->sprintf($lang->forum_permissions_in, $forum_data['name'])); + $form_container->output_row_header($lang->permissions_group, array("class" => "align_center", 'style' => 'width: 30%')); + $form_container->output_row_header($lang->overview_allowed_actions, array("class" => "align_center")); + $form_container->output_row_header($lang->overview_disallowed_actions, array("class" => "align_center")); + $form_container->output_row_header($lang->controls, array("class" => "align_center", 'style' => 'width: 120px', 'colspan' => 2)); + + if($mybb->request_method == "post") + { + foreach($usergroups as $usergroup) + { + if(isset($mybb->input['fields_'.$usergroup['gid']])) + { + $input_permissions = $mybb->input['fields_'.$usergroup['gid']]; + if(!is_array($input_permissions)) + { + // Convering the comma separated list from Javascript form into a variable + $input_permissions = explode(',' , $input_permissions); + } + foreach($input_permissions as $input_permission) + { + $mybb->input['permissions'][$usergroup['gid']][$input_permission] = 1; + } + } + } + } + + foreach($usergroups as $usergroup) + { + $perms = array(); + if(isset($mybb->input['default_permissions'])) + { + if($mybb->input['default_permissions'][$usergroup['gid']]) + { + if(is_array($existing_permissions) && $existing_permissions[$usergroup['gid']]) + { + $perms = $existing_permissions[$usergroup['gid']]; + $default_checked = false; + } + elseif(is_array($cached_forum_perms) && $cached_forum_perms[$forum_data['fid']][$usergroup['gid']]) + { + $perms = $cached_forum_perms[$forum_data['fid']][$usergroup['gid']]; + $default_checked = true; + } + else if(is_array($cached_forum_perms) && $cached_forum_perms[$forum_data['pid']][$usergroup['gid']]) + { + $perms = $cached_forum_perms[$forum_data['pid']][$usergroup['gid']]; + $default_checked = true; + } + } + + if(!$perms) + { + $perms = $usergroup; + $default_checked = true; + } + } + else + { + if(is_array($existing_permissions) && $existing_permissions[$usergroup['gid']]) + { + $perms = $existing_permissions[$usergroup['gid']]; + $default_checked = false; + } + elseif(is_array($cached_forum_perms) && $cached_forum_perms[$forum_data['fid']][$usergroup['gid']]) + { + $perms = $cached_forum_perms[$forum_data['fid']][$usergroup['gid']]; + $default_checked = true; + } + else if(is_array($cached_forum_perms) && $cached_forum_perms[$forum_data['pid']][$usergroup['gid']]) + { + $perms = $cached_forum_perms[$forum_data['pid']][$usergroup['gid']]; + $default_checked = true; + } + + if(!$perms) + { + $perms = $usergroup; + $default_checked = true; + } + } + + foreach($field_list as $forum_permission => $forum_perm_title) + { + if(isset($mybb->input['permissions'])) + { + if($mybb->input['permissions'][$usergroup['gid']][$forum_permission]) + { + $perms_checked[$forum_permission] = 1; + } + else + { + $perms_checked[$forum_permission] = 0; + } + } + else + { + if($perms[$forum_permission] == 1) + { + $perms_checked[$forum_permission] = 1; + } + else + { + $perms_checked[$forum_permission] = 0; + } + } + } + $usergroup['title'] = htmlspecialchars_uni($usergroup['title']); + + if($default_checked) + { + $inherited_text = $lang->inherited_permission; + } + else + { + $inherited_text = $lang->custom_permission; + } + + $form_container->output_cell("{$usergroup['title']} ({$inherited_text})"); + + $field_select = "
\n"; + $field_select .= "
{$lang->enabled}
    \n"; + foreach($perms_checked as $perm => $value) + { + if($value == 1) + { + $field_select .= "
  • {$field_list2[$perm]}
  • "; + } + } + $field_select .= "
\n"; + $field_select .= "
{$lang->disabled}
    \n"; + foreach($perms_checked as $perm => $value) + { + if($value == 0) + { + $field_select .= "
  • {$field_list2[$perm]}
  • "; + } + } + $field_select .= "
\n"; + $field_select .= $form->generate_hidden_field("fields_".$usergroup['gid'], @implode(",", @array_keys($perms_checked, '1')), array('id' => 'fields_'.$usergroup['gid'])); + $field_select .= $form->generate_hidden_field("fields_inherit_".$usergroup['gid'], (int)$default_checked, array('id' => 'fields_inherit_'.$usergroup['gid'])); + $field_select .= $form->generate_hidden_field("fields_default_".$usergroup['gid'], @implode(",", @array_keys($perms_checked, '1')), array('id' => 'fields_default_'.$usergroup['gid'])); + $field_select = str_replace("'", "\\'", $field_select); + $field_select = str_replace("\n", "", $field_select); + + $field_select = "\n"; + + $field_selected = array(); + foreach($field_list as $forum_permission => $permission_title) + { + $field_options[$forum_permission] = $permission_title; + if($perms_checked[$forum_permission]) + { + $field_selected[] = $forum_permission; + } + } + + $field_select .= "\n"; + $form_container->output_cell($field_select, array('colspan' => 2)); + + if(!$default_checked) + { + $form_container->output_cell("{$lang->edit_permissions}", array("class" => "align_center")); + $form_container->output_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_clear_custom_permission}')\">{$lang->clear_custom_perms}", array("class" => "align_center")); + } + else + { + $form_container->output_cell("{$lang->set_custom_perms}", array("class" => "align_center", "colspan" => 2)); + } + + $form_container->construct_row(array('id' => 'row_'.$usergroup['gid'])); + + $ids[] = $usergroup['gid']; + } + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_forum); + $form->output_submit_wrapper($buttons); + $form->end(); + + // Write in our JS based field selector + echo "\n"; + + $page->output_footer(); +} + +if($mybb->input['action'] == "deletemod") +{ + $modid = (int)$mybb->input['id']; + $isgroup = (int)$mybb->input['isgroup']; + $fid = $mybb->get_input('fid', 1); + + $query = $db->simple_select("moderators", "*", "id='{$modid}' AND isgroup = '{$isgroup}' AND fid='{$fid}'"); + $mod = $db->fetch_array($query); + + // Does the forum not exist? + if(!$mod['mid']) + { + flash_message($lang->error_invalid_moderator, 'error'); + admin_redirect("index.php?module=forum-management&fid={$fid}"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=forum-management&fid={$fid}"); + } + + $plugins->run_hooks("admin_forum_management_deletemod"); + + if($mybb->request_method == "post") + { + $mid = $mod['mid']; + if($mybb->input['isgroup']) + { + $query = $db->query(" + SELECT m.*, g.title + FROM ".TABLE_PREFIX."moderators m + LEFT JOIN ".TABLE_PREFIX."usergroups g ON (g.gid=m.id) + WHERE m.mid='{$mid}' + "); + } + else + { + $query = $db->query(" + SELECT m.*, u.username, u.usergroup + FROM ".TABLE_PREFIX."moderators m + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=m.id) + WHERE m.mid='{$mid}' + "); + } + $mod = $db->fetch_array($query); + + $db->delete_query("moderators", "mid='{$mid}'"); + + $plugins->run_hooks("admin_forum_management_deletemod_commit"); + + $cache->update_moderators(); + + $forum = get_forum($fid); + + // Log admin action + if($isgroup) + { + log_admin_action($mid, $mod['title'], $forum['fid'], $forum['name']); + } + else + { + log_admin_action($mid, $mod['username'], $forum['fid'], $forum['name']); + } + + flash_message($lang->success_moderator_deleted, 'success'); + admin_redirect("index.php?module=forum-management&fid={$fid}#tab_moderators"); + } + else + { + $page->output_confirm_action("index.php?module=forum-management&action=deletemod&fid={$mod['fid']}&uid={$mod['uid']}", $lang->confirm_moderator_deletion); + } +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("forums", "*", "fid='{$mybb->input['fid']}'"); + $forum = $db->fetch_array($query); + + // Does the forum not exist? + if(!$forum['fid']) + { + flash_message($lang->error_invalid_forum, 'error'); + admin_redirect("index.php?module=forum-management"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=forum-management"); + } + + $plugins->run_hooks("admin_forum_management_delete"); + + if($mybb->request_method == "post") + { + $fid = $mybb->get_input('fid', 1); + $forum_info = get_forum($fid); + + $query = $db->simple_select("forums", "posts,unapprovedposts,threads,unapprovedthreads", "fid='{$fid}'"); + $stats = $db->fetch_array($query); + + // Delete the forum + $db->delete_query("forums", "fid='$fid'"); + + switch($db->type) + { + case "pgsql": + case "sqlite": + $query = $db->simple_select("forums", "*", "','|| parentlist|| ',' LIKE '%,$fid,%'"); + break; + default: + $query = $db->simple_select("forums", "*", "CONCAT(',', parentlist, ',') LIKE '%,$fid,%'"); + } + while($forum = $db->fetch_array($query)) + { + $fids[$forum['fid']] = $fid; + $delquery .= " OR fid='{$forum['fid']}'"; + + $stats['posts'] += $forum['posts']; + $stats['unapprovedposts'] += $forum['unapprovedposts']; + $stats['threads'] += $forum['threads']; + $stats['unapprovedthreads'] += $forum['unapprovedthreads']; + } + + switch($db->type) + { + case "pgsql": + case "sqlite": + $db->delete_query("forums", "','||parentlist||',' LIKE '%,$fid,%'"); + break; + default: + $db->delete_query("forums", "CONCAT(',',parentlist,',') LIKE '%,$fid,%'"); + } + + $db->delete_query("threads", "fid='{$fid}' {$delquery}"); + $db->delete_query("posts", "fid='{$fid}' {$delquery}"); + $db->delete_query("moderators", "fid='{$fid}' {$delquery}"); + $db->delete_query("forumsubscriptions", "fid='{$fid}' {$delquery}"); + + $update_stats = array( + 'numthreads' => "-".$stats['threads'], + 'numunapprovedthreads' => "-".$stats['unapprovedthreads'], + 'numposts' => "-".$stats['posts'], + 'numunapprovedposts' => "-".$stats['unapprovedposts'] + ); + update_stats($update_stats); + + $plugins->run_hooks("admin_forum_management_delete_commit"); + + $cache->update_forums(); + $cache->update_moderators(); + $cache->update_forumpermissions(); + + // Log admin action + log_admin_action($forum_info['fid'], $forum_info['name']); + + flash_message($lang->success_forum_deleted, 'success'); + admin_redirect("index.php?module=forum-management"); + } + else + { + $page->output_confirm_action("index.php?module=forum-management&action=delete&fid={$forum['fid']}", $lang->confirm_forum_deletion); + } +} + +if(!$mybb->input['action']) +{ + if(!isset($mybb->input['fid'])) + { + $mybb->input['fid'] = 0; + } + + $fid = $mybb->get_input('fid', 1); + if($fid) + { + $forum = get_forum($fid); + } + + $plugins->run_hooks("admin_forum_management_start"); + + if($mybb->request_method == "post") + { + if($mybb->input['update'] == "permissions") + { + $inherit = array(); + foreach($mybb->input as $id => $permission) + { + // Make sure we're only skipping inputs that don't start with "fields_" and aren't fields_default_ or fields_inherit_ + if(strpos($id, 'fields_') === false || (strpos($id, 'fields_default_') !== false || strpos($id, 'fields_inherit_') !== false)) + { + continue; + } + + list(, $gid) = explode('fields_', $id); + + if($mybb->input['fields_default_'.$gid] == $permission && $mybb->input['fields_inherit_'.$gid] == 1) + { + $inherit[$gid] = 1; + continue; + } + $inherit[$gid] = 0; + + // If it isn't an array then it came from the javascript form + if(!is_array($permission)) + { + $permission = explode(',', $permission); + $permission = array_flip($permission); + foreach($permission as $name => $value) + { + $permission[$name] = 1; + } + } + foreach(array('canview','canpostthreads','canpostreplys','canpostpolls') as $name) + { + if($permission[$name]) + { + $permissions[$name][$gid] = 1; + } + else + { + $permissions[$name][$gid] = 0; + } + } + } + + $canview = $permissions['canview']; + $canpostthreads = $permissions['canpostthreads']; + $canpostpolls = $permissions['canpostpolls']; + $canpostattachments = $permissions['canpostattachments']; + $canpostreplies = $permissions['canpostreplys']; + + save_quick_perms($fid); + + $plugins->run_hooks("admin_forum_management_start_permissions_commit"); + + $cache->update_forums(); + + // Log admin action + log_admin_action('quickpermissions', $fid, $forum['name']); + + flash_message($lang->success_forum_permissions_updated, 'success'); + admin_redirect("index.php?module=forum-management&fid={$fid}#tab_permissions"); + } + elseif($mybb->input['add'] == "moderators") + { + $forum = get_forum($fid); + if(!$forum) + { + flash_message($lang->error_invalid_forum, 'error'); + admin_redirect("index.php?module=forum-management&fid={$fid}#tab_moderators"); + } + if(!empty($mybb->input['usergroup'])) + { + $isgroup = 1; + $gid = (int)$mybb->input['usergroup']; + + if(!$groupscache[$gid]) + { + // Didn't select a valid moderator + flash_message($lang->error_moderator_not_found, 'error'); + admin_redirect("index.php?module=forum-management&fid={$fid}#tab_moderators"); + } + + $newmod = array( + "id" => $gid, + "name" => $groupscache[$gid]['title'] + ); + } + else + { + $options = array( + 'fields' => array('uid AS id', 'username AS name') + ); + $newmod = get_user_by_username($mybb->input['username'], $options); + + if(empty($newmod['id'])) + { + flash_message($lang->error_moderator_not_found, 'error'); + admin_redirect("index.php?module=forum-management&fid={$fid}#tab_moderators"); + } + + $isgroup = 0; + } + + if($newmod['id']) + { + $query = $db->simple_select("moderators", "id", "id='".$newmod['id']."' AND fid='".$fid."' AND isgroup='{$isgroup}'", array('limit' => 1)); + + if(!$db->num_rows($query)) + { + $new_mod = array( + "fid" => $fid, + "id" => $newmod['id'], + "isgroup" => $isgroup, + "caneditposts" => 1, + "cansoftdeleteposts" => 1, + "canrestoreposts" => 1, + "candeleteposts" => 1, + "cansoftdeletethreads" => 1, + "canrestorethreads" => 1, + "candeletethreads" => 1, + "canviewips" => 1, + "canviewunapprove" => 1, + "canviewdeleted" => 1, + "canopenclosethreads" => 1, + "canstickunstickthreads" => 1, + "canapproveunapprovethreads" => 1, + "canapproveunapproveposts" => 1, + "canapproveunapproveattachs" => 1, + "canmanagethreads" => 1, + "canmanagepolls" => 1, + "canpostclosedthreads" => 1, + "canmovetononmodforum" => 1, + "canusecustomtools" => 1, + "canmanageannouncements" => 1, + "canmanagereportedposts" => 1, + "canviewmodlog" => 1 + ); + + $mid = $db->insert_query("moderators", $new_mod); + + if(!$isgroup) + { + $db->update_query("users", array('usergroup' => 6), "uid='{$newmod['id']}' AND usergroup='2'"); + } + + $plugins->run_hooks("admin_forum_management_start_moderators_commit"); + + $cache->update_moderators(); + + // Log admin action + log_admin_action('addmod', $mid, $newmod['name'], $fid, $forum['name']); + + flash_message($lang->success_moderator_added, 'success'); + admin_redirect("index.php?module=forum-management&action=editmod&mid={$mid}"); + } + else + { + flash_message($lang->error_moderator_already_added, 'error'); + admin_redirect("index.php?module=forum-management&fid={$fid}#tab_moderators"); + } + } + else + { + flash_message($lang->error_moderator_not_found, 'error'); + admin_redirect("index.php?module=forum-management&fid={$fid}#tab_moderators"); + } + } + else + { + if(!empty($mybb->input['disporder']) && is_array($mybb->input['disporder'])) + { + foreach($mybb->input['disporder'] as $update_fid => $order) + { + $db->update_query("forums", array('disporder' => (int)$order), "fid='".(int)$update_fid."'"); + } + + $plugins->run_hooks("admin_forum_management_start_disporder_commit"); + + $cache->update_forums(); + + // Log admin action + log_admin_action('orders', $forum['fid'], $forum['name']); + + flash_message($lang->success_forum_disporder_updated, 'success'); + admin_redirect("index.php?module=forum-management&fid=".$mybb->input['fid']); + } + } + } + + $page->extra_header .= "\n"; + + if($fid) + { + $page->add_breadcrumb_item($lang->view_forum, "index.php?module=forum-management"); + } + + $page->output_header($lang->forum_management); + + if($fid) + { + $page->output_nav_tabs($sub_tabs, 'view_forum'); + } + else + { + $page->output_nav_tabs($sub_tabs, 'forum_management'); + } + + $form = new Form("index.php?module=forum-management", "post", "management"); + echo $form->generate_hidden_field("fid", $mybb->input['fid']); + + if($fid) + { + $tabs = array( + 'subforums' => $lang->subforums, + 'permissions' => $lang->forum_permissions, + 'moderators' => $lang->moderators, + ); + $tabs = $plugins->run_hooks("admin_forum_management_start_graph_tabs", $tabs); + $page->output_tab_control($tabs); + + echo "
\n"; + if(!isset($forum_cache) || !is_array($forum_cache)) + { + cache_forums(); + } + $form_container = new FormContainer($lang->sprintf($lang->in_forums, $forum_cache[$fid]['name'])); + } + else + { + $form_container = new FormContainer($lang->manage_forums); + } + $form_container->output_row_header($lang->forum); + $form_container->output_row_header($lang->order, array("class" => "align_center", 'width' => '5%')); + $form_container->output_row_header($lang->controls, array("class" => "align_center", 'style' => 'width: 200px')); + + build_admincp_forums_list($form_container, $fid); + + $submit_options = array(); + + if($form_container->num_rows() == 0) + { + $form_container->output_cell($lang->no_forums, array('colspan' => 3)); + $form_container->construct_row(); + $submit_options = array('disabled' => true); + } + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->update_forum_orders, $submit_options); + $buttons[] = $form->generate_reset_button($lang->reset); + + $form->output_submit_wrapper($buttons); + + if(!$fid) + { + $form->end(); + } + + if($fid) + { + echo "
\n"; + $form->end(); + + $query = $db->simple_select("usergroups", "*", "", array("order" => "name")); + while($usergroup = $db->fetch_array($query)) + { + $usergroups[$usergroup['gid']] = $usergroup; + } + + $query = $db->simple_select("forumpermissions", "*", "fid='{$fid}'"); + while($existing = $db->fetch_array($query)) + { + $existing_permissions[$existing['gid']] = $existing; + } + + $cached_forum_perms = $cache->read("forumpermissions"); + $field_list = array( + 'canview' => $lang->permissions_canview, + 'canpostthreads' => $lang->permissions_canpostthreads, + 'canpostreplys' => $lang->permissions_canpostreplys, + 'canpostpolls' => $lang->permissions_canpostpolls, + ); + + $field_list2 = array( + 'canview' => $lang->perm_drag_canview, + 'canpostthreads' => $lang->perm_drag_canpostthreads, + 'canpostreplys' => $lang->perm_drag_canpostreplys, + 'canpostpolls' => $lang->perm_drag_canpostpolls, + ); + + $ids = array(); + + $form = new Form("index.php?module=forum-management", "post", "management"); + echo $form->generate_hidden_field("fid", $mybb->input['fid']); + echo $form->generate_hidden_field("update", "permissions"); + + echo "
\n"; + + $form_container = new FormContainer($lang->sprintf($lang->forum_permissions_in, $forum_cache[$fid]['name'])); + $form_container->output_row_header($lang->permissions_group, array("class" => "align_center", 'style' => 'width: 30%')); + $form_container->output_row_header($lang->overview_allowed_actions, array("class" => "align_center")); + $form_container->output_row_header($lang->overview_disallowed_actions, array("class" => "align_center")); + $form_container->output_row_header($lang->controls, array("class" => "align_center", 'style' => 'width: 120px', 'colspan' => 2)); + foreach($usergroups as $usergroup) + { + $perms = array(); + if(isset($mybb->input['default_permissions'])) + { + if($mybb->input['default_permissions'][$usergroup['gid']]) + { + if(is_array($existing_permissions) && $existing_permissions[$usergroup['gid']]) + { + $perms = $existing_permissions[$usergroup['gid']]; + $default_checked = false; + } + elseif(is_array($cached_forum_perms) && $cached_forum_perms[$forum['fid']][$usergroup['gid']]) + { + $perms = $cached_forum_perms[$forum['fid']][$usergroup['gid']]; + $default_checked = true; + } + else if(is_array($cached_forum_perms) && $cached_forum_perms[$forum['pid']][$usergroup['gid']]) + { + $perms = $cached_forum_perms[$forum['pid']][$usergroup['gid']]; + $default_checked = true; + } + } + + if(!$perms) + { + $perms = $usergroup; + $default_checked = true; + } + } + else + { + if(isset($existing_permissions) && is_array($existing_permissions) && $existing_permissions[$usergroup['gid']]) + { + $perms = $existing_permissions[$usergroup['gid']]; + $default_checked = false; + } + elseif(is_array($cached_forum_perms) && isset($cached_forum_perms[$forum['fid']]) && $cached_forum_perms[$forum['fid']][$usergroup['gid']]) + { + $perms = $cached_forum_perms[$forum['fid']][$usergroup['gid']]; + $default_checked = true; + } + else if(is_array($cached_forum_perms) && $cached_forum_perms[$forum['pid']][$usergroup['gid']]) + { + $perms = $cached_forum_perms[$forum['pid']][$usergroup['gid']]; + $default_checked = true; + } + + if(!$perms) + { + $perms = $usergroup; + $default_checked = true; + } + } + foreach($field_list as $forum_permission => $forum_perm_title) + { + if(isset($mybb->input['permissions'])) + { + if($mybb->input['permissions'][$usergroup['gid']][$forum_permission]) + { + $perms_checked[$forum_permission] = 1; + } + else + { + $perms_checked[$forum_permission] = 0; + } + } + else + { + if($perms[$forum_permission] == 1) + { + $perms_checked[$forum_permission] = 1; + } + else + { + $perms_checked[$forum_permission] = 0; + } + } + } + $usergroup['title'] = htmlspecialchars_uni($usergroup['title']); + + if($default_checked == 1) + { + $inherited_text = $lang->inherited_permission; + } + else + { + $inherited_text = $lang->custom_permission; + } + + $form_container->output_cell("{$usergroup['title']} ({$inherited_text})"); + + $field_select = "
\n"; + $field_select .= "
    \n"; + foreach($perms_checked as $perm => $value) + { + if($value == 1) + { + $field_select .= "
  • {$field_list2[$perm]}
  • "; + } + } + $field_select .= "
\n"; + $field_select .= "
    \n"; + foreach($perms_checked as $perm => $value) + { + if($value == 0) + { + $field_select .= "
  • {$field_list2[$perm]}
  • "; + } + } + $field_select .= "
\n"; + $field_select .= $form->generate_hidden_field("fields_".$usergroup['gid'], @implode(",", @array_keys($perms_checked, '1')), array('id' => 'fields_'.$usergroup['gid'])); + $field_select .= $form->generate_hidden_field("fields_inherit_".$usergroup['gid'], (int)$default_checked, array('id' => 'fields_inherit_'.$usergroup['gid'])); + $field_select .= $form->generate_hidden_field("fields_default_".$usergroup['gid'], @implode(",", @array_keys($perms_checked, '1')), array('id' => 'fields_default_'.$usergroup['gid'])); + $field_select = str_replace("'", "\\'", $field_select); + $field_select = str_replace("\n", "", $field_select); + + $field_select = "\n"; + + $field_selected = array(); + foreach($field_list as $forum_permission => $permission_title) + { + $field_options[$forum_permission] = $permission_title; + if($perms_checked[$forum_permission]) + { + $field_selected[] = $forum_permission; + } + } + + $field_select .= "\n"; + $form_container->output_cell($field_select, array('colspan' => 2)); + + if(!$default_checked) + { + $form_container->output_cell("{$lang->edit_permissions}", array("class" => "align_center")); + $form_container->output_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_clear_custom_permission}')\">{$lang->clear_custom_perms}", array("class" => "align_center")); + } + else + { + $form_container->output_cell("{$lang->set_custom_perms}", array("class" => "align_center", "colspan" => 2)); + } + $form_container->construct_row(array('id' => 'row_'.$usergroup['gid'])); + + $ids[] = $usergroup['gid']; + } + $form_container->end(); + + $buttons = array(); + $buttons[] = $form->generate_submit_button($lang->update_forum_permissions); + $buttons[] = $form->generate_reset_button($lang->reset); + + $form->output_submit_wrapper($buttons); + + // Write in our JS based field selector + echo "\n"; + + echo "
\n"; + $form->end(); + echo "
\n"; + $form_container = new FormContainer($lang->sprintf($lang->moderators_assigned_to, $forum_cache[$fid]['name'])); + $form_container->output_row_header($lang->name, array('width' => '75%')); + $form_container->output_row_header($lang->controls, array("class" => "align_center", 'style' => 'width: 200px', 'colspan' => 2)); + $query = $db->query(" + SELECT m.mid, m.id, m.isgroup, u.username, g.title + FROM ".TABLE_PREFIX."moderators m + LEFT JOIN ".TABLE_PREFIX."users u ON (m.isgroup='0' AND m.id=u.uid) + LEFT JOIN ".TABLE_PREFIX."usergroups g ON (m.isgroup='1' AND m.id=g.gid) + WHERE fid='{$fid}' + ORDER BY m.isgroup DESC, u.username, g.title + "); + while($moderator = $db->fetch_array($query)) + { + if($moderator['isgroup']) + { + $moderator['img'] = "style}/images/icons/group.png\" alt=\"{$lang->group}\" title=\"{$lang->group}\" />"; + $form_container->output_cell("{$moderator['img']} ".htmlspecialchars_uni($moderator['title'])." ({$lang->usergroup} {$moderator['id']})"); + $form_container->output_cell("{$lang->edit}", array("class" => "align_center")); + $form_container->output_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_moderator_deletion}')\">{$lang->delete}", array("class" => "align_center")); + } + else + { + $moderator['img'] = "style}/images/icons/user.png\" alt=\"{$lang->user}\" title=\"{$lang->user}\" />"; + $form_container->output_cell("{$moderator['img']} ".htmlspecialchars_uni($moderator['username']).""); + $form_container->output_cell("{$lang->edit}", array("class" => "align_center")); + $form_container->output_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_moderator_deletion}')\">{$lang->delete}", array("class" => "align_center")); + } + $form_container->construct_row(); + } + + if($form_container->num_rows() == 0) + { + $form_container->output_cell($lang->no_moderators, array('colspan' => 3)); + $form_container->construct_row(); + } + $form_container->end(); + + // Users + $buttons = array(); + $form = new Form("index.php?module=forum-management", "post", "management"); + echo $form->generate_hidden_field("fid", $mybb->input['fid']); + echo $form->generate_hidden_field("add", "moderators"); + + // Usergroup Moderator + if(!is_array($usergroups)) + { + $usergroups = $groupscache; + } + + foreach($usergroups as $group) + { + $modgroups[$group['gid']] = $lang->usergroup." ".$group['gid'].": ".$group['title']; + } + + if(!isset($mybb->input['usergroup'])) + { + $mybb->input['usergroup'] = ''; + } + + if(!isset($mybb->input['username'])) + { + $mybb->input['username'] = ''; + } + + $form_container = new FormContainer($lang->add_usergroup_as_moderator); + $form_container->output_row($lang->usergroup." *", $lang->moderator_usergroup_desc, $form->generate_select_box('usergroup', $modgroups, $mybb->input['usergroup'], array('id' => 'usergroup')), 'usergroup'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->add_usergroup_moderator); + $form->output_submit_wrapper($buttons); + $form->end(); + echo "
"; + + $form = new Form("index.php?module=forum-management", "post", "management"); + echo $form->generate_hidden_field("fid", $mybb->input['fid']); + echo $form->generate_hidden_field("add", "moderators"); + $form_container = new FormContainer($lang->add_user_as_moderator); + $form_container->output_row($lang->username." *", $lang->moderator_username_desc, $form->generate_text_box('username', $mybb->input['username'], array('id' => 'username')), 'username'); + $form_container->end(); + + // Autocompletion for usernames + echo ' + + + '; + + $buttons = array($form->generate_submit_button($lang->add_user_moderator)); + $form->output_submit_wrapper($buttons); + $form->end(); + + echo "
\n"; + + $plugins->run_hooks("admin_forum_management_start_graph"); + } + + $page->output_footer(); +} + +/** + * + */ +function build_admincp_forums_list(&$form_container, $pid=0, $depth=1) +{ + global $mybb, $lang, $db, $sub_forums; + static $forums_by_parent; + + if(!is_array($forums_by_parent)) + { + $forum_cache = cache_forums(); + + foreach($forum_cache as $forum) + { + $forums_by_parent[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum; + } + } + + if(!is_array($forums_by_parent[$pid])) + { + return; + } + + foreach($forums_by_parent[$pid] as $children) + { + foreach($children as $forum) + { + $forum['name'] = preg_replace("#&(?!\#[0-9]+;)#si", "&", $forum['name']); // Fix & but allow unicode + + if($forum['active'] == 0) + { + $forum['name'] = "".$forum['name'].""; + } + + if($forum['type'] == "c" && ($depth == 1 || $depth == 2)) + { + $sub_forums = ''; + if(isset($forums_by_parent[$forum['fid']]) && $depth == 2) + { + build_admincp_forums_list($form_container, $forum['fid'], $depth+1); + } + if($sub_forums) + { + $sub_forums = "
{$lang->sub_forums}: {$sub_forums}"; + } + + $form_container->output_cell("
{$forum['name']}{$sub_forums}
"); + + $form_container->output_cell("", array("class" => "align_center")); + + $popup = new PopupMenu("forum_{$forum['fid']}", $lang->options); + $popup->add_item($lang->edit_forum, "index.php?module=forum-management&action=edit&fid={$forum['fid']}"); + $popup->add_item($lang->subforums, "index.php?module=forum-management&fid={$forum['fid']}"); + $popup->add_item($lang->moderators, "index.php?module=forum-management&fid={$forum['fid']}#tab_moderators"); + $popup->add_item($lang->permissions, "index.php?module=forum-management&fid={$forum['fid']}#tab_permissions"); + $popup->add_item($lang->add_child_forum, "index.php?module=forum-management&action=add&pid={$forum['fid']}"); + $popup->add_item($lang->copy_forum, "index.php?module=forum-management&action=copy&fid={$forum['fid']}"); + $popup->add_item($lang->delete_forum, "index.php?module=forum-management&action=delete&fid={$forum['fid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_forum_deletion}')"); + + $form_container->output_cell($popup->fetch(), array("class" => "align_center")); + + $form_container->construct_row(); + + // Does this category have any sub forums? + if($forums_by_parent[$forum['fid']]) + { + build_admincp_forums_list($form_container, $forum['fid'], $depth+1); + } + } + elseif($forum['type'] == "f" && ($depth == 1 || $depth == 2)) + { + if($forum['description']) + { + $forum['description'] = preg_replace("#&(?!\#[0-9]+;)#si", "&", $forum['description']); + $forum['description'] = "
".$forum['description'].""; + } + + $sub_forums = ''; + if(isset($forums_by_parent[$forum['fid']]) && $depth == 2) + { + build_admincp_forums_list($form_container, $forum['fid'], $depth+1); + } + if($sub_forums) + { + $sub_forums = "
{$lang->sub_forums}: {$sub_forums}"; + } + + $form_container->output_cell("
{$forum['name']}{$forum['description']}{$sub_forums}
"); + + $form_container->output_cell("", array("class" => "align_center")); + + $popup = new PopupMenu("forum_{$forum['fid']}", $lang->options); + $popup->add_item($lang->edit_forum, "index.php?module=forum-management&action=edit&fid={$forum['fid']}"); + $popup->add_item($lang->subforums, "index.php?module=forum-management&fid={$forum['fid']}"); + $popup->add_item($lang->moderators, "index.php?module=forum-management&fid={$forum['fid']}#tab_moderators"); + $popup->add_item($lang->permissions, "index.php?module=forum-management&fid={$forum['fid']}#tab_permissions"); + $popup->add_item($lang->add_child_forum, "index.php?module=forum-management&action=add&pid={$forum['fid']}"); + $popup->add_item($lang->copy_forum, "index.php?module=forum-management&action=copy&fid={$forum['fid']}"); + $popup->add_item($lang->delete_forum, "index.php?module=forum-management&action=delete&fid={$forum['fid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_forum_deletion}')"); + + $form_container->output_cell($popup->fetch(), array("class" => "align_center")); + + $form_container->construct_row(); + + if(isset($forums_by_parent[$forum['fid']]) && $depth == 1) + { + build_admincp_forums_list($form_container, $forum['fid'], $depth+1); + } + } + else if($depth == 3) + { + if($donecount < $mybb->settings['subforumsindex']) + { + $sub_forums .= "{$comma} {$forum['name']}"; + $comma = $lang->comma; + } + + // Have we reached our max visible subforums? put a nice message and break out of the loop + ++$donecount; + if($donecount == $mybb->settings['subforumsindex']) + { + if(subforums_count($forums_by_parent[$pid]) > $donecount) + { + $sub_forums .= $comma.$lang->sprintf($lang->more_subforums, (subforums_count($forums_by_parent[$pid]) - $donecount)); + return; + } + } + } + } + } +} + +function retrieve_single_permissions_row($gid, $fid) +{ + global $mybb, $lang, $cache, $db; + + $query = $db->simple_select("usergroups", "*", "gid='{$gid}'"); + $usergroup = $db->fetch_array($query); + + $query = $db->simple_select("forums", "*", "fid='{$fid}'"); + $forum_data = $db->fetch_array($query); + + $query = $db->simple_select("forumpermissions", "*", "fid='{$fid}'"); + while($existing = $db->fetch_array($query)) + { + $existing_permissions[$existing['gid']] = $existing; + } + + $cached_forum_perms = $cache->read("forumpermissions"); + $field_list = array( + 'canview' => $lang->permissions_canview, + 'canpostthreads' => $lang->permissions_canpostthreads, + 'canpostreplys' => $lang->permissions_canpostreplys, + 'canpostpolls' => $lang->permissions_canpostpolls, + ); + + $field_list2 = array( + 'canview' => $lang->perm_drag_canview, + 'canpostthreads' => $lang->perm_drag_canpostthreads, + 'canpostreplys' => $lang->perm_drag_canpostreplys, + 'canpostpolls' => $lang->perm_drag_canpostpolls, + ); + + $form = new Form('', '', "", 0, "", true); + $form_container = new FormContainer(); + + $perms = array(); + + if(is_array($existing_permissions) && $existing_permissions[$usergroup['gid']]) + { + $perms = $existing_permissions[$usergroup['gid']]; + $default_checked = false; + } + elseif(is_array($cached_forum_perms) && $cached_forum_perms[$forum_data['fid']][$usergroup['gid']]) + { + $perms = $cached_forum_perms[$forum_data['fid']][$usergroup['gid']]; + $default_checked = true; + } + else if(is_array($cached_forum_perms) && $cached_forum_perms[$forum_data['pid']][$usergroup['gid']]) + { + $perms = $cached_forum_perms[$forum_data['pid']][$usergroup['gid']]; + $default_checked = true; + } + + if(!$perms) + { + $perms = $usergroup; + $default_checked = true; + } + + foreach($field_list as $forum_permission => $forum_perm_title) + { + if($perms[$forum_permission] == 1) + { + $perms_checked[$forum_permission] = 1; + } + else + { + $perms_checked[$forum_permission] = 0; + } + } + + $usergroup['title'] = htmlspecialchars_uni($usergroup['title']); + + if($default_checked == 1) + { + $inherited_text = $lang->inherited_permission; + } + else + { + $inherited_text = $lang->custom_permission; + } + + $form_container->output_cell("{$usergroup['title']} ({$inherited_text})"); + + $field_select = "
\n"; + $field_select .= "
{$lang->enabled}
    \n"; + foreach($perms_checked as $perm => $value) + { + if($value == 1) + { + $field_select .= "
  • {$field_list2[$perm]}
  • "; + } + } + $field_select .= "
\n"; + $field_select .= "
{$lang->disabled}
    \n"; + foreach($perms_checked as $perm => $value) + { + if($value == 0) + { + $field_select .= "
  • {$field_list2[$perm]}
  • "; + } + } + $field_select .= "
\n"; + $field_select .= $form->generate_hidden_field("fields_".$usergroup['gid'], @implode(",", @array_keys($perms_checked, 1)), array('id' => 'fields_'.$usergroup['gid'])); + $field_select = str_replace("\n", "", $field_select); + + foreach($field_list as $forum_permission => $permission_title) + { + $field_options[$forum_permission] = $permission_title; + } + $form_container->output_cell($field_select, array('colspan' => 2)); + + if(!$default_checked) + { + $form_container->output_cell("{$lang->edit_permissions}", array("class" => "align_center")); + $form_container->output_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_clear_custom_permission}')\">{$lang->clear_custom_perms}", array("class" => "align_center")); + } + else + { + $form_container->output_cell("{$lang->set_custom_perms}", array("class" => "align_center", "colspan" => 2)); + } + $form_container->construct_row(); + return $form_container->output_row_cells(0, true); +} + diff --git a/Upload/admin/modules/forum/moderation_queue.php b/Upload/admin/modules/forum/moderation_queue.php new file mode 100644 index 0000000..75f1a83 --- /dev/null +++ b/Upload/admin/modules/forum/moderation_queue.php @@ -0,0 +1,567 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->moderation_queue, "index.php?module=forum-moderation_queue"); + +$sub_tabs['threads'] = array( + 'title' => $lang->threads, + 'link' => "index.php?module=forum-moderation_queue&type=threads", + 'description' => $lang->threads_desc +); + +$sub_tabs['posts'] = array( + 'title' => $lang->posts, + 'link' => "index.php?module=forum-moderation_queue&type=posts", + 'description' => $lang->posts_desc +); + +$sub_tabs['attachments'] = array( + 'title' => $lang->attachments, + 'link' => "index.php?module=forum-moderation_queue&type=attachments", + 'description' => $lang->attachments_desc +); + +$plugins->run_hooks("admin_forum_moderation_queue_begin"); + +// Actually performing our moderation choices +if($mybb->request_method == "post") +{ + $plugins->run_hooks("admin_forum_moderation_queue_commit"); + + require_once MYBB_ROOT."inc/functions_upload.php"; + require_once MYBB_ROOT."inc/class_moderation.php"; + $moderation = new Moderation; + + if(is_array($mybb->input['threads'])) + { + $threads_to_approve = $threads_to_delete = array(); + // Fetch threads + $query = $db->simple_select("threads", "tid", "tid IN (".implode(",", array_map("intval", array_keys($mybb->input['threads'])))."){$flist}"); + while($thread = $db->fetch_array($query)) + { + $action = $mybb->input['threads'][$thread['tid']]; + if($action == "approve") + { + $threads_to_approve[] = $thread['tid']; + } + else if($action == "delete" && $mybb->settings['soft_delete'] != 1) + { + $moderation->delete_thread($thread['tid']); + } + else if($action == "delete") + { + $threads_to_delete[] = $thread['tid']; + } + } + if(!empty($threads_to_approve)) + { + $moderation->approve_threads($threads_to_approve); + } + if(!empty($threads_to_delete)) + { + $moderation->soft_delete_threads($threads_to_delete); + } + + $plugins->run_hooks("admin_forum_moderation_queue_threads_commit"); + + // Log admin action + log_admin_action('threads'); + + flash_message($lang->success_threads, 'success'); + admin_redirect("index.php?module=forum-moderation_queue&type=threads"); + } + else if(is_array($mybb->input['posts'])) + { + $posts_to_approve = $posts_to_delete = array(); + // Fetch posts + $query = $db->simple_select("posts", "pid", "pid IN (".implode(",", array_map("intval", array_keys($mybb->input['posts'])))."){$flist}"); + while($post = $db->fetch_array($query)) + { + $action = $mybb->input['posts'][$post['pid']]; + if($action == "approve") + { + $posts_to_approve[] = $post['pid']; + } + else if($action == "delete" && $mybb->settings['soft_delete'] != 1) + { + $moderation->delete_post($post['pid']); + } + else if($action == "delete") + { + $posts_to_delete[] = $post['pid']; + } + } + if(!empty($posts_to_approve)) + { + $moderation->approve_posts($posts_to_approve); + } + if(!empty($posts_to_delete)) + { + $moderation->soft_delete_posts($posts_to_delete); + } + + $plugins->run_hooks("admin_forum_moderation_queue_posts_commit"); + + // Log admin action + log_admin_action('posts'); + + flash_message($lang->success_posts, 'success'); + admin_redirect("index.php?module=forum-moderation_queue&type=posts"); + + } + else if(is_array($mybb->input['attachments'])) + { + $query = $db->simple_select("attachments", "aid, pid", "aid IN (".implode(",", array_map("intval", array_keys($mybb->input['attachments'])))."){$flist}"); + while($attachment = $db->fetch_array($query)) + { + $action = $mybb->input['attachments'][$attachment['aid']]; + if($action == "approve") + { + $db->update_query("attachments", array("visible" => 1), "aid='{$attachment['aid']}'"); + } + else if($action == "delete") + { + remove_attachment($attachment['pid'], '', $attachment['aid']); + } + } + + $plugins->run_hooks("admin_forum_moderation_queue_attachments_commit"); + + // Log admin action + log_admin_action('attachments'); + + flash_message($lang->success_attachments, 'success'); + admin_redirect("index.php?module=forum-moderation_queue&type=attachments"); + } +} + +$all_options = "\n"; + +// Threads awaiting moderation +if($mybb->input['type'] == "threads" || !$mybb->input['type']) +{ + $plugins->run_hooks("admin_forum_moderation_queue_threads"); + + $forum_cache = $cache->read("forums"); + + $query = $db->simple_select("threads", "COUNT(tid) AS unapprovedthreads", "visible=0"); + $unapproved_threads = $db->fetch_field($query, "unapprovedthreads"); + + if($unapproved_threads > 0) + { + // Figure out if we need to display multiple pages. + $per_page = 15; + if($mybb->input['page'] > 0) + { + $current_page = $mybb->get_input('page', 1); + $start = ($current_page-1)*$per_page; + $pages = $unapproved_threads / $per_page; + $pages = ceil($pages); + if($current_page > $pages) + { + $start = 0; + $current_page = 1; + } + } + else + { + $start = 0; + $current_page = 1; + } + + $pagination = draw_admin_pagination($current_page, $per_page, $unapproved_threads, "index.php?module=forum-moderation_queue&page={page}"); + + $page->add_breadcrumb_item($lang->threads_awaiting_moderation); + $page->output_header($lang->threads_awaiting_moderation); + $page->output_nav_tabs($sub_tabs, "threads"); + + $form = new Form("index.php?module=forum-moderation_queue", "post"); + + $table = new Table; + $table->construct_header($lang->subject); + $table->construct_header($lang->author, array("class" => "align_center", "width" => "20%")); + $table->construct_header($lang->posted, array("class" => "align_center", "width" => "20%")); + + $query = $db->query(" + SELECT t.tid, t.dateline, t.fid, t.subject, t.username AS threadusername, p.message AS postmessage, u.username AS username, t.uid + FROM ".TABLE_PREFIX."threads t + LEFT JOIN ".TABLE_PREFIX."posts p ON (p.pid=t.firstpost) + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=t.uid) + WHERE t.visible='0' + ORDER BY t.lastpost DESC + LIMIT {$start}, {$per_page} + "); + while($thread = $db->fetch_array($query)) + { + $thread['subject'] = htmlspecialchars_uni($thread['subject']); + $thread['threadlink'] = get_thread_link($thread['tid']); + $thread['forumlink'] = get_forum_link($thread['fid']); + $forum_name = $forum_cache[$thread['fid']]['name']; + $threaddate = my_date('relative', $thread['dateline']); + + if($thread['username'] == "") + { + if($thread['threadusername'] != "") + { + $profile_link = $thread['threadusername']; + } + else + { + $profile_link = $lang->guest; + } + } + else + { + $profile_link = build_profile_link($thread['username'], $thread['uid'], "_blank"); + } + + $thread['postmessage'] = nl2br(htmlspecialchars_uni($thread['postmessage'])); + + $table->construct_cell("{$thread['subject']}"); + $table->construct_cell($profile_link, array("class" => "align_center")); + $table->construct_cell($threaddate, array("class" => "align_center")); + $table->construct_row(); + + $controls = "
\n"; + $controls .= $form->generate_radio_button("threads[{$thread['tid']}]", "ignore", $lang->ignore, array('class' => 'radio_ignore', 'checked' => true))." "; + $controls .= $form->generate_radio_button("threads[{$thread['tid']}]", "delete", $lang->delete, array('class' => 'radio_delete', 'checked' => false))." "; + $controls .= $form->generate_radio_button("threads[{$thread['tid']}]", "approve", $lang->approve, array('class' => 'radio_approve', 'checked' => false)); + $controls .= "
"; + + $forum = "{$lang->forum} {$forum_name}
"; + + $table->construct_cell("
{$controls}
{$forum}
{$thread['postmessage']}
", array("colspan" => 3)); + $table->construct_row(); + } + + $table->output($lang->threads_awaiting_moderation); + echo $all_options; + echo $pagination; + + $buttons[] = $form->generate_submit_button($lang->perform_action); + $form->output_submit_wrapper($buttons); + $form->end(); + + echo ''; + + $page->output_footer(); + } +} + +// Posts awaiting moderation +if($mybb->input['type'] == "posts" || $mybb->input['type'] == "") +{ + $plugins->run_hooks("admin_forum_moderation_queue_posts"); + + $forum_cache = $cache->read("forums"); + + $query = $db->query(" + SELECT COUNT(pid) AS unapprovedposts + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + WHERE p.visible='0' AND t.firstpost != p.pid + "); + $unapproved_posts = $db->fetch_field($query, "unapprovedposts"); + + if($unapproved_posts > 0) + { + // Figure out if we need to display multiple pages. + $per_page = 15; + if($mybb->input['page'] > 0) + { + $current_page = $mybb->get_input('page', 1); + $start = ($current_page-1)*$per_page; + $pages = $unapproved_posts / $per_page; + $pages = ceil($pages); + if($current_page > $pages) + { + $start = 0; + $current_page = 1; + } + } + else + { + $start = 0; + $current_page = 1; + } + + $pagination = draw_admin_pagination($current_page, $per_page, $unapproved_posts, "index.php?module=forum-moderation_queue&type=posts&page={page}"); + + + $page->add_breadcrumb_item($lang->posts_awaiting_moderation); + $page->output_header($lang->posts_awaiting_moderation); + $page->output_nav_tabs($sub_tabs, "posts"); + + $form = new Form("index.php?module=forum-moderation_queue", "post"); + + $table = new Table; + $table->construct_header($lang->subject); + $table->construct_header($lang->author, array("class" => "align_center", "width" => "20%")); + $table->construct_header($lang->posted, array("class" => "align_center", "width" => "20%")); + + $query = $db->query(" + SELECT p.pid, p.subject, p.message, p.dateline, p.username AS postusername, t.subject AS threadsubject, t.tid, u.username, p.uid, t.fid + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) + WHERE p.visible='0' AND t.firstpost != p.pid + ORDER BY p.dateline DESC + LIMIT {$start}, {$per_page} + "); + while($post = $db->fetch_array($query)) + { + $altbg = alt_trow(); + $post['threadsubject'] = htmlspecialchars_uni($post['threadsubject']); + $post['subject'] = htmlspecialchars_uni($post['subject']); + + if(!$post['subject']) + { + $post['subject'] = $lang->re." ".$post['threadsubject']; + } + + $post['postlink'] = get_post_link($post['pid'], $post['tid']); + $post['threadlink'] = get_thread_link($post['tid']); + $post['forumlink'] = get_forum_link($post['fid']); + $forum_name = $forum_cache[$post['fid']]['name']; + $postdate = my_date('relative', $post['dateline']); + + if($post['username'] == "") + { + if($post['postusername'] != "") + { + $profile_link = $post['postusername']; + } + else + { + $profile_link = $lang->guest; + } + } + else + { + $profile_link = build_profile_link($post['username'], $post['uid'], "_blank"); + } + + $post['message'] = nl2br(htmlspecialchars_uni($post['message'])); + + $table->construct_cell("{$post['subject']}"); + $table->construct_cell($profile_link, array("class" => "align_center")); + $table->construct_cell($postdate, array("class" => "align_center")); + $table->construct_row(); + + $controls = "
\n"; + $controls .= $form->generate_radio_button("posts[{$post['pid']}]", "ignore", $lang->ignore, array('class' => 'radio_ignore', 'checked' => true))." "; + $controls .= $form->generate_radio_button("posts[{$post['pid']}]", "delete",$lang->delete, array('class' => 'radio_delete', 'checked' => false))." "; + $controls .= $form->generate_radio_button("posts[{$post['pid']}]", "approve", $lang->approve, array('class' => 'radio_approve', 'checked' => false)); + $controls .= "
"; + + $thread = "{$lang->thread} {$post['threadsubject']}"; + $forum = "{$lang->forum} {$forum_name}
"; + + $table->construct_cell("
{$controls}
{$forum}{$thread}
{$post['message']}
", array("colspan" => 3)); + $table->construct_row(); + } + + $table->output($lang->posts_awaiting_moderation); + echo $all_options; + echo $pagination; + + $buttons[] = $form->generate_submit_button($lang->perform_action); + $form->output_submit_wrapper($buttons); + $form->end(); + + echo ''; + + $page->output_footer(); + } + else if($mybb->input['type'] == "posts") + { + $page->output_header($lang->moderation_queue); + $page->output_nav_tabs($sub_tabs, "posts"); + echo "

{$lang->error_no_posts}

"; + $page->output_footer(); + } +} + +// Attachments awaiting moderation +if($mybb->input['type'] == "attachments" || $mybb->input['type'] == "") +{ + $plugins->run_hooks("admin_forum_moderation_queue_attachments"); + + $query = $db->query(" + SELECT COUNT(aid) AS unapprovedattachments + FROM ".TABLE_PREFIX."attachments a + LEFT JOIN ".TABLE_PREFIX."posts p ON (p.pid=a.pid) + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + WHERE a.visible='0' + "); + $unapproved_attachments = $db->fetch_field($query, "unapprovedattachments"); + + if($unapproved_attachments > 0) + { + // Figure out if we need to display multiple pages. + $per_page = 15; + if($mybb->input['page'] > 0) + { + $current_page = $mybb->get_input('page', 1); + $start = ($current_page-1)*$per_page; + $pages = $unapproved_attachments / $per_page; + $pages = ceil($pages); + if($current_page > $pages) + { + $start = 0; + $current_page = 1; + } + } + else + { + $start = 0; + $current_page = 1; + } + + $pagination = draw_admin_pagination($current_page, $per_page, $unapproved_attachments, "index.php?module=forum-moderation_queue&type=attachments&page={page}"); + + $page->add_breadcrumb_item($lang->attachments_awaiting_moderation); + $page->output_header($lang->attachments_awaiting_moderation); + $page->output_nav_tabs($sub_tabs, "attachments"); + + $form = new Form("index.php?module=forum-moderation_queue", "post"); + + $table = new Table; + $table->construct_header($lang->filename); + $table->construct_header($lang->uploadedby, array("class" => "align_center", "width" => "20%")); + $table->construct_header($lang->posted, array("class" => "align_center", "width" => "20%")); + $table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 3)); + + $query = $db->query(" + SELECT a.*, p.subject AS postsubject, p.dateline, p.uid, u.username, t.tid, t.subject AS threadsubject + FROM ".TABLE_PREFIX."attachments a + LEFT JOIN ".TABLE_PREFIX."posts p ON (p.pid=a.pid) + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) + WHERE a.visible='0' + ORDER BY a.dateuploaded DESC + LIMIT {$start}, {$per_page} + "); + + while($attachment = $db->fetch_array($query)) + { + if(!$attachment['dateuploaded']) $attachment['dateuploaded'] = $attachment['dateline']; + $attachdate = my_date('relative', $attachment['dateuploaded']); + + $attachment['postsubject'] = htmlspecialchars_uni($attachment['postsubject']); + $attachment['filename'] = htmlspecialchars_uni($attachment['filename']); + $attachment['threadsubject'] = htmlspecialchars_uni($attachment['threadsubject']); + $attachment['filesize'] = get_friendly_size($attachment['filesize']); + + $link = get_post_link($attachment['pid'], $attachment['tid']) . "#pid{$attachment['pid']}"; + $thread_link = get_thread_link($attachment['tid']); + $profile_link = build_profile_link($attachment['username'], $attachment['uid'], "_blank"); + + $table->construct_cell("{$attachment['filename']} ({$attachment['filesize']})
{$lang->post} {$attachment['postsubject']}"); + $table->construct_cell($profile_link, array("class" => "align_center")); + $table->construct_cell($attachdate, array("class" => "align_center")); + + $table->construct_cell($form->generate_radio_button("attachments[{$attachment['aid']}]", "ignore", $lang->ignore, array('class' => 'radio_ignore', 'checked' => true)), array("class" => "align_center")); + $table->construct_cell($form->generate_radio_button("attachments[{$attachment['aid']}]", "delete", $lang->delete, array('class' => 'radio_delete', 'checked' => false)), array("class" => "align_center")); + $table->construct_cell($form->generate_radio_button("attachments[{$attachment['aid']}]", "approve", $lang->approve, array('class' => 'radio_approve', 'checked' => false)), array("class" => "align_center")); + $table->construct_row(); + } + $table->output($lang->attachments_awaiting_moderation); + echo $all_options; + echo $pagination; + + $buttons[] = $form->generate_submit_button($lang->perform_action); + $form->output_submit_wrapper($buttons); + $form->end(); + + echo ''; + + $page->output_footer(); + } + else if($mybb->input['type'] == "attachments") + { + $page->output_header($lang->moderation_queue); + $page->output_nav_tabs($sub_tabs, "attachments"); + echo "

{$lang->error_no_attachments}

"; + $page->output_footer(); + } +} + +// Still nothing? All queues are empty! :-D +$page->output_header($lang->moderation_queue); +echo "

{$lang->error_no_threads}

"; +$page->output_footer(); diff --git a/Upload/admin/modules/forum/module_meta.php b/Upload/admin/modules/forum/module_meta.php new file mode 100644 index 0000000..e4a0713 --- /dev/null +++ b/Upload/admin/modules/forum/module_meta.php @@ -0,0 +1,76 @@ +
Please make sure IN_MYBB is defined."); +} + +function forum_meta() +{ + global $page, $lang, $plugins; + + $sub_menu = array(); + $sub_menu['10'] = array("id" => "management", "title" => $lang->forum_management, "link" => "index.php?module=forum-management"); + $sub_menu['20'] = array("id" => "announcements", "title" => $lang->forum_announcements, "link" => "index.php?module=forum-announcements"); + $sub_menu['30'] = array("id" => "moderation_queue", "title" => $lang->moderation_queue, "link" => "index.php?module=forum-moderation_queue"); + $sub_menu['40'] = array("id" => "attachments", "title" => $lang->attachments, "link" => "index.php?module=forum-attachments"); + + $sub_menu = $plugins->run_hooks("admin_forum_menu", $sub_menu); + + $page->add_menu_item($lang->forums_and_posts, "forum", "index.php?module=forum", 20, $sub_menu); + + return true; +} + +function forum_action_handler($action) +{ + global $page, $lang, $plugins; + + $page->active_module = "forum"; + + $actions = array( + 'moderation_queue' => array('active' => 'moderation_queue', 'file' => 'moderation_queue.php'), + 'announcements' => array('active' => 'announcements', 'file' => 'announcements.php'), + 'attachments' => array('active' => 'attachments', 'file' => 'attachments.php'), + 'management' => array('active' => 'management', 'file' => 'management.php') + ); + + $actions = $plugins->run_hooks("admin_forum_action_handler", $actions); + + if(isset($actions[$action])) + { + $page->active_action = $actions[$action]['active']; + return $actions[$action]['file']; + } + else + { + $page->active_action = "management"; + return "management.php"; + } +} + +function forum_admin_permissions() +{ + global $lang, $plugins; + + $admin_permissions = array( + "management" => $lang->can_manage_forums, + "announcements" => $lang->can_manage_forum_announcements, + "moderation_queue" => $lang->can_moderate, + "attachments" => $lang->can_manage_attachments, + ); + + $admin_permissions = $plugins->run_hooks("admin_forum_permissions", $admin_permissions); + + return array("name" => $lang->forums_and_posts, "permissions" => $admin_permissions, "disporder" => 20); +} + diff --git a/Upload/admin/modules/home/credits.php b/Upload/admin/modules/home/credits.php new file mode 100644 index 0000000..89b1840 --- /dev/null +++ b/Upload/admin/modules/home/credits.php @@ -0,0 +1,148 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->mybb_credits, "index.php?module=home-credits"); + +$plugins->run_hooks("admin_home_credits_begin"); + +if(!$mybb->input['action']) +{ + $page->output_header($lang->mybb_credits); + + $sub_tabs['credits'] = array( + 'title' => $lang->mybb_credits, + 'link' => "index.php?module=home-credits", + 'description' => $lang->mybb_credits_description + ); + + $sub_tabs['credits_about'] = array( + 'title' => $lang->about_the_team, + 'link' => "http://www.mybb.com/about/team", + 'link_target' => "_blank", + ); + + $sub_tabs['check_for_updates'] = array( + 'title' => $lang->check_for_updates, + 'link' => "index.php?module=home-credits&fetch_new=1", + ); + + $plugins->run_hooks("admin_home_credits_start"); + + $page->output_nav_tabs($sub_tabs, 'credits'); + + $mybb_credits = $cache->read('mybb_credits'); + + if($mybb->get_input('fetch_new', 1) == 1 || $mybb->get_input('fetch_new', 1) == -2 || ($mybb->get_input('fetch_new', 1) != -1 && (!is_array($mybb_credits) || $mybb_credits['last_check'] <= TIME_NOW - 60*60*24*14))) + { + $new_mybb_credits = array( + 'last_check' => TIME_NOW + ); + + require_once MYBB_ROOT."inc/class_xml.php"; + $contents = fetch_remote_file("http://www.mybb.com/mybb_team.xml"); + + if(!$contents) + { + flash_message($lang->error_communication, 'error'); + if($mybb->get_input('fetch_new', 1) == -2) + { + admin_redirect('index.php?module=tools-cache'); + } + admin_redirect('index.php?module=home-credits&fetch_new=-1'); + } + + $parser = new XMLParser($contents); + $tree = $parser->get_tree(); + $mybbgroup = array(); + foreach($tree['mybbgroup']['team'] as $team) + { + $members = array(); + foreach($team['member'] as $member) + { + $members[] = array( + 'name' => htmlspecialchars_uni($member['name']['value']), + 'username' => htmlspecialchars_uni($member['username']['value']), + 'profile' => htmlspecialchars_uni($member['profile']['value']), + 'lead' => (bool)$member['attributes']['lead'] or false + ); + } + $mybbgroup[] = array( + 'title' => htmlspecialchars_uni($team['attributes']['title']), + 'members' => $members + ); + } + $new_mybb_credits['credits'] = $mybbgroup; + + $cache->update('mybb_credits', $new_mybb_credits); + + if($mybb->get_input('fetch_new', 1) == -2) + { + $lang->load('tools_cache'); + flash_message($lang->success_cache_reloaded, 'sucess'); + admin_redirect('index.php?module=tools-cache'); + } + $mybb_credits = $new_mybb_credits; + } + + if(empty($mybb_credits) || (is_array($mybb_credits) && empty($mybb_credits['credits']))) + { + $table = new Table; + $table->construct_cell($lang->no_credits); + $table->construct_row(); + } + else + { + $largest_count = $i = 0; + $team_max = array(); + foreach($mybb_credits['credits'] as $team) + { + $count = count($team['members']); + $team_max[$i++] = $count; + if($largest_count < $count) + { + $largest_count = $count; + } + } + $largest_count -= 1; + + $table = new Table; + foreach($mybb_credits['credits'] as $team) + { + $table->construct_header($team['title'], array('width' => '16%')); + } + + for($i = 0; $i <= $largest_count; $i++) + { + foreach($team_max as $team => $max) + { + if($max < $i) + { + $table->construct_cell(" "); + } + else + { + $table->construct_cell("{$mybb_credits['credits'][$team]['members'][$i]['name']}"); + } + } + $table->construct_row(); + } + } + + $table->output($lang->mybb_credits); + + $page->output_footer(); +} + diff --git a/Upload/admin/modules/home/index.html b/Upload/admin/modules/home/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/modules/home/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/modules/home/index.php b/Upload/admin/modules/home/index.php new file mode 100644 index 0000000..9ed52ca --- /dev/null +++ b/Upload/admin/modules/home/index.php @@ -0,0 +1,374 @@ +
Please make sure IN_MYBB is defined."); +} + +$plugins->run_hooks("admin_home_index_begin"); + +$sub_tabs['dashboard'] = array( + 'title' => $lang->dashboard, + 'link' => "index.php", + 'description' => $lang->dashboard_description +); + +$sub_tabs['version_check'] = array( + 'title' => $lang->version_check, + 'link' => "index.php?module=home&action=version_check", + 'description' => $lang->version_check_description +); + +if($mybb->input['action'] == "version_check") +{ + $plugins->run_hooks("admin_home_version_check_start"); + + $current_version = rawurlencode($mybb->version_code); + + $updated_cache = array( + "last_check" => TIME_NOW + ); + + require_once MYBB_ROOT."inc/class_xml.php"; + $contents = fetch_remote_file("http://www.mybb.com/version_check.php"); + + if(!$contents) + { + flash_message($lang->error_communication, 'error'); + admin_redirect('index.php'); + } + + $plugins->run_hooks("admin_home_version_check"); + + $page->add_breadcrumb_item($lang->version_check, "index.php?module=home-version_check"); + $page->output_header($lang->version_check); + $page->output_nav_tabs($sub_tabs, 'version_check'); + + // We do this because there is some weird symbols that show up in the xml file for unknown reasons + $pos = strpos($contents, "<"); + if($pos > 1) + { + $contents = substr($contents, $pos); + } + + $pos = strpos(strrev($contents), ">"); + if($pos > 1) + { + $contents = substr($contents, 0, (-1) * ($pos-1)); + } + + $parser = new XMLParser($contents); + $tree = $parser->get_tree(); + + $latest_code = (int)$tree['mybb']['version_code']['value']; + $latest_version = "".htmlspecialchars_uni($tree['mybb']['latest_version']['value'])." (".$latest_code.")"; + if($latest_code > $mybb->version_code) + { + $latest_version = "".$latest_version.""; + $version_warn = 1; + $updated_cache['latest_version'] = $latest_version; + $updated_cache['latest_version_code'] = $latest_code; + } + else + { + $latest_version = "".$latest_version.""; + } + + if($version_warn) + { + $page->output_error("

{$lang->error_out_of_date} {$lang->update_forum}

"); + } + else + { + $page->output_success("

{$lang->success_up_to_date}

"); + } + + $table = new Table; + $table->construct_header($lang->your_version); + $table->construct_header($lang->latest_version); + + $table->construct_cell("".$mybb->version." (".$mybb->version_code.")"); + $table->construct_cell($latest_version); + $table->construct_row(); + + $table->output($lang->version_check); + + require_once MYBB_ROOT."inc/class_feedparser.php"; + + $feed_parser = new FeedParser(); + $feed_parser->parse_feed("http://feeds.feedburner.com/MyBBDevelopmentBlog"); + + $updated_cache['news'] = array(); + + require_once MYBB_ROOT . '/inc/class_parser.php'; + $post_parser = new postParser(); + + if($feed_parser->error == '') + { + foreach($feed_parser->items as $item) + { + if(!isset($updated_cache['news'][2])) + { + $description = $item['description']; + $content = $item['content']; + + $description = $post_parser->parse_message($description, array( + 'allow_html' => true, + ) + ); + + $content = $post_parser->parse_message($content, array( + 'allow_html' => true, + ) + ); + + $updated_cache['news'][] = array( + 'title' => htmlspecialchars_uni($item['title']), + 'description' => preg_replace('##', '', $description), + 'link' => htmlspecialchars_uni($item['link']), + 'author' => htmlspecialchars_uni($item['author']), + 'dateline' => $item['date_timestamp'], + ); + } + + $stamp = ''; + if($item['date_timestamp']) + { + $stamp = my_date('relative', $item['date_timestamp']); + } + + $link = htmlspecialchars_uni($item['link']); + + $table->construct_cell("".htmlspecialchars_uni($item['title'])."

{$content}{$stamp}

» {$lang->read_more}
"); + $table->construct_row(); + } + } + else + { + $table->construct_cell("{$lang->error_fetch_news} "); + $table->construct_row(); + } + + $cache->update("update_check", $updated_cache); + + $table->output($lang->latest_mybb_announcements); + $page->output_footer(); +} +elseif(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_home_index_start"); + + if($mybb->request_method == "post" && isset($mybb->input['adminnotes'])) + { + // Update Admin Notes cache + $update_cache = array( + "adminmessage" => $mybb->input['adminnotes'] + ); + + $cache->update("adminnotes", $update_cache); + + $plugins->run_hooks("admin_home_index_start_begin"); + + flash_message($lang->success_notes_updated, 'success'); + admin_redirect("index.php"); + } + + $page->add_breadcrumb_item($lang->dashboard); + $page->output_header($lang->dashboard); + + $sub_tabs['dashboard'] = array( + 'title' => $lang->dashboard, + 'link' => "index.php", + 'description' => $lang->dashboard_description + ); + + $page->output_nav_tabs($sub_tabs, 'dashboard'); + + // Load stats cache + $stats = $cache->read("stats"); + + $serverload = get_server_load(); + + // Get the number of users + $query = $db->simple_select("users", "COUNT(uid) AS numusers"); + $users = my_number_format($db->fetch_field($query, "numusers")); + + // Get the number of users awaiting validation + $awaitingusers = $cache->read('awaitingactivation'); + + if(!empty($awaitingusers['users'])) + { + $awaitingusers = (int)$awaitingusers['users']; + } + else + { + $awaitingusers = 0; + } + + if($awaitingusers < 1) + { + $awaitingusers = 0; + } + else + { + $awaitingusers = my_number_format($awaitingusers); + } + + // Get the number of new users for today + $timecut = TIME_NOW - 86400; + $query = $db->simple_select("users", "COUNT(uid) AS newusers", "regdate > '$timecut'"); + $newusers = my_number_format($db->fetch_field($query, "newusers")); + + // Get the number of active users today + $query = $db->simple_select("users", "COUNT(uid) AS activeusers", "lastvisit > '$timecut'"); + $activeusers = my_number_format($db->fetch_field($query, "activeusers")); + + // Get the number of threads + $threads = my_number_format($stats['numthreads']); + + // Get the number of unapproved threads + $unapproved_threads = my_number_format($stats['numunapprovedthreads']); + + // Get the number of new threads for today + $query = $db->simple_select("threads", "COUNT(*) AS newthreads", "dateline > '$timecut' AND visible='1' AND closed NOT LIKE 'moved|%'"); + $newthreads = my_number_format($db->fetch_field($query, "newthreads")); + + // Get the number of posts + $posts = my_number_format($stats['numposts']); + + // Get the number of unapproved posts + if($stats['numunapprovedposts'] < 0) + { + $stats['numunapprovedposts'] = 0; + } + + $unapproved_posts = my_number_format($stats['numunapprovedposts']); + + // Get the number of new posts for today + $query = $db->simple_select("posts", "COUNT(*) AS newposts", "dateline > '$timecut' AND visible='1'"); + $newposts = my_number_format($db->fetch_field($query, "newposts")); + + // Get the number of reported post + $query = $db->simple_select("reportedcontent", "COUNT(*) AS reported_posts", "type = 'post' OR type = ''"); + $reported_posts = my_number_format($db->fetch_field($query, "reported_posts")); + + // Get the number of reported posts that haven't been marked as read yet + $query = $db->simple_select("reportedcontent", "COUNT(*) AS new_reported_posts", "reportstatus='0' AND (type = 'post' OR type = '')"); + $new_reported_posts = my_number_format($db->fetch_field($query, "new_reported_posts")); + + // Get the number and total file size of attachments + $query = $db->simple_select("attachments", "COUNT(*) AS numattachs, SUM(filesize) as spaceused", "visible='1' AND pid > '0'"); + $attachs = $db->fetch_array($query); + $attachs['spaceused'] = get_friendly_size($attachs['spaceused']); + $approved_attachs = my_number_format($attachs['numattachs']); + + // Get the number of unapproved attachments + $query = $db->simple_select("attachments", "COUNT(*) AS numattachs", "visible='0' AND pid > '0'"); + $unapproved_attachs = my_number_format($db->fetch_field($query, "numattachs")); + + // Fetch the last time an update check was run + $update_check = $cache->read("update_check"); + + // If last update check was greater than two weeks ago (14 days) show an alert + if(isset($update_check['last_check']) && $update_check['last_check'] <= TIME_NOW-60*60*24*14) + { + $lang->last_update_check_two_weeks = $lang->sprintf($lang->last_update_check_two_weeks, "index.php?module=home&action=version_check"); + $page->output_error("

{$lang->last_update_check_two_weeks}

"); + } + + // If the update check contains information about a newer version, show an alert + if(isset($update_check['latest_version_code']) && $update_check['latest_version_code'] > $mybb->version_code) + { + $lang->new_version_available = $lang->sprintf($lang->new_version_available, "MyBB {$mybb->version}", "MyBB {$update_check['latest_version']}"); + $page->output_error("

{$lang->new_version_available}

"); + } + + $plugins->run_hooks("admin_home_index_output_message"); + + $adminmessage = $cache->read("adminnotes"); + + $table = new Table; + $table->construct_header($lang->mybb_server_stats, array("colspan" => 2)); + $table->construct_header($lang->forum_stats, array("colspan" => 2)); + + $table->construct_cell("{$lang->mybb_version}", array('width' => '25%')); + $table->construct_cell($mybb->version, array('width' => '25%')); + $table->construct_cell("{$lang->threads}", array('width' => '25%')); + $table->construct_cell("{$threads} {$lang->threads}
{$newthreads} {$lang->new_today}
{$unapproved_threads} {$lang->unapproved}", array('width' => '25%')); + $table->construct_row(); + + $table->construct_cell("{$lang->php_version}", array('width' => '25%')); + $table->construct_cell(PHP_VERSION, array('width' => '25%')); + $table->construct_cell("{$lang->posts}", array('width' => '25%')); + $table->construct_cell("{$posts} {$lang->posts}
{$newposts} {$lang->new_today}
{$unapproved_posts} {$lang->unapproved}
{$reported_posts} {$lang->reported_posts}
{$new_reported_posts} {$lang->unread_reports}", array('width' => '25%')); + $table->construct_row(); + + $table->construct_cell("{$lang->sql_engine}", array('width' => '25%')); + $table->construct_cell($db->short_title." ".$db->get_version(), array('width' => '25%')); + $table->construct_cell("{$lang->users}", array('width' => '25%')); + $table->construct_cell("{$users} {$lang->registered_users}
{$activeusers} {$lang->active_users}
{$newusers} {$lang->registrations_today}
'5')))."&from=home\">{$awaitingusers} {$lang->awaiting_activation}", array('width' => '25%')); + $table->construct_row(); + + $table->construct_cell("{$lang->server_load}", array('width' => '25%')); + $table->construct_cell($serverload, array('width' => '25%')); + $table->construct_cell("{$lang->attachments}", array('width' => '25%')); + $table->construct_cell("{$approved_attachs} {$lang->attachments}
{$unapproved_attachs} {$lang->unapproved}
{$attachs['spaceused']} {$lang->used}", array('width' => '25%')); + $table->construct_row(); + + $table->output($lang->dashboard); + + echo ' +
'; + + $table = new Table; + $table->construct_header($lang->admin_notes_public); + + $form = new Form("index.php", "post"); + $table->construct_cell($form->generate_text_area("adminnotes", $adminmessage['adminmessage'], array('style' => 'width: 99%; height: 200px;'))); + $table->construct_row(); + + $table->output($lang->admin_notes); + + $buttons[] = $form->generate_submit_button($lang->save_notes); + $form->output_submit_wrapper($buttons); + $form->end(); + + echo '
+
'; + + // Latest news widget + $table = new Table; + $table->construct_header($lang->news_description); + + if(!empty($update_check['news']) && is_array($update_check['news'])) + { + foreach($update_check['news'] as $news_item) + { + $posted = my_date('relative', $news_item['dateline']); + $table->construct_cell("{$news_item['title']}
{$posted}"); + $table->construct_row(); + + $table->construct_cell($news_item['description']); + $table->construct_row(); + } + } + else + { + $table->construct_cell($lang->no_announcements); + $table->construct_row(); + } + + $table->output($lang->latest_mybb_announcements); + echo '
'; + + $page->output_footer(); +} diff --git a/Upload/admin/modules/home/module_meta.php b/Upload/admin/modules/home/module_meta.php new file mode 100644 index 0000000..fdfe79e --- /dev/null +++ b/Upload/admin/modules/home/module_meta.php @@ -0,0 +1,173 @@ +
Please make sure IN_MYBB is defined."); +} + +function home_meta() +{ + global $page, $lang, $plugins; + + $sub_menu = array(); + $sub_menu['10'] = array("id" => "dashboard", "title" => $lang->dashboard, "link" => "index.php?module=home-dashboard"); + $sub_menu['20'] = array("id" => "preferences", "title" => $lang->preferences, "link" => "index.php?module=home-preferences"); + $sub_menu['30'] = array("id" => "docs", "title" => $lang->mybb_documentation, "link" => "http://docs.mybb.com"); + $sub_menu['40'] = array("id" => "credits", "title" => $lang->mybb_credits, "link" => "index.php?module=home-credits"); + $sub_menu = $plugins->run_hooks("admin_home_menu", $sub_menu); + + $page->add_menu_item($lang->home, "home", "index.php", 1, $sub_menu); + + return true; +} + +function home_action_handler($action) +{ + global $page, $db, $lang, $plugins; + + $page->active_module = "home"; + + $actions = array( + 'preferences' => array('active' => 'preferences', 'file' => 'preferences.php'), + 'credits' => array('active' => 'credits', 'file' => 'credits.php'), + 'version_check' => array('active' => 'version_check', 'file' => 'version_check.php'), + 'dashboard' => array('active' => 'dashboard', 'file' => 'index.php') + ); + + if(!isset($actions[$action])) + { + $page->active_action = "dashboard"; + } + else + { + $page->active_action = $actions[$action]['active']; + } + + $actions = $plugins->run_hooks("admin_home_action_handler", $actions); + + if($page->active_action == "dashboard") + { + // Quick Access + $sub_menu = array(); + $sub_menu['10'] = array("id" => "add_forum", "title" => $lang->add_new_forum, "link" => "index.php?module=forum-management&action=add"); + $sub_menu['20'] = array("id" => "search", "title" => $lang->search_for_users, "link" => "index.php?module=user-users&action=search"); + $sub_menu['30'] = array("id" => "themes", "title" => $lang->themes, "link" => "index.php?module=style-themes"); + $sub_menu['40'] = array("id" => "templates", "title" => $lang->templates, "link" => "index.php?module=style-templates"); + $sub_menu['50'] = array("id" => "plugins", "title" => $lang->plugins, "link" => "index.php?module=config-plugins"); + $sub_menu['60'] = array("id" => "backupdb", "title" => $lang->database_backups, "link" => "index.php?module=tools-backupdb"); + + $sub_menu = $plugins->run_hooks("admin_home_menu_quick_access", $sub_menu); + + $sidebar = new SidebarItem($lang->quick_access); + $sidebar->add_menu_items($sub_menu, $page->active_action); + + $page->sidebar .= $sidebar->get_markup(); + + // Online Administrators in the last 30 minutes + $timecut = TIME_NOW-60*30; + $query = $db->simple_select("adminsessions", "uid, ip, useragent", "lastactive > {$timecut}"); + $online_users = "
    "; + $online_admins = array(); + + // If there's only 1 user online, it has to be us. + if($db->num_rows($query) == 1) + { + $user = $db->fetch_array($query); + global $mybb; + + // Are we on a mobile device? + // Stolen from http://stackoverflow.com/a/10989424 + $user_type = "desktop"; + if(is_mobile($user["useragent"])) + { + $user_type = "mobile"; + } + + $online_admins[$mybb->user['username']] = array( + "uid" => $mybb->user['uid'], + "username" => $mybb->user['username'], + "ip" => $user["ip"], + "type" => $user_type + ); + } + else + { + $uid_in = array(); + while($user = $db->fetch_array($query)) + { + $uid_in[] = $user['uid']; + + $user_type = "desktop"; + if(is_mobile($user['useragent'])) + { + $user_type = "mobile"; + } + + $online_admins[$user['uid']] = array( + "ip" => $user['ip'], + "type" => $user_type + ); + } + + $query = $db->simple_select("users", "uid, username", "uid IN(".implode(',', $uid_in).")", array('order_by' => 'username')); + while($user = $db->fetch_array($query)) + { + $online_admins[$user['username']] = array( + "uid" => $user['uid'], + "username" => $user['username'], + "ip" => $online_admins[$user['uid']]['ip'], + "type" => $online_admins[$user['uid']]['type'] + ); + unset($online_admins[$user['uid']]); + } + } + + $done_users = array(); + + asort($online_admins); + + foreach($online_admins as $user) + { + if(!isset($done_users["{$user['uid']}.{$user['ip']}"])) + { + if($user['type'] == "mobile") + { + $class = " class=\"mobile_user\""; + } + else + { + $class = ""; + } + $ip_address = my_inet_ntop($db->unescape_binary($user['ip'])); + $online_users .= "
  • ipaddress} {$ip_address}\"{$class}>".build_profile_link($user['username'].' ('.$ip_address.')', $user['uid'], "_blank")."
  • "; + $done_users["{$user['uid']}.{$user['ip']}"] = 1; + } + } + $online_users .= "
"; + $sidebar = new SidebarItem($lang->online_admins); + $sidebar->set_contents($online_users); + + $page->sidebar .= $sidebar->get_markup(); + } + + if(isset($actions[$action])) + { + $page->active_action = $actions[$action]['active']; + return $actions[$action]['file']; + } + else + { + $page->active_action = "dashboard"; + return "index.php"; + } +} + diff --git a/Upload/admin/modules/home/preferences.php b/Upload/admin/modules/home/preferences.php new file mode 100644 index 0000000..3f65ca7 --- /dev/null +++ b/Upload/admin/modules/home/preferences.php @@ -0,0 +1,107 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->preferences_and_personal_notes, "index.php?module=home-preferences"); + +$plugins->run_hooks("admin_home_preferences_begin"); + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_home_preferences_start"); + + if($mybb->request_method == "post") + { + $query = $db->simple_select("adminoptions", "permissions, defaultviews", "uid='{$mybb->user['uid']}'"); + $adminopts = $db->fetch_array($query); + + $sqlarray = array( + "notes" => $db->escape_string($mybb->input['notes']), + "cpstyle" => $db->escape_string($mybb->input['cpstyle']), + "cplanguage" => $db->escape_string($mybb->input['cplanguage']), + "permissions" => $db->escape_string($adminopts['permissions']), + "defaultviews" => $db->escape_string($adminopts['defaultviews']), + "uid" => $mybb->user['uid'], + "codepress" => (int)$mybb->input['codepress'], // It's actually CodeMirror but for compatibility purposes lets leave it codepress + ); + + $db->replace_query("adminoptions", $sqlarray, "uid"); + + $plugins->run_hooks("admin_home_preferences_start_commit"); + + flash_message($lang->success_preferences_updated, 'success'); + admin_redirect("index.php?module=home-preferences"); + } + + $page->output_header($lang->preferences_and_personal_notes); + + $sub_tabs['preferences'] = array( + 'title' => $lang->preferences_and_personal_notes, + 'link' => "index.php?module=home-preferences", + 'description' => $lang->prefs_and_personal_notes_description + ); + + $page->output_nav_tabs($sub_tabs, 'preferences'); + + $query = $db->simple_select("adminoptions", "notes, cpstyle, cplanguage, codepress", "uid='".$mybb->user['uid']."'", array('limit' => 1)); + $admin_options = $db->fetch_array($query); + + $form = new Form("index.php?module=home-preferences", "post"); + $dir = @opendir(MYBB_ADMIN_DIR."/styles"); + + $folders = array(); + while($folder = readdir($dir)) + { + if($folder != "." && $folder != ".." && @file_exists(MYBB_ADMIN_DIR."/styles/$folder/main.css")) + { + $folders[$folder] = ucfirst($folder); + } + } + closedir($dir); + ksort($folders); + $setting_code = $form->generate_select_box("cpstyle", $folders, $admin_options['cpstyle']); + + $languages = $lang->get_languages(1); + $language_code = $form->generate_select_box("cplanguage", $languages, $admin_options['cplanguage']); + + $table = new Table; + $table->construct_header($lang->global_preferences); + + $table->construct_cell("{$lang->acp_theme}
{$lang->select_acp_theme}

{$setting_code}"); + $table->construct_row(); + + $table->construct_cell("{$lang->acp_language}
{$lang->select_acp_language}

{$language_code}"); + $table->construct_row(); + + $table->construct_cell("{$lang->codemirror}
{$lang->use_codemirror_desc}

".$form->generate_on_off_radio('codepress', $admin_options['codepress'])); + $table->construct_row(); + + $table->output($lang->preferences); + + $table->construct_header($lang->notes_not_shared); + + $table->construct_cell($form->generate_text_area("notes", $admin_options['notes'], array('style' => 'width: 99%; height: 300px;'))); + $table->construct_row(); + + $table->output($lang->personal_notes); + + $buttons[] = $form->generate_submit_button($lang->save_notes_and_prefs); + $form->output_submit_wrapper($buttons); + + $form->end(); + + $page->output_footer(); +} + diff --git a/Upload/admin/modules/index.html b/Upload/admin/modules/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/modules/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/modules/style/index.html b/Upload/admin/modules/style/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/modules/style/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/modules/style/module_meta.php b/Upload/admin/modules/style/module_meta.php new file mode 100644 index 0000000..6793187 --- /dev/null +++ b/Upload/admin/modules/style/module_meta.php @@ -0,0 +1,68 @@ +
Please make sure IN_MYBB is defined."); +} + +function style_meta() +{ + global $page, $lang, $plugins; + + $sub_menu = array(); + $sub_menu['10'] = array("id" => "themes", "title" => $lang->themes, "link" => "index.php?module=style-themes"); + $sub_menu['20'] = array("id" => "templates", "title" => $lang->templates, "link" => "index.php?module=style-templates"); + + $sub_menu = $plugins->run_hooks("admin_style_menu", $sub_menu); + + $page->add_menu_item($lang->templates_and_style, "style", "index.php?module=style", 40, $sub_menu); + return true; +} + +function style_action_handler($action) +{ + global $page, $lang, $plugins; + + $page->active_module = "style"; + + $actions = array( + 'templates' => array('active' => 'templates', 'file' => 'templates.php'), + 'themes' => array('active' => 'themes', 'file' => 'themes.php') + ); + + $actions = $plugins->run_hooks("admin_style_action_handler", $actions); + + if(isset($actions[$action])) + { + $page->active_action = $actions[$action]['active']; + return $actions[$action]['file']; + } + else + { + $page->active_action = "themes"; + return "themes.php"; + } +} + +function style_admin_permissions() +{ + global $lang, $plugins; + + $admin_permissions = array( + "themes" => $lang->can_manage_themes, + "templates" => $lang->can_manage_templates, + ); + + $admin_permissions = $plugins->run_hooks("admin_style_permissions", $admin_permissions); + + return array("name" => $lang->templates_and_style, "permissions" => $admin_permissions, "disporder" => 40); +} diff --git a/Upload/admin/modules/style/templates.php b/Upload/admin/modules/style/templates.php new file mode 100644 index 0000000..b9929fb --- /dev/null +++ b/Upload/admin/modules/style/templates.php @@ -0,0 +1,1962 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->template_sets, "index.php?module=style-templates"); + +$sid = $mybb->get_input('sid', 1); + +$expand_str = ""; +$expand_str2 = ""; +$expand_array = array(); +if(isset($mybb->input['expand'])) +{ + $expand_array = explode("|", $mybb->input['expand']); + $expand_array = array_map("intval", $expand_array); + $expand_str = "&expand=".implode("|", $expand_array); + $expand_str2 = "&expand=".implode("|", $expand_array); +} + +if($mybb->input['action'] == "add_set" || $mybb->input['action'] == "add_template" || ($mybb->input['action'] == "add_template_group" && !$sid) || $mybb->input['action'] == "search_replace" || $mybb->input['action'] == "find_updated" || (!$mybb->input['action'] && !$sid)) +{ + $sub_tabs['templates'] = array( + 'title' => $lang->manage_template_sets, + 'link' => "index.php?module=style-templates", + 'description' => $lang->manage_template_sets_desc + ); + + $sub_tabs['add_set'] = array( + 'title' => $lang->add_set, + 'link' => "index.php?module=style-templates&action=add_set".$expand_str + ); + + if($mybb->get_input('sid', 1) != -1) + { + $sub_tabs['add_template_group'] = array( + 'title' => $lang->add_template_group, + 'link' => "index.php?module=style-templates&action=add_template_group".$expand_str, + 'description' => $lang->add_template_group_desc + ); + } + + $sub_tabs['search_replace'] = array( + 'title' => $lang->search_replace, + 'link' => "index.php?module=style-templates&action=search_replace", + 'description' => $lang->search_replace_desc + ); + + $sub_tabs['find_updated'] = array( + 'title' => $lang->find_updated, + 'link' => "index.php?module=style-templates&action=find_updated", + 'description' => $lang->find_updated_desc + ); +} +else if(($sid && !$mybb->input['action']) || $mybb->input['action'] == "edit_set" || $mybb->input['action'] == "check_set" || $mybb->input['action'] == "edit_template" || $mybb->input['action'] == "add_template_group") +{ + $sub_tabs['manage_templates'] = array( + 'title' => $lang->manage_templates, + 'link' => "index.php?module=style-templates&sid=".$sid.$expand_str, + 'description' => $lang->manage_templates_desc + ); + + if($sid > 0) + { + $sub_tabs['edit_set'] = array( + 'title' => $lang->edit_set, + 'link' => "index.php?module=style-templates&action=edit_set&sid=".$sid.$expand_str, + 'description' => $lang->edit_set_desc + ); + } + + $sub_tabs['add_template'] = array( + 'title' => $lang->add_template, + 'link' => "index.php?module=style-templates&action=add_template&sid=".$sid.$expand_str, + 'description' => $lang->add_template_desc + ); + + if($mybb->get_input('sid', 1) != -1) + { + $sub_tabs['add_template_group'] = array( + 'title' => $lang->add_template_group, + 'link' => "index.php?module=style-templates&action=add_template_group&sid=".$sid.$expand_str, + 'description' => $lang->add_template_group_desc + ); + } +} + +$template_sets = array(); +$template_sets[-1] = $lang->global_templates; + +$query = $db->simple_select("templatesets", "*", "", array('order_by' => 'title', 'order_dir' => 'ASC')); +while($template_set = $db->fetch_array($query)) +{ + $template_sets[$template_set['sid']] = $template_set['title']; +} + +$plugins->run_hooks("admin_style_templates"); + +if($mybb->input['action'] == "add_set") +{ + $plugins->run_hooks("admin_style_templates_add_set"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_set_title; + } + + if(!$errors) + { + $sid = $db->insert_query("templatesets", array('title' => $db->escape_string($mybb->input['title']))); + + $plugins->run_hooks("admin_style_templates_add_set_commit"); + + // Log admin action + log_admin_action($sid, $mybb->input['title']); + + flash_message($lang->success_template_set_saved, 'success'); + admin_redirect("index.php?module=style-templates&sid=".$sid); + } + } + + $page->add_breadcrumb_item($lang->add_set); + + $page->output_header($lang->add_set); + + $sub_tabs = array(); + $sub_tabs['add_set'] = array( + 'title' => $lang->add_set, + 'link' => "index.php?module=style-templates&action=add_set", + 'description' => $lang->add_set_desc + ); + + $page->output_nav_tabs($sub_tabs, 'add_set'); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['title'] = ""; + } + + $form = new Form("index.php?module=style-templates&action=add_set", "post", "add_set"); + + $form_container = new FormContainer($lang->add_set); + $form_container->output_row($lang->title, "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->end(); + + $buttons = array(); + $buttons[] = $form->generate_submit_button($lang->save); + + $form->output_submit_wrapper($buttons); + + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "add_template") +{ + $plugins->run_hooks("admin_style_templates_add_template"); + + if($mybb->request_method == "post") + { + if(empty($mybb->input['title'])) + { + $errors[] = $lang->error_missing_set_title; + } + else + { + $query = $db->simple_select("templates", "COUNT(tid) as count", "title='".$db->escape_string($mybb->input['title'])."' AND (sid = '-2' OR sid = '{$sid}')"); + if($db->fetch_field($query, "count") > 0) + { + $errors[] = $lang->error_already_exists; + } + } + + if(!isset($template_sets[$sid])) + { + $errors[] = $lang->error_invalid_set; + } + + // Are we trying to do malicious things in our template? + if(check_template($mybb->input['template'])) + { + $errors[] = $lang->error_security_problem; + } + + if(!$errors) + { + $template_array = array( + 'title' => $db->escape_string($mybb->input['title']), + 'sid' => $sid, + 'template' => $db->escape_string(rtrim($mybb->input['template'])), + 'version' => $db->escape_string($mybb->version_code), + 'status' => '', + 'dateline' => TIME_NOW + ); + + $tid = $db->insert_query("templates", $template_array); + + $plugins->run_hooks("admin_style_templates_add_template_commit"); + + // Log admin action + log_admin_action($tid, $mybb->input['title'], $sid, $template_sets[$sid]); + + flash_message($lang->success_template_saved, 'success'); + + if($mybb->input['continue']) + { + admin_redirect("index.php?module=style-templates&action=edit_template&title=".urlencode($mybb->input['title'])."&sid=".$sid.$expand_str2); + } + else + { + admin_redirect("index.php?module=style-templates&sid=".$sid.$expand_str2); + } + } + } + + if($errors) + { + $template = $mybb->input; + } + else + { + if(!$sid) + { + $sid = -1; + } + + $template['template'] = ""; + $template['sid'] = $sid; + } + + if($mybb->input['sid']) + { + $page->add_breadcrumb_item($template_sets[$sid], "index.php?module=style-templates&sid={$sid}{$expand_str}"); + } + + if($admin_options['codepress'] != 0) + { + $page->extra_header .= ' + + + + + + + + + + + +'; + } + + $page->add_breadcrumb_item($lang->add_template); + + $page->output_header($lang->add_template); + + $sub_tabs = array(); + $sub_tabs['add_template'] = array( + 'title' => $lang->add_template, + 'link' => "index.php?module=style-templates&action=add_template&sid=".$template['sid'].$expand_str, + 'description' => $lang->add_template_desc + ); + + $page->output_nav_tabs($sub_tabs, 'add_template'); + + if($errors) + { + $page->output_inline_error($errors); + } + + $form = new Form("index.php?module=style-templates&action=add_template{$expand_str}", "post", "add_template"); + + $form_container = new FormContainer($lang->add_template); + $form_container->output_row($lang->template_name, $lang->template_name_desc, $form->generate_text_box('title', $template['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->template_set, $lang->template_set_desc, $form->generate_select_box('sid', $template_sets, $sid), 'sid'); + $form_container->output_row("", "", $form->generate_text_area('template', $template['template'], array('id' => 'template', 'class' => '', 'style' => 'width: 100%; height: 500px;')), 'template'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_continue, array('name' => 'continue')); + $buttons[] = $form->generate_submit_button($lang->save_close, array('name' => 'close')); + + $form->output_submit_wrapper($buttons); + + $form->end(); + + if($admin_options['codepress'] != 0) + { + echo ""; + } + + $page->output_footer(); +} + +if($mybb->input['action'] == "add_template_group") +{ + $plugins->run_hooks("admin_style_templates_add_template_group"); + + if($mybb->get_input('sid', 1) == -1) + { + admin_redirect("index.php?module=style-templates&sid={$sid}".$expand_str2); + } + + $errors = array(); + if($mybb->request_method == "post") + { + $prefix = trim($mybb->input['prefix']); + if(!$prefix) + { + $errors[] = $lang->error_missing_group_prefix; + } + + $title = trim($mybb->input['title']); + if(!$title) + { + $errors[] = $lang->error_missing_group_title; + } + + if(!$errors) + { + $query = $db->simple_select("templategroups", "COUNT(gid) AS gid", "prefix = '".$db->escape_string($mybb->input['prefix'])."'"); + $prefix_count = $db->fetch_field($query, 'gid'); + + if($prefix_count >= 1) + { + $errors[] = $lang->error_duplicate_group_prefix; + } + else + { + // Add template group + $insert_array = array( + 'prefix' => $db->escape_string($prefix), + 'title' => $db->escape_string($title), + 'isdefault' => 0 + ); + + $gid = $db->insert_query('templategroups', $insert_array); + + $plugins->run_hooks('admin_style_templates_add_template_group_commit'); + + log_admin_action($gid, $title); + flash_message($lang->success_template_group_saved, 'success'); + + if($sid) + { + admin_redirect("index.php?module=style-templates&sid={$sid}".$expand_str2); + } + + admin_redirect('index.php?module=style-templates'); + } + } + } + + if($mybb->input['sid']) + { + $page->add_breadcrumb_item($template_sets[$sid], "index.php?module=style-templates&sid={$sid}{$expand_str}"); + } + + $page->add_breadcrumb_item($lang->add_template_group); + $page->output_header($lang->add_template_group); + $page->output_nav_tabs($sub_tabs, 'add_template_group'); + + if($errors) + { + $template_group = array( + 'prefix' => $prefix, + 'title' => $title + ); + + $page->output_inline_error($errors); + } + + $form = new Form("index.php?module=style-templates&action=add_template_group{$expand_str}", "post", "add_template_group"); + echo $form->generate_hidden_field('sid', $sid); + + $form_container = new FormContainer($lang->add_template_group); + $form_container->output_row($lang->template_group_prefix, $lang->template_group_prefix_desc, $form->generate_text_box('prefix', $template_group['prefix'], array('id' => 'prefix')), 'prefix'); + $form_container->output_row($lang->template_group_title, $lang->template_group_title_desc, $form->generate_text_box('title', $template_group['title'], array('id' => 'title')), 'title'); + $form_container->end(); + + $buttons = array( + $form->generate_submit_button($lang->add_template_group) + ); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit_set") +{ + $query = $db->simple_select("templatesets", "*", "sid='{$sid}'"); + $set = $db->fetch_array($query); + if(!$set) + { + flash_message($lang->error_invalid_input, 'error'); + admin_redirect("index.php?module=style-templates"); + } + + $plugins->run_hooks("admin_style_templates_edit_set"); + + $sid = $set['sid']; + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_set_title; + } + + if(!$errors) + { + $query = $db->update_query("templatesets", array('title' => $db->escape_string($mybb->input['title'])), "sid='{$sid}'"); + + $plugins->run_hooks("admin_style_templates_edit_set_commit"); + + // Log admin action + log_admin_action($sid, $set['title']); + + flash_message($lang->success_template_set_saved, 'success'); + admin_redirect("index.php?module=style-templates&sid=".$sid.$expand_str2); + } + } + + if($sid) + { + $page->add_breadcrumb_item($template_sets[$sid], "index.php?module=style-templates&sid={$sid}{$expand_str}"); + } + + $page->add_breadcrumb_item($lang->edit_set); + + $page->output_header($lang->edit_set); + + $sub_tabs = array(); + $sub_tabs['edit_set'] = array( + 'title' => $lang->edit_set, + 'link' => "index.php?module=style-templates&action=edit_set&sid=".$sid, + 'description' => $lang->edit_set_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_set'); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $query = $db->simple_select("templatesets", "title", "sid='{$sid}'"); + $mybb->input['title'] = $db->fetch_field($query, "title"); + } + + $form = new Form("index.php?module=style-templates&action=edit_set{$expand_str}", "post", "edit_set"); + echo $form->generate_hidden_field("sid", $sid); + + $form_container = new FormContainer($lang->edit_set); + $form_container->output_row($lang->title, "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->end(); + + $buttons = array(); + $buttons[] = $form->generate_submit_button($lang->save); + + $form->output_submit_wrapper($buttons); + + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit_template") +{ + if(!$mybb->input['title'] || !$sid || !isset($template_sets[$sid])) + { + flash_message($lang->error_missing_input, 'error'); + admin_redirect("index.php?module=style-templates"); + } + + $plugins->run_hooks("admin_style_templates_edit_template"); + + if($mybb->request_method == "post") + { + if(empty($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + // Are we trying to do malicious things in our template? + if(check_template($mybb->input['template'])) + { + $errors[] = $lang->error_security_problem; + } + + if(!$errors) + { + $query = $db->simple_select("templates", "*", "tid='{$mybb->input['tid']}'"); + $template = $db->fetch_array($query); + + $template_array = array( + 'title' => $db->escape_string($mybb->input['title']), + 'sid' => $sid, + 'template' => $db->escape_string(rtrim($mybb->input['template'])), + 'version' => $mybb->version_code, + 'status' => '', + 'dateline' => TIME_NOW + ); + + // Make sure we have the correct tid associated with this template. If the user double submits then the tid could originally be the master template tid, but because the form is sumbitted again, the tid doesn't get updated to the new modified template one. This then causes the master template to be overwritten + $query = $db->simple_select("templates", "tid", "title='".$db->escape_string($template['title'])."' AND (sid = '-2' OR sid = '{$template['sid']}')", array('order_by' => 'sid', 'order_dir' => 'desc', 'limit' => 1)); + $template['tid'] = $db->fetch_field($query, "tid"); + + $plugins->run_hooks("admin_style_templates_edit_template_commit_start"); + + if($sid > 0) + { + // Check to see if it's never been edited before (i.e. master) or if this a new template (i.e. we've renamed it) or if it's a custom template + $query = $db->simple_select("templates", "sid", "title='".$db->escape_string($mybb->input['title'])."' AND (sid = '-2' OR sid = '{$sid}' OR sid='{$template['sid']}')", array('order_by' => 'sid', 'order_dir' => 'desc')); + $existing_sid = $db->fetch_field($query, "sid"); + $existing_rows = $db->num_rows($query); + + if(($existing_sid == -2 && $existing_rows == 1) || $existing_rows == 0) + { + $template['tid'] = $db->insert_query("templates", $template_array); + } + else + { + $db->update_query("templates", $template_array, "tid='{$template['tid']}' AND sid != '-2'"); + } + } + else + { + // Global template set + $db->update_query("templates", $template_array, "tid='{$template['tid']}' AND sid != '-2'"); + } + + $plugins->run_hooks("admin_style_templates_edit_template_commit"); + + $query = $db->simple_select("templatesets", "title", "sid='{$sid}'"); + $set = $db->fetch_array($query); + + $exploded = explode("_", $template_array['title'], 2); + $prefix = $exploded[0]; + + $query = $db->simple_select("templategroups", "gid", "prefix = '".$db->escape_string($prefix)."'"); + $group = $db->fetch_field($query, "gid"); + + if(!$group) + { + $group = "-1"; + } + + // Log admin action + log_admin_action($template['tid'], $mybb->input['title'], $mybb->input['sid'], $set['title']); + + flash_message($lang->success_template_saved, 'success'); + + if($mybb->input['continue']) + { + if($mybb->input['from'] == "diff_report") + { + admin_redirect("index.php?module=style-templates&action=edit_template&title=".urlencode($mybb->input['title'])."&sid=".$mybb->get_input('sid', 1).$expand_str2."&from=diff_report"); + } + else + { + admin_redirect("index.php?module=style-templates&action=edit_template&title=".urlencode($mybb->input['title'])."&sid=".$mybb->get_input('sid', 1).$expand_str2); + } + } + else + { + if($mybb->input['from'] == "diff_report") + { + admin_redirect("index.php?module=style-templates&action=find_updated"); + } + else + { + admin_redirect("index.php?module=style-templates&sid=".$mybb->get_input('sid', 1).$expand_str2."#group_{$group}"); + } + } + } + } + + if($errors) + { + $template = $mybb->input; + } + else + { + $query = $db->simple_select("templates", "*", "title='".$db->escape_string($mybb->input['title'])."' AND (sid='-2' OR sid='{$sid}')", array('order_by' => 'sid', 'order_dir' => 'DESC', 'limit' => 1)); + $template = $db->fetch_array($query); + } + $template['title'] = htmlspecialchars_uni($template['title']); + + if($admin_options['codepress'] != 0) + { + $page->extra_header .= ' + + + + + + + + + + + +'; + } + + $page->add_breadcrumb_item($template_sets[$sid], "index.php?module=style-templates&sid={$sid}{$expand_str}"); + + if(!isset($mybb->input['from'])) + { + $mybb->input['from'] = ''; + } + + if($mybb->input['from'] == "diff_report") + { + $page->add_breadcrumb_item($lang->find_updated, "index.php?module=style-templates&action=find_updated"); + } + + $page->add_breadcrumb_item($lang->edit_template_breadcrumb.$template['title'], "index.php?module=style-templates&sid={$sid}"); + + $page->output_header($lang->sprintf($lang->editing_template, $template['title'])); + + + $sub_tabs = array(); + + if($mybb->input['from'] == "diff_report") + { + $sub_tabs['find_updated'] = array( + 'title' => $lang->find_updated, + 'link' => "index.php?module=style-templates&action=find_updated" + ); + + $sub_tabs['diff_report'] = array( + 'title' => $lang->diff_report, + 'link' => "index.php?module=style-templates&action=diff_report&title=".$db->escape_string($template['title'])."&sid1=".(int)$template['sid']."&sid2=-2", + ); + } + + $sub_tabs['edit_template'] = array( + 'title' => $lang->edit_template, + 'link' => "index.php?module=style-templates&action=edit_template&title=".htmlspecialchars_uni($template['title']).$expand_str, + 'description' => $lang->edit_template_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_template'); + + if($errors) + { + $page->output_inline_error($errors); + } + + $form = new Form("index.php?module=style-templates&action=edit_template{$expand_str}", "post", "edit_template"); + echo $form->generate_hidden_field('tid', $template['tid'])."\n"; + + if($mybb->input['from'] == "diff_report") + { + echo $form->generate_hidden_field('from', "diff_report"); + } + + $form_container = new FormContainer($lang->edit_template_breadcrumb.$template['title']); + $form_container->output_row($lang->template_name, $lang->template_name_desc, $form->generate_text_box('title', $template['title'], array('id' => 'title')), 'title'); + + // Force users to save the default template to a specific set, rather than the "global" templates - where they can delete it + if($template['sid'] == "-2") + { + unset($template_sets[-1]); + } + + $form_container->output_row($lang->template_set, $lang->template_set_desc, $form->generate_select_box('sid', $template_sets, $sid)); + + $form_container->output_row("", "", $form->generate_text_area('template', $template['template'], array('id' => 'template', 'class' => '', 'style' => 'width: 100%; height: 500px;'))); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_continue, array('name' => 'continue')); + $buttons[] = $form->generate_submit_button($lang->save_close, array('name' => 'close')); + + $form->output_submit_wrapper($buttons); + + $form->end(); + + if($admin_options['codepress'] != 0) + { + echo ""; + } + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit_template_group") +{ + $query = $db->simple_select("templategroups", "*", "gid = '".(int)$mybb->input['gid']."'"); + + if(!$db->num_rows($query)) + { + flash_message($lang->error_missing_template_group, 'error'); + admin_redirect("index.php?module=style-templates&sid={$sid}{$expand_str}"); + } + + $template_group = $db->fetch_array($query); + if(isset($template_group['isdefault']) && $template_group['isdefault'] == 1) + { + flash_message($lang->error_default_template_group, 'error'); + admin_redirect("index.php?module=style-templates&sid={$sid}{$expand_str}"); + } + + $plugins->run_hooks("admin_style_templates_edit_template_group"); + + $errors = array(); + if($mybb->request_method == "post") + { + $prefix = trim($mybb->input['prefix']); + if(!$prefix) + { + $errors[] = $lang->error_missing_group_prefix; + } + + $title = trim($mybb->input['title']); + if(!$title) + { + $errors[] = $lang->error_missing_group_title; + } + + if(!$errors) + { + if($prefix != $template_group['prefix']) + { + $query = $db->simple_select("templategroups", "COUNT(gid) AS gid", "prefix = '".$db->escape_string($mybb->input['prefix'])."'"); + $prefix_count = $db->fetch_field($query, 'gid'); + + if($prefix_count >= 1) + { + $errors[] = $lang->error_duplicate_group_prefix; + } + } + + if(!$errors) + { + // Add template group + $update_array = array( + 'prefix' => $db->escape_string($prefix), + 'title' => $db->escape_string($title), + 'isdefault' => 0 + ); + + $plugins->run_hooks('admin_style_templates_edit_template_group_commit'); + + $db->update_query('templategroups', $update_array, "gid = '{$template_group['gid']}'"); + + log_admin_action($template_group['gid'], $title); + flash_message($lang->success_template_group_saved, 'success'); + admin_redirect("index.php?module=style-templates&sid={$sid}"); + } + } + } + + $lang->editing_template_group = $lang->sprintf($lang->editing_template_group, $template_group['title']); + + $page->add_breadcrumb_item($template_sets[$sid], "index.php?module=style-templates&sid={$sid}{$expand_str}"); + $page->add_breadcrumb_item($lang->editing_template_group, "index.php?module=style-templates&sid={$sid}"); + + $page->output_header($lang->editing_template_group); + + if($errors) + { + $template_group['prefix'] = $prefix; + $template_group['title'] = $title; + + $page->output_inline_error($errors); + } + + $form = new Form("index.php?module=style-templates&action=edit_template_group", "post"); + echo $form->generate_hidden_field('sid', $sid); + echo $form->generate_hidden_field('gid', $template_group['gid']); + + $form_container = new FormContainer($lang->edit_template_group); + $form_container->output_row($lang->template_group_prefix, $lang->template_group_prefix_desc, $form->generate_text_box('prefix', $template_group['prefix'], array('id' => 'prefix')), 'prefix'); + $form_container->output_row($lang->template_group_title, $lang->template_group_title_desc, $form->generate_text_box('title', $template_group['title'], array('id' => 'title')), 'title'); + $form_container->end(); + + $buttons = array( + $form->generate_submit_button($lang->save_template_group) + ); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "search_replace") +{ + $plugins->run_hooks("admin_style_templates_search_replace"); + + if($mybb->request_method == "post") + { + if($mybb->input['type'] == "templates") + { + // Search and replace in templates + + if(!$mybb->input['find']) + { + flash_message($lang->search_noneset, "error"); + admin_redirect("index.php?module=style-templates&action=search_replace"); + } + else + { + $page->add_breadcrumb_item($lang->search_replace); + + $page->output_header($lang->search_replace); + + $plugins->run_hooks("admin_style_templates_search_replace_find"); + + $page->output_nav_tabs($sub_tabs, 'search_replace'); + + $templates_list = array(); + $table = new Table; + + $template_sets = array(); + + // Get the names of all template sets + $template_sets[-2] = $lang->master_templates; + $template_sets[-1] = $lang->global_templates; + + $query = $db->simple_select("templatesets", "sid, title"); + while($set = $db->fetch_array($query)) + { + $template_sets[$set['sid']] = $set['title']; + } + + // Select all templates with that search term + $query = $db->query(" + SELECT t.tid, t.title, t.sid, t.template + FROM ".TABLE_PREFIX."templates t + LEFT JOIN ".TABLE_PREFIX."templatesets s ON (t.sid=s.sid) + LEFT JOIN ".TABLE_PREFIX."templates t2 ON (t.title=t2.title AND t2.sid='1') + WHERE t.template LIKE '%".$db->escape_string_like($mybb->input['find'])."%' AND NOT (t.sid = -2 AND (t2.tid) IS NOT NULL) + ORDER BY t.title ASC + "); + if($db->num_rows($query) == 0) + { + $table->construct_cell($lang->sprintf($lang->search_noresults, htmlspecialchars_uni($mybb->input['find'])), array("class" => "align_center")); + + $table->construct_row(); + + $table->output($lang->search_results); + } + else + { + $template_list = array(); + while($template = $db->fetch_array($query)) + { + $template_list[$template['sid']][$template['title']] = $template; + } + + $count = 0; + + foreach($template_list as $sid => $templates) + { + ++$count; + + $search_header = $lang->sprintf($lang->search_header, htmlspecialchars_uni($mybb->input['find']), $template_sets[$sid]); + $table->construct_header($search_header, array("colspan" => 2)); + + foreach($templates as $title => $template) + { + // Do replacement + $newtemplate = str_ireplace($mybb->input['find'], $mybb->input['replace'], $template['template']); + if($newtemplate != $template['template'] && check_template($newtemplate) === false) + { + // If the template is different, that means the search term has been found. + if(trim($mybb->input['replace']) != "") + { + if($template['sid'] == -2) + { + // The template is a master template. We have to make a new custom template. + $new_template = array( + "title" => $db->escape_string($title), + "template" => $db->escape_string($newtemplate), + "sid" => 1, + "version" => $mybb->version_code, + "status" => '', + "dateline" => TIME_NOW + ); + $new_tid = $db->insert_query("templates", $new_template); + $label = $lang->sprintf($lang->search_created_custom, $template['title']); + $url = "index.php?module=style-templates&action=edit_template&title=".urlencode($template['title'])."&sid=1"; + } + else + { + // The template is a custom template. Replace as normal. + // Update the template if there is a replacement term + $updatedtemplate = array( + "template" => $db->escape_string($newtemplate) + ); + $db->update_query("templates", $updatedtemplate, "tid='".$template['tid']."'"); + $label = $lang->sprintf($lang->search_updated, $template['title']); + $url = "index.php?module=style-templates&action=edit_template&title=".urlencode($template['title'])."&sid={$template['sid']}"; + } + } + else + { + // Just show that the term was found + if($template['sid'] == -2) + { + $label = $lang->sprintf($lang->search_found, $template['title']); + } + else + { + $label = $lang->sprintf($lang->search_found, $template['title']); + $url = "index.php?module=style-templates&action=edit_template&title=".urlencode($template['title'])."&sid={$template['sid']}"; + } + } + } + else + { + // Just show that the term was found + if($template['sid'] == -2) + { + $label = $lang->sprintf($lang->search_found, $template['title']); + } + else + { + $label = $lang->sprintf($lang->search_found, $template['title']); + $url = "index.php?module=style-templates&action=edit_template&title=".urlencode($template['title'])."&sid={$template['sid']}"; + } + } + + $table->construct_cell($label, array("width" => "85%")); + + if($sid == -2) + { + $popup = new PopupMenu("template_{$template['tid']}", $lang->options); + + foreach($template_sets as $set_sid => $title) + { + if($set_sid > 0) + { + $popup->add_item($lang->edit_in." ".htmlspecialchars_uni($title), "index.php?module=style-templates&action=edit_template&title=".urlencode($template['title'])."&sid={$set_sid}"); + } + } + + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + } + else + { + $table->construct_cell("{$lang->edit}", array("class" => "align_center")); + } + + $table->construct_row(); + } + + if($count == 1) + { + $table->output($lang->search_results); + } + else + { + $table->output(); + } + } + } + + if(trim($mybb->input['replace']) != "") + { + // Log admin action - only if replace + log_admin_action($mybb->input['find'], $mybb->input['replace']); + } + + $page->output_footer(); + exit; + } + } + else + { + if(!$mybb->input['title']) + { + flash_message($lang->search_noneset, "error"); + admin_redirect("index.php?module=style-templates&action=search_replace"); + } + else + { + // Search Template Titles + + $templatessets = array(); + + $templates_sets = array(); + // Get the names of all template sets + $template_sets[-2] = $lang->master_templates; + $template_sets[-1] = $lang->global_templates; + + $plugins->run_hooks("admin_style_templates_search_replace_title"); + + $query = $db->simple_select("templatesets", "sid, title"); + while($set = $db->fetch_array($query)) + { + $template_sets[$set['sid']] = $set['title']; + } + + $table = new Table; + + $query = $db->query(" + SELECT t.tid, t.title, t.sid, s.title as settitle, t2.tid as customtid + FROM ".TABLE_PREFIX."templates t + LEFT JOIN ".TABLE_PREFIX."templatesets s ON (t.sid=s.sid) + LEFT JOIN ".TABLE_PREFIX."templates t2 ON (t.title=t2.title AND t2.sid='1') + WHERE t.title LIKE '%".$db->escape_string_like($mybb->input['title'])."%' + ORDER BY t.title ASC + "); + while($template = $db->fetch_array($query)) + { + if($template['sid'] == -2) + { + if(!$template['customtid']) + { + $template['original'] = true; + } + else + { + $template['modified'] = true; + } + } + else + { + $template['original'] = false; + $template['modified'] = false; + } + $templatessets[$template['sid']][$template['title']] = $template; + } + + $page->add_breadcrumb_item($lang->search_replace); + + $page->output_header($lang->search_replace); + + $page->output_nav_tabs($sub_tabs, 'search_replace'); + + if(empty($templatessets)) + { + $table->construct_cell($lang->sprintf($lang->search_noresults_title, htmlspecialchars_uni($mybb->input['title'])), array("class" => "align_center")); + + $table->construct_row(); + + $table->output($lang->search_results); + } + + $count = 0; + + foreach($templatessets as $sid => $templates) + { + ++$count; + + $table->construct_header($template_sets[$sid], array("colspan" => 2)); + + foreach($templates as $template) + { + $template['pretty_title'] = $template['title']; + + $popup = new PopupMenu("template_{$template['tid']}", $lang->options); + + if($sid == -2) + { + foreach($template_sets as $set_sid => $title) + { + if($set_sid < 0) continue; + + $popup->add_item($lang->edit_in." ".htmlspecialchars_uni($title), "index.php?module=style-templates&action=edit_template&title=".urlencode($template['title'])."&sid={$set_sid}"); + } + } + else + { + $popup->add_item($lang->full_edit, "index.php?module=style-templates&action=edit_template&title=".urlencode($template['title'])."&sid={$sid}"); + } + + if(isset($template['modified']) && $template['modified'] == true) + { + if($sid > 0) + { + $popup->add_item($lang->diff_report, "index.php?module=style-templates&action=diff_report&title=".urlencode($template['title'])."&sid2={$sid}"); + + $popup->add_item($lang->revert_to_orig, "index.php?module=style-templates&action=revert&title=".urlencode($template['title'])."&sid={$sid}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_template_revertion}')"); + } + + $template['pretty_title'] = "{$template['title']}"; + } + // This template does not exist in the master list + else if(!isset($template['original']) || $template['original'] == false) + { + $popup->add_item($lang->delete_template, "index.php?module=style-templates&action=delete_template&title=".urlencode($template['title'])."&sid={$sid}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_template_deletion}')"); + + $template['pretty_title'] = "{$template['title']}"; + } + + $table->construct_cell("{$template['pretty_title']}", array("width" => "85%")); + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + + $table->construct_row(); + } + + if($count == 1) + { + $table->output($lang->sprintf($lang->search_names_header, htmlspecialchars_uni($mybb->input['title']))); + } + else if($count > 0) + { + $table->output(); + } + } + + $page->output_footer(); + exit; + } + } + } + + if($admin_options['codepress'] != 0) + { + $page->extra_header .= ' + + + + + + + + + + + +'; + } + + $page->add_breadcrumb_item($lang->search_replace); + + $page->output_header($lang->search_replace); + + $page->output_nav_tabs($sub_tabs, 'search_replace'); + + $form = new Form("index.php?module=style-templates&action=search_replace", "post", "do_template"); + echo $form->generate_hidden_field('type', "templates"); + + $form_container = new FormContainer($lang->search_replace); + $form_container->output_row($lang->search_for, "", $form->generate_text_area('find', $mybb->input['find'], array('id' => 'find', 'class' => '', 'style' => 'width: 100%; height: 200px;'))); + + $form_container->output_row($lang->replace_with, "", $form->generate_text_area('replace', $mybb->input['replace'], array('id' => 'replace', 'class' => '', 'style' => 'width: 100%; height: 200px;'))); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->find_and_replace); + + $form->output_submit_wrapper($buttons); + + $form->end(); + + echo "
"; + + + $form = new Form("index.php?module=style-templates&action=search_replace", "post", "do_title"); + echo $form->generate_hidden_field('type', "titles"); + + $form_container = new FormContainer($lang->search_template_names); + + $form_container->output_row($lang->search_for, "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + + $form_container->end(); + + $buttons = array(); + $buttons[] = $form->generate_submit_button($lang->find_templates); + $buttons[] = $form->generate_reset_button($lang->reset); + + $form->output_submit_wrapper($buttons); + + $form->end(); + + if($admin_options['codepress'] != 0) + { + echo ""; + } + + $page->output_footer(); +} + +if($mybb->input['action'] == "find_updated") +{ + // Finds templates that are old and have been updated by MyBB + $compare_version = $mybb->version_code; + $query = $db->query(" + SELECT COUNT(*) AS updated_count + FROM ".TABLE_PREFIX."templates t + LEFT JOIN ".TABLE_PREFIX."templates m ON (m.title=t.title AND m.sid=-2 AND m.version > t.version) + WHERE t.sid > 0 AND m.template != t.template + "); + $count = $db->fetch_array($query); + + if($count['updated_count'] < 1) + { + flash_message($lang->no_updated_templates, 'success'); + admin_redirect("index.php?module=style-templates"); + } + + $plugins->run_hooks("admin_style_templates_find_updated"); + + $page->add_breadcrumb_item($lang->find_updated, "index.php?module=style-templates&action=find_updated"); + + $page->output_header($lang->find_updated); + + $page->output_nav_tabs($sub_tabs, 'find_updated'); + + $query = $db->simple_select("templatesets", "*", "", array('order_by' => 'title')); + while($templateset = $db->fetch_array($query)) + { + $templatesets[$templateset['sid']] = $templateset; + } + + echo << +{$lang->legend} +
    +
  • {$lang->updated_template_welcome1}
  • +
  • {$lang->updated_template_welcome2}
  • +
  • {$lang->updated_template_welcome3}
  • +
+ +LEGEND; + + $count = 0; + $done_set = array(); + $done_output = array(); + $templates = array(); + $table = new Table; + + $query = $db->query(" + SELECT t.tid, t.title, t.sid, t.version + FROM ".TABLE_PREFIX."templates t + LEFT JOIN ".TABLE_PREFIX."templates m ON (m.title=t.title AND m.sid=-2 AND m.version > t.version) + WHERE t.sid > 0 AND m.template != t.template + ORDER BY t.sid ASC, title ASC + "); + while($template = $db->fetch_array($query)) + { + $templates[$template['sid']][] = $template; + } + + foreach($templates as $sid => $templates) + { + if(!$done_set[$sid]) + { + $table->construct_header($templatesets[$sid]['title'], array("colspan" => 2)); + + $done_set[$sid] = 1; + ++$count; + } + + foreach($templates as $template) + { + $popup = new PopupMenu("template_{$template['tid']}", $lang->options); + $popup->add_item($lang->full_edit, "index.php?module=style-templates&action=edit_template&title=".urlencode($template['title'])."&sid={$sid}&from=diff_report"); + $popup->add_item($lang->diff_report, "index.php?module=style-templates&action=diff_report&title=".urlencode($template['title'])."&sid1=".$template['sid']."&sid2=-2&from=diff_report"); + $popup->add_item($lang->revert_to_orig, "index.php?module=style-templates&action=revert&title=".urlencode($template['title'])."&sid={$sid}&from=diff_report&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_template_revertion}')"); + + $table->construct_cell("{$template['title']}", array('width' => '80%')); + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + + $table->construct_row(); + } + + if($done_set[$sid] && !$done_output[$sid]) + { + $done_output[$sid] = 1; + if($count == 1) + { + $table->output($lang->find_updated); + } + else + { + $table->output(); + } + } + } + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete_template_group") +{ + $gid = (int)$mybb->input['gid']; + $query = $db->simple_select("templategroups", "*", "gid='{$gid}'"); + + if(!$db->num_rows($query)) + { + flash_message($lang->error_missing_template_group, 'error'); + admin_redirect("index.php?module=style-templates&sid={$sid}"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=style-templates&sid={$sid}"); + } + + $plugins->run_hooks("admin_style_template_group_delete"); + + $template_group = $db->fetch_array($query); + + if($mybb->request_method == "post") + { + // Delete the group + $db->delete_query("templategroups", "gid = '{$template_group['gid']}'"); + + $plugins->run_hooks("admin_style_template_group_delete_commit"); + + // Log admin action + log_admin_action($template_group['gid'], $template_group['title']); + + flash_message($lang->success_template_group_deleted, 'success'); + admin_redirect("index.php?module=style-templates&sid={$sid}"); + } + else + { + $page->output_confirm_action("index.php?module=style-templates&action=delete_template_group&gid={$template_group['gid']}&sid={$sid}", $lang->confirm_template_group_delete); + } +} + +if($mybb->input['action'] == "delete_set") +{ + $query = $db->simple_select("templatesets", "*", "sid='{$sid}' AND sid > 0"); + $set = $db->fetch_array($query); + + // Does the template not exist? + if(!$set['sid']) + { + flash_message($lang->error_invalid_template_set, 'error'); + admin_redirect("index.php?module=style-templates"); + } + + $plugins->run_hooks("admin_style_templates_delete_set"); + + // Is there a theme attached to this set? + $query = $db->simple_select("themes", "properties"); + while($theme = $db->fetch_array($query)) + { + $properties = my_unserialize($theme['properties']); + if($properties['templateset'] == $sid) + { + flash_message($lang->error_themes_attached_template_set, 'error'); + admin_redirect("index.php?module=style-templates"); + break; + } + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=style-templates"); + } + + if($mybb->request_method == "post") + { + // Delete the templateset + $db->delete_query("templatesets", "sid='{$set['sid']}'"); + // Delete all custom templates in this templateset + $db->delete_query("templates", "sid='{$set['sid']}'"); + + $plugins->run_hooks("admin_style_templates_delete_set_commit"); + + // Log admin action + log_admin_action($set['sid'], $set['title']); + + flash_message($lang->success_template_set_deleted, 'success'); + admin_redirect("index.php?module=style-templates"); + } + else + { + $page->output_confirm_action("index.php?module=style-templates&action=delete_set&sid={$set['sid']}", $lang->confirm_template_set_deletion); + } + +} + +if($mybb->input['action'] == "delete_template") +{ + $query = $db->query(" + SELECT t.*, s.title as set_title + FROM ".TABLE_PREFIX."templates t + LEFT JOIN ".TABLE_PREFIX."templatesets s ON(t.sid=s.sid) + WHERE t.title='".$db->escape_string($mybb->input['title'])."' AND t.sid > '-2' AND t.sid = '{$sid}' + "); + $template = $db->fetch_array($query); + + // Does the template not exist? + if(!$template) + { + flash_message($lang->error_invalid_template, 'error'); + admin_redirect("index.php?module=style-templates"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=style-templates&sid={$template['sid']}{$expand_str2}"); + } + + $plugins->run_hooks("admin_style_templates_delete_template"); + + if($mybb->request_method == "post") + { + // Delete the template + $db->delete_query("templates", "tid='{$template['tid']}'"); + + $plugins->run_hooks("admin_style_templates_delete_template_commit"); + + // Log admin action + log_admin_action($template['tid'], $template['title'], $template['sid'], $template['set_title']); + + flash_message($lang->success_template_deleted, 'success'); + admin_redirect("index.php?module=style-templates&sid={$template['sid']}{$expand_str2}"); + } + else + { + $page->output_confirm_action("index.php?module=style-templates&action=delete_template&sid={$template['sid']}{$expand_str}", $lang->confirm_template_deletion); + } +} + +if($mybb->input['action'] == "diff_report") +{ + // Compares a template of sid1 with that of sid2, if no sid1, it is assumed -2 + if(!$mybb->input['sid1'] || !isset($template_sets[$mybb->input['sid1']])) + { + $mybb->input['sid1'] = -2; + } + + if($mybb->input['sid2'] == -2) + { + $sub_tabs['find_updated'] = array( + 'title' => $lang->find_updated, + 'link' => "index.php?module=style-templates&action=find_updated" + ); + } + + if($mybb->input['sid2'] != -2 && !isset($template_sets[$mybb->input['sid2']])) + { + flash_message($lang->error_invalid_input, 'error'); + admin_redirect("index.php?module=style-templates"); + } + + if(!$mybb->input['from']) + { + $mybb->input['from'] = 0; + } + + $sub_tabs['diff_report'] = array( + 'title' => $lang->diff_report, + 'link' => "index.php?module=style-templates&action=diff_report&title=".$db->escape_string($mybb->input['title'])."&from=".$mybb->input['from']."sid1=".(int)$mybb->input['sid1']."&sid2=".(int)$mybb->input['sid2'], + 'description' => $lang->diff_report_desc + ); + + $plugins->run_hooks("admin_style_templates_diff_report"); + + $query = $db->simple_select("templates", "*", "title='".$db->escape_string($mybb->input['title'])."' AND sid='".(int)$mybb->input['sid1']."'"); + $template1 = $db->fetch_array($query); + + $query = $db->simple_select("templates", "*", "title='".$db->escape_string($mybb->input['title'])."' AND sid='".(int)$mybb->input['sid2']."'"); + $template2 = $db->fetch_array($query); + + if($mybb->input['sid2'] == -2) + { + $sub_tabs['full_edit'] = array( + 'title' => $lang->full_edit, + 'link' => "index.php?module=style-templates&action=edit_template&title=".urlencode($template1['title'])."&sid=".(int)$mybb->input['sid1']."&from=diff_report", + ); + } + + if($template1['template'] == $template2['template']) + { + flash_message($lang->templates_the_same, 'error'); + admin_redirect("index.php?module=style-templates&sid=".(int)$mybb->input['sid2'].$expand_str); + } + + $template1['template'] = explode("\n", $template1['template']); + $template2['template'] = explode("\n", $template2['template']); + + $plugins->run_hooks("admin_style_templates_diff_report_run"); + + require_once MYBB_ROOT."inc/3rdparty/diff/Diff.php"; + require_once MYBB_ROOT."inc/3rdparty/diff/Diff/Renderer.php"; + require_once MYBB_ROOT."inc/3rdparty/diff/Diff/Renderer/Inline.php"; + + $diff = new Horde_Text_Diff('auto', array($template1['template'], $template2['template'])); + $renderer = new Horde_Text_Diff_Renderer_Inline(); + + if($sid) + { + $page->add_breadcrumb_item($template_sets[$sid], "index.php?module=style-templates&sid={$sid}{$expand_str}"); + } + + if($mybb->input['sid2'] == -2) + { + $page->add_breadcrumb_item($lang->find_updated, "index.php?module=style-templates&action=find_updated"); + } + + $page->add_breadcrumb_item($lang->diff_report.": ".$template1['title'], "index.php?module=style-templates&action=diff_report&title=".$db->escape_string($mybb->input['title'])."&from=".$mybb->input['from']."&sid1=".(int)$mybb->input['sid1']."&sid2=".(int)$mybb->input['sid2']); + + $page->output_header($lang->template_sets); + + $page->output_nav_tabs($sub_tabs, 'diff_report'); + + $table = new Table; + + if($mybb->input['from']) + { + $table->construct_header("".$lang->master_updated_ins."
".$lang->master_updated_del.""); + } + else + { + $table->construct_header("".$lang->master_updated_del."
".$lang->master_updated_ins.""); + } + + $table->construct_cell("
".$renderer->render($diff)."
"); + $table->construct_row(); + + $table->output($lang->template_diff_analysis.": ".$template1['title']); + + $page->output_footer(); +} + +if($mybb->input['action'] == "revert") +{ + $query = $db->query(" + SELECT t.*, s.title as set_title + FROM ".TABLE_PREFIX."templates t + LEFT JOIN ".TABLE_PREFIX."templatesets s ON(s.sid=t.sid) + WHERE t.title='".$db->escape_string($mybb->input['title'])."' AND t.sid > 0 AND t.sid = '".$mybb->get_input('sid', 1)."' + "); + $template = $db->fetch_array($query); + + // Does the template not exist? + if(!$template) + { + flash_message($lang->error_invalid_template, 'error'); + admin_redirect("index.php?module=style-templates"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=style-templates&sid={$template['sid']}{$expand_str2}"); + } + + $plugins->run_hooks("admin_style_templates_revert"); + + if($mybb->request_method == "post") + { + // Revert the template + $db->delete_query("templates", "tid='{$template['tid']}'"); + + $plugins->run_hooks("admin_style_templates_revert_commit"); + + // Log admin action + log_admin_action($template['tid'], $template['title'], $template['sid'], $template['set_title']); + + flash_message($lang->success_template_reverted, 'success'); + + if($mybb->input['from'] == "diff_report") + { + admin_redirect("index.php?module=style-templates&action=find_updated"); + } + else + { + admin_redirect("index.php?module=style-templates&sid={$template['sid']}{$expand_str2}"); + } + } + else + { + $page->output_confirm_action("index.php?module=style-templates&sid={$template['sid']}{$expand_str}", $lang->confirm_template_revertion); + } +} + +if($mybb->input['sid'] && !$mybb->input['action']) +{ + if(!isset($template_sets[$mybb->input['sid']])) + { + flash_message($lang->error_invalid_input, 'error'); + admin_redirect("index.php?module=style-templates"); + } + + $plugins->run_hooks("admin_style_templates_set"); + + $table = new Table; + + $page->add_breadcrumb_item($template_sets[$sid], "index.php?module=style-templates&sid={$sid}"); + + $page->output_header($lang->template_sets); + + $page->output_nav_tabs($sub_tabs, 'manage_templates'); + + $table->construct_header($lang->template_set); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 150)); + + // Global Templates + if($sid == -1) + { + $query = $db->simple_select("templates", "tid,title", "sid='-1'", array('order_by' => 'title', 'order_dir' => 'ASC')); + while($template = $db->fetch_array($query)) + { + $popup = new PopupMenu("template_{$template['tid']}", $lang->options); + $popup->add_item($lang->full_edit, "index.php?module=style-templates&action=edit_template&title=".urlencode($template['title'])."&sid=-1"); + $popup->add_item($lang->delete_template, "index.php?module=style-templates&action=delete_template&title=".urlencode($template['title'])."&sid=-1&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_template_deletion}')"); + + $table->construct_cell("{$template['title']}"); + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_global_templates, array('colspan' => 2)); + $table->construct_row(); + } + + $table->output($template_sets[$sid]); + + $page->output_footer(); + } + + if(!isset($mybb->input['expand'])) + { + $mybb->input['expand'] = ''; + } + if($mybb->input['expand'] == 'all') + { + // If we're expanding everything, stick in the ungrouped templates in the list as well + $expand_array = array(-1); + } + // Fetch Groups + $query = $db->simple_select("templategroups", "*"); + + $template_groups = array(); + while($templategroup = $db->fetch_array($query)) + { + $templategroup['title'] = $lang->parse($templategroup['title'])." ".$lang->templates; + if($mybb->input['expand'] == 'all') + { + $expand_array[] = $templategroup['gid']; + } + if(in_array($templategroup['gid'], $expand_array)) + { + $templategroup['expanded'] = 1; + } + $template_groups[$templategroup['prefix']] = $templategroup; + } + + function sort_template_groups($a, $b) + { + return strcasecmp($a['title'], $b['title']); + } + uasort($template_groups, "sort_template_groups"); + + // Add the ungrouped templates group at the bottom + $template_groups['-1'] = array( + "prefix" => "", + "title" => $lang->ungrouped_templates, + "gid" => -1 + ); + + // Load the list of templates + $query = $db->simple_select("templates", "*", "sid='".$mybb->get_input('sid', 1)."' OR sid='-2'", array('order_by' => 'sid DESC, title', 'order_dir' => 'ASC')); + while($template = $db->fetch_array($query)) + { + $exploded = explode("_", $template['title'], 2); + + if(isset($template_groups[$exploded[0]])) + { + $group = $exploded[0]; + } + else + { + $group = -1; + } + + $template['gid'] = -1; + if(isset($template_groups[$exploded[0]]['gid'])) + { + $template['gid'] = $template_groups[$exploded[0]]['gid']; + } + + // If this template is not a master template, we simple add it to the list + if($template['sid'] != -2) + { + $template['original'] = false; + $template['modified'] = false; + $template_groups[$group]['templates'][$template['title']] = $template; + } + else if(!in_array($template['gid'], $expand_array) && !isset($expand_array[-1])) + { + $template['original'] = true; + $template['modified'] = false; + $template_groups[$group]['templates'][$template['title']] = $template; + + // Save some memory! + unset($template_groups[$group]['templates'][$template['title']]['template']); + } + // Otherwise, if we are down to master templates we need to do a few extra things + else + { + // Master template that hasn't been customised in the set we have expanded + if(!isset($template_groups[$group]['templates'][$template['title']]) || $template_groups[$group]['templates'][$template['title']]['template'] == $template['template']) + { + $template['original'] = true; + $template_groups[$group]['templates'][$template['title']] = $template; + } + // Template has been modified in the set we have expanded (it doesn't match the master) + else if($template_groups[$group]['templates'][$template['title']]['template'] != $template['template'] && $template_groups[$group]['templates'][$template['title']]['sid'] != -2) + { + $template_groups[$group]['templates'][$template['title']]['modified'] = true; + } + + // Save some memory! + unset($template_groups[$group]['templates'][$template['title']]['template']); + } + } + + foreach($template_groups as $prefix => $group) + { + $tmp_expand = ""; + if(in_array($group['gid'], $expand_array)) + { + $expand = $lang->collapse; + $expanded = true; + + $tmp_expand = $expand_array; + $unsetgid = array_search($group['gid'], $tmp_expand); + unset($tmp_expand[$unsetgid]); + $group['expand_str'] = implode("|", $tmp_expand); + } + else + { + $expand = $lang->expand; + $expanded = false; + + $group['expand_str'] = implode("|", $expand_array); + if($group['expand_str']) + { + $group['expand_str'] .= "|"; + } + $group['expand_str'] .= $group['gid']; + } + + if($group['expand_str']) + { + $group['expand_str'] = "&expand={$group['expand_str']}"; + } + + $set_popup = ''; + if(isset($group['isdefault']) && !$group['isdefault']) + { + $popup = new PopupMenu("template_set_{$group['gid']}", $lang->options); + $popup->add_item($lang->edit_template_group, "index.php?module=style-templates&sid={$sid}&action=edit_template_group&gid={$group['gid']}{$group['expand_str']}"); + $popup->add_item($lang->delete_template_group, "index.php?module=style-templates&sid={$sid}&action=delete_template_group&gid={$group['gid']}&my_post_key={$mybb->post_code}{$group['expand_str']}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_template_group_delete}')"); + + $set_popup = "
{$popup->fetch()}
"; + } + + if($expanded == true) + { + // Show templates in this group + $table->construct_cell("{$set_popup}{$group['title']}"); + $table->construct_cell("{$expand}", array("class" => "align_center")); + $table->construct_row(array("class" => "alt_row", "id" => "group_".$group['gid'], "name" => "group_".$group['gid'])); + + if(isset($group['templates']) && count($group['templates']) > 0) + { + $templates = $group['templates']; + ksort($templates); + + foreach($templates as $template) + { + $template['pretty_title'] = $template['title']; + + $popup = new PopupMenu("template_{$template['tid']}", $lang->options); + $popup->add_item($lang->full_edit, "index.php?module=style-templates&action=edit_template&title=".urlencode($template['title'])."&sid={$sid}{$expand_str}"); + + if(isset($template['modified']) && $template['modified'] == true) + { + if($sid > 0) + { + $popup->add_item($lang->diff_report, "index.php?module=style-templates&action=diff_report&title=".urlencode($template['title'])."&sid2={$sid}"); + + $popup->add_item($lang->revert_to_orig, "index.php?module=style-templates&action=revert&title=".urlencode($template['title'])."&sid={$sid}&my_post_key={$mybb->post_code}{$expand_str}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_template_revertion}')"); + } + + $template['pretty_title'] = "{$template['title']}"; + } + // This template does not exist in the master list + else if(isset($template['original']) && $template['original'] == false) + { + $popup->add_item($lang->delete_template, "index.php?module=style-templates&action=delete_template&title=".urlencode($template['title'])."&sid={$sid}&my_post_key={$mybb->post_code}{$expand_str}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_template_deletion}')"); + + $template['pretty_title'] = "{$template['title']}"; + } + + $table->construct_cell("{$template['pretty_title']}"); + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + + $table->construct_row(); + } + } + else + { + // No templates in this group + $table->construct_cell($lang->empty_template_set, array('colspan' => 2)); + $table->construct_row(); + } + } + else + { + // Collapse template set + $table->construct_cell("{$set_popup}{$group['title']}"); + $table->construct_cell("{$expand}", array("class" => "align_center")); + $table->construct_row(array("class" => "alt_row", "id" => "group_".$group['gid'], "name" => "group_".$group['gid'])); + } + } + + $table->output($template_sets[$sid]); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_style_templates_start"); + + $page->output_header($lang->template_sets); + + $page->output_nav_tabs($sub_tabs, 'templates'); + + $themes = array(); + $query = $db->simple_select("themes", "name,tid,properties", "tid != '1'"); + while($theme = $db->fetch_array($query)) + { + $tbits = my_unserialize($theme['properties']); + $themes[$tbits['templateset']][$theme['tid']] = htmlspecialchars_uni($theme['name']); + } + + $template_sets = array(); + $template_sets[-1]['title'] = $lang->global_templates; + $template_sets[-1]['sid'] = -1; + + $query = $db->simple_select("templatesets", "*", "", array('order_by' => 'title', 'order_dir' => 'ASC')); + while($template_set = $db->fetch_array($query)) + { + $template_sets[$template_set['sid']] = $template_set; + } + + $table = new Table; + $table->construct_header($lang->template_set); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 150)); + + foreach($template_sets as $set) + { + if($set['sid'] == -1) + { + $table->construct_cell("{$lang->global_templates}
{$lang->used_by_all_themes}"); + $table->construct_cell("{$lang->expand_templates}", array("class" => "align_center")); + $table->construct_row(); + continue; + } + + if($themes[$set['sid']]) + { + $used_by_note = $lang->used_by; + $comma = ""; + foreach($themes[$set['sid']] as $theme_name) + { + $used_by_note .= $comma.$theme_name; + $comma = $lang->comma; + } + } + else + { + $used_by_note = $lang->not_used_by_any_themes; + } + + if($set['sid'] == 1) + { + $actions = "{$lang->expand_templates}"; + } + else + { + $popup = new PopupMenu("templateset_{$set['sid']}", $lang->options); + $popup->add_item($lang->expand_templates, "index.php?module=style-templates&sid={$set['sid']}"); + + if($set['sid'] != 1) + { + $popup->add_item($lang->edit_template_set, "index.php?module=style-templates&action=edit_set&sid={$set['sid']}"); + + if(!$themes[$set['sid']]) + { + $popup->add_item($lang->delete_template_set, "index.php?module=style-templates&action=delete_set&sid={$set['sid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_template_set_deletion}')"); + } + } + + $actions = $popup->fetch(); + } + + $table->construct_cell("{$set['title']}
{$used_by_note}"); + $table->construct_cell($actions, array("class" => "align_center")); + $table->construct_row(); + } + + $table->output($lang->template_sets); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/style/themes.php b/Upload/admin/modules/style/themes.php new file mode 100644 index 0000000..624831b --- /dev/null +++ b/Upload/admin/modules/style/themes.php @@ -0,0 +1,2980 @@ +
Please make sure IN_MYBB is defined."); +} + +require_once MYBB_ADMIN_DIR."inc/functions_themes.php"; + +$page->extra_header .= " +"; + +if($mybb->input['action'] == "xmlhttp_stylesheet" && $mybb->request_method == "post") +{ + // Fetch the theme we want to edit this stylesheet in + $query = $db->simple_select("themes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $theme = $db->fetch_array($query); + + if(!$theme['tid'] || $theme['tid'] == 1) + { + flash_message($lang->error_invalid_theme, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $parent_list = make_parent_theme_list($theme['tid']); + $parent_list = implode(',', $parent_list); + if(!$parent_list) + { + $parent_list = 1; + } + + $query = $db->simple_select("themestylesheets", "*", "name='".$db->escape_string($mybb->input['file'])."' AND tid IN ({$parent_list})", array('order_by' => 'tid', 'order_dir' => 'desc', 'limit' => 1)); + $stylesheet = $db->fetch_array($query); + + // Does the theme not exist? + if(!$stylesheet['sid']) + { + flash_message($lang->error_invalid_stylesheet, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $css_array = css_to_array($stylesheet['stylesheet']); + $selector_list = get_selectors_as_options($css_array, $mybb->input['selector']); + $editable_selector = $css_array[$mybb->input['selector']]; + $properties = parse_css_properties($editable_selector['values']); + + $form = new Form("index.php?module=style-themes&action=stylesheet_properties", "post", "selector_form", 0, "", true); + echo $form->generate_hidden_field("tid", $mybb->input['tid'], array('id' => "tid"))."\n"; + echo $form->generate_hidden_field("file", htmlspecialchars_uni($mybb->input['file']), array('id' => "file"))."\n"; + echo $form->generate_hidden_field("selector", htmlspecialchars_uni($mybb->input['selector']), array('id' => 'hidden_selector'))."\n"; + + $table = new Table; + if($lang->settings['rtl'] === true) + { + $div_align = "left"; + } + else + { + $div_align = "right"; + } + + $table->construct_cell("
".$form->generate_text_box('css_bits[background]', $properties['background'], array('id' => 'css_bits[background]', 'style' => 'width: 260px;'))."
{$lang->background}
", array('style' => 'width: 20%;')); + $table->construct_cell("{$lang->extra_css_atribs}
".$form->generate_text_area('css_bits[extra]', $properties['extra'], array('id' => 'css_bits[extra]', 'style' => 'width: 98%;', 'rows' => '19'))."
", array('rowspan' => 8)); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[color]', $properties['color'], array('id' => 'css_bits[color]', 'style' => 'width: 260px;'))."
{$lang->color}
", array('style' => 'width: 40%;')); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[width]', $properties['width'], array('id' => 'css_bits[width]', 'style' => 'width: 260px;'))."
{$lang->width}
", array('style' => 'width: 40%;')); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[font_family]', $properties['font-family'], array('id' => 'css_bits[font_family]', 'style' => 'width: 260px;'))."
{$lang->font_family}
", array('style' => 'width: 40%;')); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[font_size]', $properties['font-size'], array('id' => 'css_bits[font_size]', 'style' => 'width: 260px;'))."
{$lang->font_size}
", array('style' => 'width: 40%;')); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[font_style]', $properties['font-style'], array('id' => 'css_bits[font_style]', 'style' => 'width: 260px;'))."
{$lang->font_style}
", array('style' => 'width: 40%;')); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[font_weight]', $properties['font-weight'], array('id' => 'css_bits[font_weight]', 'style' => 'width: 260px;'))."
{$lang->font_weight}
", array('style' => 'width: 40%;')); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[text_decoration]', $properties['text-decoration'], array('id' => 'css_bits[text_decoration]', 'style' => 'width: 260px;'))."
{$lang->text_decoration}
", array('style' => 'width: 40%;')); + $table->construct_row(); + + $table->output(htmlspecialchars_uni($editable_selector['class_name']).""); + exit; +} + +$page->add_breadcrumb_item($lang->themes, "index.php?module=style-themes"); + +if($mybb->input['action'] == "add" || $mybb->input['action'] == "import" || $mybb->input['action'] == "browse" || !$mybb->input['action']) +{ + $sub_tabs['themes'] = array( + 'title' => $lang->themes, + 'link' => "index.php?module=style-themes", + 'description' => $lang->themes_desc + ); + + $sub_tabs['create_theme'] = array( + 'title' => $lang->create_new_theme, + 'link' => "index.php?module=style-themes&action=add", + 'description' => $lang->create_new_theme_desc + ); + + $sub_tabs['import_theme'] = array( + 'title' => $lang->import_a_theme, + 'link' => "index.php?module=style-themes&action=import", + 'description' => $lang->import_a_theme_desc + ); + + $sub_tabs['browse_themes'] = array( + 'title' => $lang->browse_themes, + 'link' => "index.php?module=style-themes&action=browse", + 'description' => $lang->browse_themes_desc + ); +} + +$plugins->run_hooks("admin_style_themes_begin"); + +if($mybb->input['action'] == "browse") +{ + $plugins->run_hooks("admin_style_themes_browse"); + + $page->add_breadcrumb_item($lang->browse_themes); + + $page->output_header($lang->browse_themes); + + $page->output_nav_tabs($sub_tabs, 'browse_themes'); + + // Process search requests + require_once MYBB_ROOT."inc/class_xml.php"; + + $keywords = ""; + if($mybb->input['keywords']) + { + $keywords = "&keywords=".urlencode($mybb->input['keywords']); + } + + if($mybb->input['page']) + { + $url_page = "&page=".$mybb->get_input('page', 1); + } + else + { + $mybb->input['page'] = 1; + $url_page = ""; + } + + // Gets the major version code. i.e. 1410 -> 1400 or 121 -> 1200 + $major_version_code = round($mybb->version_code/100, 0)*100; + // Convert to mods site version codes + $search_version = ($major_version_code/100).'x'; + + $contents = fetch_remote_file("http://community.mybb.com/xmlbrowse.php?type=themes&version={$search_version}{$keywords}{$url_page}", $post_data); + + if(!$contents) + { + $page->output_inline_error($lang->error_communication_problem); + $page->output_footer(); + exit; + } + + $table = new Table; + $table->construct_header($lang->themes, array('colspan' => 2)); + $table->construct_header($lang->controls, array("class" => "align_center", 'width' => 125)); + + $parser = new XMLParser($contents); + $tree = $parser->get_tree(); + + if(!is_array($tree) || !isset($tree['results'])) + { + $page->output_inline_error($lang->error_communication_problem); + $page->output_footer(); + exit; + } + + if(!empty($tree['results']['result'])) + { + if(array_key_exists("tag", $tree['results']['result'])) + { + $only_theme = $tree['results']['result']; + unset($tree['results']['result']); + $tree['results']['result'][0] = $only_theme; + } + + require_once MYBB_ROOT . '/inc/class_parser.php'; + $post_parser = new postParser(); + + foreach($tree['results']['result'] as $result) + { + $result['thumbnail']['value'] = htmlspecialchars_uni($result['thumbnail']['value']); + $result['name']['value'] = htmlspecialchars_uni($result['name']['value']); + $result['description']['value'] = htmlspecialchars_uni($result['description']['value']); + $result['author']['value'] = $post_parser->parse_message($result['author']['value'], array( + 'allow_html' => true + ) + ); + $result['download_url']['value'] = htmlspecialchars_uni(html_entity_decode($result['download_url']['value'])); + + $table->construct_cell("\"{$lang-theme_thumbnail}\" title=\"{$lang->theme_thumbnail}\"/>", array("class" => "align_center", "width" => 100)); + $table->construct_cell("{$result['name']['value']}
{$result['description']['value']}
{$lang->created_by} {$result['author']['value']}"); + $table->construct_cell("{$lang->download}", array("class" => "align_center")); + $table->construct_row(); + } + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->error_no_results_found, array("colspan" => 3)); + $table->construct_row(); + } + + $search = new Form("index.php?module=style-themes&action=browse", 'post', 'search_form'); + echo "
"; + if($mybb->input['keywords']) + { + $default_class = ''; + $value = htmlspecialchars_uni($mybb->input['keywords']); + } + else + { + $default_class = "search_default"; + $value = $lang->search_for_themes; + } + echo $search->generate_text_box('keywords', $value, array('id' => 'search_keywords', 'class' => "{$default_class} field150 field_small"))."\n"; + echo "search}\" />\n"; + echo "\n"; + echo "
\n"; + echo $search->end(); + + // Recommended themes = Default; Otherwise search results & pagination + if($mybb->request_method == "post") + { + $table->output("{$lang->browse_all_themes}".$lang->sprintf($lang->browse_results_for_mybb, $mybb->version)); + } + else + { + $table->output("{$lang->browse_all_themes}".$lang->sprintf($lang->recommended_themes_for_mybb, $mybb->version)); + } + + echo "
".draw_admin_pagination($mybb->input['page'], 15, $tree['results']['attributes']['total'], "index.php?module=style-themes&action=browse{$keywords}&page={page}"); + + $page->output_footer(); +} + +if($mybb->input['action'] == "import") +{ + $plugins->run_hooks("admin_style_themes_import"); + + if($mybb->request_method == "post") + { + if(!$_FILES['local_file'] && !$mybb->input['url']) + { + $errors[] = $lang->error_missing_url; + } + + if(!$errors) + { + // Find out if there was an uploaded file + if($_FILES['local_file']['error'] != 4) + { + // Find out if there was an error with the uploaded file + if($_FILES['local_file']['error'] != 0) + { + $errors[] = $lang->error_uploadfailed.$lang->error_uploadfailed_detail; + switch($_FILES['local_file']['error']) + { + case 1: // UPLOAD_ERR_INI_SIZE + $errors[] = $lang->error_uploadfailed_php1; + break; + case 2: // UPLOAD_ERR_FORM_SIZE + $errors[] = $lang->error_uploadfailed_php2; + break; + case 3: // UPLOAD_ERR_PARTIAL + $errors[] = $lang->error_uploadfailed_php3; + break; + case 6: // UPLOAD_ERR_NO_TMP_DIR + $errors[] = $lang->error_uploadfailed_php6; + break; + case 7: // UPLOAD_ERR_CANT_WRITE + $errors[] = $lang->error_uploadfailed_php7; + break; + default: + $errors[] = $lang->sprintf($lang->error_uploadfailed_phpx, $_FILES['local_file']['error']); + break; + } + } + + if(!$errors) + { + // Was the temporary file found? + if(!is_uploaded_file($_FILES['local_file']['tmp_name'])) + { + $errors[] = $lang->error_uploadfailed_lost; + } + // Get the contents + $contents = @file_get_contents($_FILES['local_file']['tmp_name']); + // Delete the temporary file if possible + @unlink($_FILES['local_file']['tmp_name']); + // Are there contents? + if(!trim($contents)) + { + $errors[] = $lang->error_uploadfailed_nocontents; + } + } + } + else if(!empty($mybb->input['url'])) + { + // Get the contents + $contents = @fetch_remote_file($mybb->input['url']); + if(!$contents) + { + $errors[] = $lang->error_local_file; + } + } + else + { + // UPLOAD_ERR_NO_FILE + $errors[] = $lang->error_uploadfailed_php4; + } + + if(!$errors) + { + $options = array( + 'no_stylesheets' => ($mybb->input['import_stylesheets'] ? 0 : 1), + 'no_templates' => ($mybb->input['import_templates'] ? 0 : 1), + 'version_compat' => (int)$mybb->input['version_compat'], + 'parent' => $mybb->get_input('tid', 1), + 'force_name_check' => true, + ); + $theme_id = import_theme_xml($contents, $options); + + if($theme_id > -1) + { + $plugins->run_hooks("admin_style_themes_import_commit"); + + // Log admin action + log_admin_action($theme_id); + + flash_message($lang->success_imported_theme, 'success'); + admin_redirect("index.php?module=style-themes&action=edit&tid=".$theme_id); + } + else + { + switch($theme_id) + { + case -1: + $errors[] = $lang->error_uploadfailed_nocontents; + break; + case -2: + $errors[] = $lang->error_invalid_version; + break; + case -3: + $errors[] = $lang->error_theme_already_exists; + break; + case -4: + $errors[] = $lang->error_theme_security_problem; + } + } + } + } + } + + $query = $db->simple_select("themes", "tid, name"); + while($theme = $db->fetch_array($query)) + { + $themes[$theme['tid']] = $theme['name']; + } + + $page->add_breadcrumb_item($lang->import_a_theme, "index.php?module=style-themes&action=import"); + + $page->output_header("{$lang->themes} - {$lang->import_a_theme}"); + + $page->output_nav_tabs($sub_tabs, 'import_theme'); + + if($errors) + { + $page->output_inline_error($errors); + + if($mybb->input['import'] == 1) + { + $import_checked[1] = ""; + $import_checked[2] = "checked=\"checked\""; + } + else + { + $import_checked[1] = "checked=\"checked\""; + $import_checked[2] = ""; + } + } + else + { + $import_checked[1] = "checked=\"checked\""; + $import_checked[2] = ""; + + $mybb->input['import_stylesheets'] = true; + $mybb->input['import_templates'] = true; + } + + $form = new Form("index.php?module=style-themes&action=import", "post", "", 1); + + $actions = ' +
+
+
+ + + + +
'.$form->generate_file_upload_box("local_file", array('style' => 'width: 230px;')).'
+
+
+
+ + + + +
'.$form->generate_text_box("url", $mybb->input['file']).'
+
+ '; + + $form_container = new FormContainer($lang->import_a_theme); + $form_container->output_row($lang->import_from, $lang->import_from_desc, $actions, 'file'); + $form_container->output_row($lang->parent_theme, $lang->parent_theme_desc, $form->generate_select_box('tid', $themes, $mybb->input['tid'], array('id' => 'tid')), 'tid'); + $form_container->output_row($lang->new_name, $lang->new_name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->advanced_options, "", $form->generate_check_box('version_compat', '1', $lang->ignore_version_compatibility, array('checked' => $mybb->input['version_compat'], 'id' => 'version_compat'))."
{$lang->ignore_version_compat_desc}
".$form->generate_check_box('import_stylesheets', '1', $lang->import_stylesheets, array('checked' => $mybb->input['import_stylesheets'], 'id' => 'import_stylesheets'))."
{$lang->import_stylesheets_desc}
".$form->generate_check_box('import_templates', '1', $lang->import_templates, array('checked' => $mybb->input['import_templates'], 'id' => 'import_templates'))."
{$lang->import_templates_desc}"); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->import_theme); + + $form->output_submit_wrapper($buttons); + + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "export") +{ + $query = $db->simple_select("themes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $theme = $db->fetch_array($query); + + // Does the theme not exist? + if(!$theme['tid']) + { + flash_message($lang->error_invalid_theme, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $plugins->run_hooks("admin_style_themes_export"); + + if($mybb->request_method == "post") + { + $properties = my_unserialize($theme['properties']); + + $xml = "settings['charset']}\"?".">\r\n"; + $xml .= "version_code."\">\r\n"; + $xml .= "\t\r\n"; + foreach($properties as $property => $value) + { + if($property == "inherited") continue; + + if(is_array($value)) + { + $value = serialize($value); + } + + $value = str_replace(']]>', ']]]]>', $value); + + $xml .= "\t\t<{$property}>\r\n"; + } + $xml .= "\t\r\n"; + + // Fetch list of all of the stylesheets for this theme + $file_stylesheets = my_unserialize($theme['stylesheets']); + + $stylesheets = array(); + $inherited_load = array(); + + // Now we loop through the list of stylesheets for each file + foreach($file_stylesheets as $file => $action_stylesheet) + { + if($file == 'inherited' || !is_array($action_stylesheet)) + { + continue; + } + + foreach($action_stylesheet as $action => $style) + { + foreach($style as $stylesheet) + { + $stylesheets[$stylesheet]['applied_to'][$file][] = $action; + if(is_array($file_stylesheets['inherited'][$file."_".$action]) && in_array($stylesheet, array_keys($file_stylesheets['inherited'][$file."_".$action]))) + { + $stylesheets[$stylesheet]['inherited'] = $file_stylesheets['inherited'][$file."_".$action]; + foreach($file_stylesheets['inherited'][$file."_".$action] as $value) + { + $inherited_load[] = $value; + } + } + } + } + } + + $inherited_load[] = $mybb->input['tid']; + $inherited_load = array_unique($inherited_load); + + $inherited_themes = array(); + if(count($inherited_load) > 0) + { + $query = $db->simple_select("themes", "tid, name", "tid IN (".implode(",", $inherited_load).")"); + while($inherited_theme = $db->fetch_array($query)) + { + $inherited_themes[$inherited_theme['tid']] = $inherited_theme['name']; + } + } + + $theme_stylesheets = array(); + + if(count($inherited_load) > 0) + { + $query = $db->simple_select("themestylesheets", "*", "tid IN (".implode(",", $inherited_load).")", array('order_by' => 'tid', 'order_dir' => 'desc')); + while($theme_stylesheet = $db->fetch_array($query)) + { + if(!$theme_stylesheets[$theme_stylesheet['cachefile']]) + { + $theme_stylesheets[$theme_stylesheet['cachefile']] = $theme_stylesheet; + $theme_stylesheets[$theme_stylesheet['sid']] = $theme_stylesheet['cachefile']; + } + } + } + + $xml .= "\t\r\n"; + foreach($stylesheets as $filename => $style) + { + if(strpos($filename, 'css.php?stylesheet=') !== false) + { + $style['sid'] = (integer)str_replace('css.php?stylesheet=', '', $filename); + $filename = $theme_stylesheets[$style['sid']]; + } + else + { + $filename = basename($filename); + $style['sid'] = $theme_stylesheets[$filename]['sid']; + } + + $style['tid'] = $theme_stylesheets[$filename]['tid']; + + if($mybb->input['custom_theme'] == 1 && $style['tid'] != $mybb->input['tid']) + { + continue; + } + + // Has the file on the file system been modified? + resync_stylesheet($theme_stylesheets[$filename]); + + $style['sid'] = $theme_stylesheets[$filename]['sid']; + + $attachedto = $theme_stylesheets[$filename]['attachedto']; + $stylesheet = $theme_stylesheets[$filename]['stylesheet']; + $stylesheet = str_replace(']]>', ']]]]>', $stylesheet); + + if($attachedto) + { + $attachedto = "attachedto=\"{$attachedto}\" "; + } + + $filename = $theme_stylesheets[$filename]['name']; + + $xml .= "\t\tversion_code}\">\r\n\t\t\r\n"; + + } + $xml .= "\t\r\n"; + + if($mybb->input['include_templates'] != 0) + { + $xml .= "\t\r\n"; + $query = $db->simple_select("templates", "*", "sid='".$properties['templateset']."'"); + while($template = $db->fetch_array($query)) + { + $template['template'] = str_replace(']]>', ']]]]>', $template['template']); + $xml .= "\t\t\r\n"; + } + $xml .= "\t\r\n"; + } + $xml .= ""; + + $plugins->run_hooks("admin_style_themes_export_commit"); + + // Log admin action + log_admin_action($theme['tid'], htmlspecialchars_uni($theme['name'])); + + $theme['name'] = rawurlencode($theme['name']); + header("Content-disposition: attachment; filename=".$theme['name']."-theme.xml"); + header("Content-type: application/octet-stream"); + header("Content-Length: ".strlen($xml)); + header("Pragma: no-cache"); + header("Expires: 0"); + echo $xml; + exit; + } + + $page->add_breadcrumb_item(htmlspecialchars_uni($theme['name']), "index.php?module=style-themes&action=edit&tid={$mybb->input['tid']}"); + + $page->add_breadcrumb_item($lang->export_theme, "index.php?module=style-themes&action=export"); + + $page->output_header("{$lang->themes} - {$lang->export_theme}"); + + $sub_tabs['edit_stylesheets'] = array( + 'title' => $lang->edit_stylesheets, + 'link' => "index.php?module=style-themes&action=edit&tid={$mybb->input['tid']}", + ); + + $sub_tabs['add_stylesheet'] = array( + 'title' => $lang->add_stylesheet, + 'link' => "index.php?module=style-themes&action=add_stylesheet&tid={$mybb->input['tid']}", + ); + + $sub_tabs['export_theme'] = array( + 'title' => $lang->export_theme, + 'link' => "index.php?module=style-themes&action=export&tid={$mybb->input['tid']}", + 'description' => $lang->export_theme_desc + ); + + $sub_tabs['duplicate_theme'] = array( + 'title' => $lang->duplicate_theme, + 'link' => "index.php?module=style-themes&action=duplicate&tid={$mybb->input['tid']}", + 'description' => $lang->duplicate_theme_desc + ); + + $page->output_nav_tabs($sub_tabs, 'export_theme'); + + if($errors) + { + $page->output_inline_error($errors); + } + + $form = new Form("index.php?module=style-themes&action=export", "post"); + echo $form->generate_hidden_field("tid", $theme['tid']); + + $form_container = new FormContainer($lang->export_theme.": ".htmlspecialchars_uni($theme['name'])); + $form_container->output_row($lang->include_custom_only, $lang->include_custom_only_desc, $form->generate_yes_no_radio('custom_theme', $mybb->input['custom_theme']), 'custom_theme'); + $form_container->output_row($lang->include_templates, $lang->include_templates_desc, $form->generate_yes_no_radio('include_templates', $mybb->input['include_templates']), 'include_templates'); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->export_theme); + + $form->output_submit_wrapper($buttons); + + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "duplicate") +{ + $query = $db->simple_select("themes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $theme = $db->fetch_array($query); + + // Does the theme not exist? + if(!$theme['tid']) + { + flash_message($lang->error_invalid_theme, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $plugins->run_hooks("admin_style_themes_duplicate"); + + if($mybb->request_method == "post") + { + if($mybb->input['name'] == "") + { + $errors[] = $lang->error_missing_name; + } + else + { + $query = $db->simple_select("themes", "COUNT(tid) as numthemes", "name = '".$db->escape_string($mybb->get_input('name'))."'"); + $numthemes = $db->fetch_field($query, 'numthemes'); + + if($numthemes) + { + $errors[] = $lang->error_theme_already_exists; + } + } + + if(!$errors) + { + $properties = my_unserialize($theme['properties']); + $sid = $properties['sid']; + $nprops = null; + if($mybb->input['duplicate_templates']) + { + $nsid = $db->insert_query("templatesets", array('title' => $db->escape_string($mybb->input['name'])." Templates")); + + // Copy all old Templates to our new templateset + $query = $db->simple_select("templates", "*", "sid='{$sid}'"); + while($template = $db->fetch_array($query)) + { + $insert = array( + "title" => $db->escape_string($template['title']), + "template" => $db->escape_string($template['template']), + "sid" => $nsid, + "version" => $db->escape_string($template['version']), + "dateline" => TIME_NOW + ); + + if($db->engine == "pgsql") + { + echo " "; + flush(); + } + + $db->insert_query("templates", $insert); + } + + // We need to change the templateset so we need to work out the others properties too + foreach($properties as $property => $value) + { + if($property == "inherited") + { + continue; + } + + $nprops[$property] = $value; + if($properties['inherited'][$property]) + { + $nprops['inherited'][$property] = $properties['inherited'][$property]; + } + else + { + $nprops['inherited'][$property] = $theme['tid']; + } + } + $nprops['templateset'] = $nsid; + } + $tid = build_new_theme($mybb->input['name'], $nprops, $theme['tid']); + + update_theme_stylesheet_list($tid); + + $plugins->run_hooks("admin_style_themes_duplicate_commit"); + + // Log admin action + log_admin_action($tid, $theme['tid']); + + flash_message($lang->success_duplicated_theme, 'success'); + admin_redirect("index.php?module=style-themes&action=edit&tid=".$tid); + } + } + + $page->add_breadcrumb_item(htmlspecialchars_uni($theme['name']), "index.php?module=style-themes&action=edit&tid={$mybb->input['tid']}"); + + $page->add_breadcrumb_item($lang->duplicate_theme, "index.php?module=style-themes&action=duplicate&tid={$theme['tid']}"); + + $page->output_header("{$lang->themes} - {$lang->duplicate_theme}"); + + $sub_tabs['edit_stylesheets'] = array( + 'title' => $lang->edit_stylesheets, + 'link' => "index.php?module=style-themes&action=edit&tid={$mybb->input['tid']}", + ); + + $sub_tabs['add_stylesheet'] = array( + 'title' => $lang->add_stylesheet, + 'link' => "index.php?module=style-themes&action=add_stylesheet&tid={$mybb->input['tid']}", + ); + + $sub_tabs['export_theme'] = array( + 'title' => $lang->export_theme, + 'link' => "index.php?module=style-themes&action=export&tid={$mybb->input['tid']}", + 'description' => $lang->export_theme_desc + ); + + $sub_tabs['duplicate_theme'] = array( + 'title' => $lang->duplicate_theme, + 'link' => "index.php?module=style-themes&action=duplicate&tid={$mybb->input['tid']}", + 'description' => $lang->duplicate_theme_desc + ); + + $page->output_nav_tabs($sub_tabs, 'duplicate_theme'); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['duplicate_templates'] = true; + } + + $form = new Form("index.php?module=style-themes&action=duplicate&tid={$theme['tid']}", "post"); + + $form_container = new FormContainer($lang->duplicate_theme); + $form_container->output_row($lang->new_name, $lang->new_name_duplicate_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->advanced_options, "", $form->generate_check_box('duplicate_templates', '1', $lang->duplicate_templates, array('checked' => $mybb->input['duplicate_templates'], 'id' => 'duplicate_templates'))."
{$lang->duplicate_templates_desc}"); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->duplicate_theme); + + $form->output_submit_wrapper($buttons); + + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_style_themes_add"); + + $query = $db->simple_select("themes", "tid, name"); + while($theme = $db->fetch_array($query)) + { + $themes[$theme['tid']] = $theme['name']; + } + + if($mybb->request_method == "post") + { + if(!$mybb->input['name']) + { + $errors[] = $lang->error_missing_name; + } + else if(in_array($mybb->input['name'], $themes)) + { + $errors[] = $lang->error_theme_already_exists; + } + + if(!$errors) + { + $tid = build_new_theme($mybb->input['name'], null, $mybb->input['tid']); + + $plugins->run_hooks("admin_style_themes_add_commit"); + + // Log admin action + log_admin_action(htmlspecialchars_uni($mybb->input['name']), $tid); + + flash_message($lang->success_theme_created, 'success'); + admin_redirect("index.php?module=style-themes&action=edit&tid=".$tid); + } + } + + $page->add_breadcrumb_item($lang->create_new_theme, "index.php?module=style-themes&action=add"); + + $page->output_header("{$lang->themes} - {$lang->create_new_theme}"); + + $page->output_nav_tabs($sub_tabs, 'create_theme'); + + if($errors) + { + $page->output_inline_error($errors); + } + + $form = new Form("index.php?module=style-themes&action=add", "post"); + + $form_container = new FormContainer($lang->create_a_theme); + $form_container->output_row($lang->name, $lang->name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name')), 'name'); + $form_container->output_row($lang->parent_theme, $lang->parent_theme_desc, $form->generate_select_box('tid', $themes, $mybb->input['tid'], array('id' => 'tid')), 'tid'); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->create_new_theme); + + $form->output_submit_wrapper($buttons); + + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("themes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $theme = $db->fetch_array($query); + + // Does the theme not exist? or are we trying to delete the master? + if(!$theme['tid'] || $theme['tid'] == 1) + { + flash_message($lang->error_invalid_theme, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=style-themes"); + } + + $plugins->run_hooks("admin_style_themes_delete"); + + if($mybb->request_method == "post") + { + $inherited_theme_cache = array(); + + $query = $db->simple_select("themes", "tid,stylesheets", "tid != '{$theme['tid']}'", array('order_by' => "pid, name")); + while($theme2 = $db->fetch_array($query)) + { + $theme2['stylesheets'] = my_unserialize($theme2['stylesheets']); + + if(!$theme2['stylesheets']['inherited']) + { + continue; + } + + $inherited_theme_cache[$theme2['tid']] = $theme2['stylesheets']['inherited']; + } + + $inherited_stylesheets = false; + + // Are any other themes relying on stylesheets from this theme? Get a list and show an error + foreach($inherited_theme_cache as $tid => $inherited) + { + foreach($inherited as $file => $value) + { + foreach($value as $filepath => $val) + { + if(strpos($filepath, "cache/themes/theme{$theme['tid']}") !== false) + { + $inherited_stylesheets = true; + } + } + } + } + + if($inherited_stylesheets == true) + { + flash_message($lang->error_inheriting_stylesheets, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $query = $db->simple_select("themestylesheets", "cachefile", "tid='{$theme['tid']}'"); + while($cachefile = $db->fetch_array($query)) + { + @unlink(MYBB_ROOT."cache/themes/theme{$theme['tid']}/{$cachefile['cachefile']}"); + } + @unlink(MYBB_ROOT."cache/themes/theme{$theme['tid']}/index.html"); + + $db->delete_query("themestylesheets", "tid='{$theme['tid']}'"); + + // Update the CSS file list for this theme + update_theme_stylesheet_list($theme['tid'], $theme, true); + + $db->update_query("users", array('style' => 0), "style='{$theme['tid']}'"); + + @rmdir(MYBB_ROOT."cache/themes/theme{$theme['tid']}/"); + + $children = make_child_theme_list($theme['tid']); + $child_tid = $children[0]; + + $db->update_query("themes", array('pid' => $theme['pid']), "tid='{$child_tid}'"); + + $db->delete_query("themes", "tid='{$theme['tid']}'", 1); + + $plugins->run_hooks("admin_style_themes_delete_commit"); + + // Log admin action + log_admin_action($theme['tid'], htmlspecialchars_uni($theme['name'])); + + flash_message($lang->success_theme_deleted, 'success'); + admin_redirect("index.php?module=style-themes"); + } + else + { + $page->output_confirm_action("index.php?module=style-themes&action=delete&tid={$theme['tid']}", $lang->confirm_theme_deletion); + } +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("themes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $theme = $db->fetch_array($query); + + // Does the theme not exist? + if(!$theme['tid'] || $theme['tid'] == 1) + { + flash_message($lang->error_invalid_theme, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $plugins->run_hooks("admin_style_themes_edit"); + + if($mybb->request_method == "post" && !$mybb->input['do']) + { + $properties = array( + 'templateset' => (int)$mybb->input['templateset'], + 'editortheme' => $mybb->input['editortheme'], + 'imgdir' => $mybb->input['imgdir'], + 'logo' => $mybb->input['logo'], + 'tablespace' => (int)$mybb->input['tablespace'], + 'borderwidth' => (int)$mybb->input['borderwidth'], + 'color' => $mybb->input['color'] + ); + + if($properties['color'] == 'none') + { + unset($properties['color']); + } + + if($mybb->input['colors']) + { + $colors = explode("\n", $mybb->input['colors']); + + foreach($colors as $color) + { + $color = explode("=", $color); + + $properties['colors'][$color[0]] = $color[1]; + } + } + + if($properties['templateset'] <= 0) + { + $errors[] = $lang->error_invalid_templateset; + } + + $theme_properties = my_unserialize($theme['properties']); + if($theme_properties['disporder']) + { + $properties['disporder'] = $theme_properties['disporder']; + } + + $allowedgroups = array(); + if(is_array($mybb->input['allowedgroups'])) + { + foreach($mybb->input['allowedgroups'] as $gid) + { + if($gid == "all") + { + $allowedgroups = "all"; + break; + } + $gid = (int)$gid; + $allowedgroups[$gid] = $gid; + } + } + if(is_array($allowedgroups)) + { + $allowedgroups = implode(",", $allowedgroups); + } + + $update_array = array( + 'name' => $db->escape_string($mybb->input['name']), + 'pid' => $mybb->get_input('pid', 1), + 'allowedgroups' => $allowedgroups, + 'properties' => $db->escape_string(serialize($properties)) + ); + + // perform validation + if(!$update_array['name']) + { + $errors[] = $lang->error_missing_name; + } + else + { + $query = $db->simple_select("themes", "COUNT(tid) as numthemes", "name = '".$db->escape_string($update_array['name'])."' AND tid != '{$theme['tid']}'"); + $numthemes = $db->fetch_field($query, 'numthemes'); + + if($numthemes) + { + $errors[] = $lang->error_theme_already_exists; + } + } + + if($update_array['pid']) + { + $query = $db->simple_select("themes", "tid", "tid='".$update_array['pid']."'"); + $parent_check = $db->fetch_field($query, "tid"); + if(!$parent_check) + { + $errors[] = $lang->error_invalid_parent_theme; + } + } + if($properties['templateset']) + { + $query = $db->simple_select("templatesets", "sid", "sid='".$properties['templateset']."'"); + $ts_check = $db->fetch_field($query, "sid"); + if(!$ts_check) + { + unset($properties['templateset']); + } + } + if(!$properties['templateset']) + { + $errors[] = $lang->error_invalid_templateset; + } + if(!$properties['editortheme'] || !file_exists(MYBB_ROOT."jscripts/sceditor/editor_themes/".$properties['editortheme']) || is_dir(MYBB_ROOT."jscripts/sceditor/editor_themes/".$properties['editortheme'])) + { + $errors[] = $lang->error_invalid_editortheme; + } + + if(empty($errors)) + { + $plugins->run_hooks("admin_style_themes_edit_commit"); + + $db->update_query("themes", $update_array, "tid='{$theme['tid']}'"); + + if($theme['def'] == 1) + { + $cache->update_default_theme(); + } + + // Log admin action + log_admin_action($theme['tid'], htmlspecialchars_uni($theme['name'])); + + flash_message($lang->success_theme_properties_updated, 'success'); + admin_redirect("index.php?module=style-themes&action=edit&tid={$theme['tid']}"); + } + } + + // Fetch list of all of the stylesheets for this theme + $file_stylesheets = my_unserialize($theme['stylesheets']); + + $stylesheets = array(); + $inherited_load = array(); + + // Now we loop through the list of stylesheets for each file + foreach($file_stylesheets as $file => $action_stylesheet) + { + if($file == 'inherited' || !is_array($action_stylesheet)) + { + continue; + } + + foreach($action_stylesheet as $action => $style) + { + foreach($style as $stylesheet) + { + $stylesheets[$stylesheet]['applied_to'][$file][] = $action; + if(is_array($file_stylesheets['inherited'][$file."_".$action]) && in_array($stylesheet, array_keys($file_stylesheets['inherited'][$file."_".$action]))) + { + $stylesheets[$stylesheet]['inherited'] = $file_stylesheets['inherited'][$file."_".$action]; + foreach($file_stylesheets['inherited'][$file."_".$action] as $value) + { + $inherited_load[] = $value; + } + } + } + } + } + + $inherited_load[] = $mybb->input['tid']; + $inherited_load = array_unique($inherited_load); + + $inherited_themes = array(); + if(count($inherited_load) > 0) + { + $query = $db->simple_select("themes", "tid, name", "tid IN (".implode(",", $inherited_load).")"); + while($inherited_theme = $db->fetch_array($query)) + { + $inherited_themes[$inherited_theme['tid']] = $inherited_theme['name']; + } + } + + $theme_stylesheets = array(); + + if(count($inherited_load) > 0) + { + $query = $db->simple_select("themestylesheets", "*", "", array('order_by' => 'sid DESC, tid', 'order_dir' => 'desc')); + while($theme_stylesheet = $db->fetch_array($query)) + { + if(!isset($theme_stylesheets[$theme_stylesheet['name']]) && in_array($theme_stylesheet['tid'], $inherited_load)) + { + $theme_stylesheets[$theme_stylesheet['name']] = $theme_stylesheet; + } + + $theme_stylesheets[$theme_stylesheet['sid']] = $theme_stylesheet['name']; + } + } + + // Save any stylesheet orders + if($mybb->request_method == "post" && $mybb->input['do'] == "save_orders") + { + if(!is_array($mybb->input['disporder'])) + { + // Error out + flash_message($lang->error_no_display_order, 'error'); + admin_redirect("index.php?module=style-themes&action=edit&tid={$theme['tid']}"); + } + + $orders = array(); + foreach($theme_stylesheets as $stylesheet => $properties) + { + if(is_array($properties)) + { + $order = (int)$mybb->input['disporder'][$properties['sid']]; + + $orders[$properties['name']] = $order; + } + } + + asort($orders, SORT_NUMERIC); + + // Save the orders in the theme properties + $properties = my_unserialize($theme['properties']); + $properties['disporder'] = $orders; + + $update_array = array( + "properties" => $db->escape_string(serialize($properties)) + ); + + $db->update_query("themes", $update_array, "tid = '{$theme['tid']}'"); + + if($theme['def'] == 1) + { + $cache->update_default_theme(); + } + + // normalize for consistency + update_theme_stylesheet_list($theme['tid'], false, true); + + flash_message($lang->success_stylesheet_order_updated, 'success'); + admin_redirect("index.php?module=style-themes&action=edit&tid={$theme['tid']}"); + } + + $page->add_breadcrumb_item(htmlspecialchars_uni($theme['name']), "index.php?module=style-themes&action=edit&tid={$mybb->input['tid']}"); + + $page->output_header("{$lang->themes} - {$lang->stylesheets}"); + + $sub_tabs['edit_stylesheets'] = array( + 'title' => $lang->edit_stylesheets, + 'link' => "index.php?module=style-themes&action=edit&tid={$mybb->input['tid']}", + 'description' => $lang->edit_stylesheets_desc + ); + + $sub_tabs['add_stylesheet'] = array( + 'title' => $lang->add_stylesheet, + 'link' => "index.php?module=style-themes&action=add_stylesheet&tid={$mybb->input['tid']}", + ); + + $sub_tabs['export_theme'] = array( + 'title' => $lang->export_theme, + 'link' => "index.php?module=style-themes&action=export&tid={$mybb->input['tid']}" + ); + + $sub_tabs['duplicate_theme'] = array( + 'title' => $lang->duplicate_theme, + 'link' => "index.php?module=style-themes&action=duplicate&tid={$mybb->input['tid']}", + 'description' => $lang->duplicate_theme_desc + ); + + $properties = my_unserialize($theme['properties']); + $page->output_nav_tabs($sub_tabs, 'edit_stylesheets'); + + $table = new Table; + $table->construct_header($lang->stylesheets); + $table->construct_header($lang->display_order, array("class" => "align_center", "width" => 50)); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 150)); + + // Display Order form + $form = new Form("index.php?module=style-themes&action=edit", "post", "edit"); + echo $form->generate_hidden_field("tid", $theme['tid']); + echo $form->generate_hidden_field("do", 'save_orders'); + + // Order the stylesheets + $ordered_stylesheets = array(); + + foreach($properties['disporder'] as $style_name => $order) + { + foreach($stylesheets as $filename => $style) + { + if(strpos($filename, 'css.php?stylesheet=') !== false) + { + $style['sid'] = (integer)str_replace('css.php?stylesheet=', '', $filename); + $filename = $theme_stylesheets[$style['sid']]; + } + + if(basename($filename) != $style_name) + { + continue; + } + + $ordered_stylesheets[$filename] = $style; + } + } + + foreach($ordered_stylesheets as $filename => $style) + { + if(strpos($filename, 'css.php?stylesheet=') !== false) + { + $style['sid'] = (integer)str_replace('css.php?stylesheet=', '', $filename); + $filename = $theme_stylesheets[$style['sid']]; + } + else + { + $filename = basename($filename); + $style['sid'] = $theme_stylesheets[$filename]['sid']; + } + + // Has the file on the file system been modified? + resync_stylesheet($theme_stylesheets[$filename]); + + $filename = $theme_stylesheets[$filename]['name']; + + $inherited = ""; + $inherited_ary = array(); + if(is_array($style['inherited'])) + { + foreach($style['inherited'] as $tid) + { + if($inherited_themes[$tid]) + { + $inherited_ary[$tid] = $inherited_themes[$tid]; + } + } + } + + if(!empty($inherited_ary)) + { + $inherited = " ({$lang->inherited_from}"; + $sep = " "; + $inherited_count = count($inherited_ary); + $count = 0; + + foreach($inherited_ary as $tid => $file) + { + if(isset($applied_to_count) && $count == $applied_to_count && $count != 0) + { + $sep = " {$lang->and} "; + } + + $inherited .= $sep.$file; + $sep = $lang->comma; + + ++$count; + } + $inherited .= ")"; + } + + if(is_array($style['applied_to']) && (!isset($style['applied_to']['global']) || $style['applied_to']['global'][0] != "global")) + { + $attached_to = ''; + + $applied_to_count = count($style['applied_to']); + $count = 0; + $sep = " "; + $name = ""; + + $colors = array(); + + if(!is_array($properties['colors'])) + { + $properties['colors'] = array(); + } + + foreach($style['applied_to'] as $name => $actions) + { + if(!$name) + { + continue; + } + + if(array_key_exists($name, $properties['colors'])) + { + $colors[] = $properties['colors'][$name]; + } + + if(count($colors)) + { + // Colors override files and are handled below. + continue; + } + + // It's a file: + ++$count; + + if($actions[0] != "global") + { + $name = "{$name} ({$lang->actions}: ".implode(',', $actions).")"; + } + + if($count == $applied_to_count && $count > 1) + { + $sep = " {$lang->and} "; + } + $attached_to .= $sep.$name; + + $sep = $lang->comma; + } + + if($attached_to) + { + $attached_to = "{$lang->attached_to} {$attached_to}"; + } + + if(count($colors)) + { + // Attached to color instead of files. + $count = 1; + $color_list = $sep = ''; + + foreach($colors as $color) + { + if($count == count($colors) && $count > 1) + { + $sep = " {$lang->and} "; + } + + $color_list .= $sep.trim($color); + ++$count; + + $sep = ', '; + } + + $attached_to = "{$lang->attached_to} ".$lang->sprintf($lang->colors_attached_to)." {$color_list}"; + } + + if($attached_to == '') + { + // Orphaned! :( + $attached_to = "{$lang->attached_to_nothing}"; + } + } + else + { + $attached_to = "{$lang->attached_to_all_pages}"; + } + + $popup = new PopupMenu("style_{$style['sid']}", $lang->options); + + $popup->add_item($lang->edit_style, "index.php?module=style-themes&action=edit_stylesheet&file=".htmlspecialchars_uni($filename)."&tid={$theme['tid']}"); + $popup->add_item($lang->properties, "index.php?module=style-themes&action=stylesheet_properties&file=".htmlspecialchars_uni($filename)."&tid={$theme['tid']}"); + + if($inherited == "") + { + $popup->add_item($lang->delete_revert, "index.php?module=style-themes&action=delete_stylesheet&file=".htmlspecialchars_uni($filename)."&tid={$theme['tid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_stylesheet_deletion}')"); + } + + $table->construct_cell("{$filename}{$inherited}
{$attached_to}"); + $table->construct_cell($form->generate_numeric_field("disporder[{$theme_stylesheets[$filename]['sid']}]", $properties['disporder'][$filename], array('style' => 'width: 80%; text-align: center;')), array("class" => "align_center")); + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + $table->construct_row(); + } + + $table->output("{$lang->stylesheets_in} ".htmlspecialchars_uni($theme['name'])); + + $buttons = array($form->generate_submit_button($lang->save_stylesheet_order)); + $form->output_submit_wrapper($buttons); + $form->end(); + + echo '
'; + + // Theme Properties table + if($errors) + { + $page->output_inline_error($errors); + } + + $form = new Form("index.php?module=style-themes&action=edit", "post", "edit"); + echo $form->generate_hidden_field("tid", $theme['tid']); + $form_container = new FormContainer($lang->edit_theme_properties); + $form_container->output_row($lang->name." *", $lang->name_desc_edit, $form->generate_text_box('name', $theme['name'], array('id' => 'name')), 'name'); + + $options = build_theme_array($theme['tid']); + $form_container->output_row($lang->parent_theme." *", $lang->parent_theme_desc, $form->generate_select_box('pid', $options, $theme['pid'], array('id' => 'pid')), 'pid'); + + $options = array(); + $query = $db->simple_select("usergroups", "gid, title", "gid != '1'", array('order_by' => 'title')); + $options['all'] = $lang->all_user_groups; + while($usergroup = $db->fetch_array($query)) + { + $options[(int)$usergroup['gid']] = $usergroup['title']; + } + $form_container->output_row($lang->allowed_user_groups, $lang->allowed_user_groups_desc, $form->generate_select_box('allowedgroups[]', $options, explode(",", $theme['allowedgroups']), array('id' => 'allowedgroups', 'multiple' => true, 'size' => 5)), 'allowedgroups'); + + $options = array(); + $query = $db->simple_select("templatesets", "*", "", array('order_by' => 'title')); + while($templateset = $db->fetch_array($query)) + { + $options[(int)$templateset['sid']] = $templateset['title']; + } + $form_container->output_row($lang->template_set." *", $lang->template_set_desc, $form->generate_select_box('templateset', $options, $properties['templateset'], array('id' => 'templateset')), 'templateset'); + + $options = array(); + $editor_theme_root = MYBB_ROOT."jscripts/sceditor/editor_themes/"; + if($dh = @opendir($editor_theme_root)) + { + while($dir = readdir($dh)) + { + if($dir == ".svn" || $dir == "." || $dir == ".." || is_dir($editor_theme_root.$dir) || get_extension($editor_theme_root.$dir) != 'css') + { + continue; + } + $options[$dir] = ucfirst(str_replace(array('_', '.css'), array(' ', ''), $dir)); + } + } + + $form_container->output_row($lang->editor_theme." *", $lang->editor_theme_desc, $form->generate_select_box('editortheme', $options, $properties['editortheme'], array('id' => 'editortheme')), 'editortheme'); + + $form_container->output_row($lang->img_directory, $lang->img_directory_desc, $form->generate_text_box('imgdir', $properties['imgdir'], array('id' => 'imgdir')), 'imgdir'); + $form_container->output_row($lang->logo, $lang->logo_desc, $form->generate_text_box('logo', $properties['logo'], array('id' => 'boardlogo')), 'logo'); + $form_container->output_row($lang->table_spacing, $lang->table_spacing_desc, $form->generate_numeric_field('tablespace', $properties['tablespace'], array('id' => 'tablespace')), 'tablespace'); + $form_container->output_row($lang->inner_border, $lang->inner_border_desc, $form->generate_numeric_field('borderwidth', $properties['borderwidth'], array('id' => 'borderwidth')), 'borderwidth'); + + $form_container->end(); + + $form_container = new FormContainer($lang->colors_manage); + + if(!$properties['colors'] || !is_array($properties['colors'])) + { + $color_setting = $lang->colors_no_color_setting; + } + else + { + $colors = array('none' => $lang->colors_please_select); + $colors = array_merge($colors, $properties['colors']); + + $color_setting = $form->generate_select_box('color', $colors, $properties['color'], array('class' => "select\" style=\"width: 200px;")); + + $mybb->input['colors'] = ''; + foreach($properties['colors'] as $key => $color) + { + if($mybb->input['colors']) + { + $mybb->input['colors'] .= "\n"; + } + + $mybb->input['colors'] .= "{$key}={$color}"; + } + } + + $form_container->output_row($lang->colors_setting, $lang->colors_setting_desc, $color_setting, 'color'); + $form_container->output_row($lang->colors_add, $lang->colors_add_desc, $form->generate_text_area('colors', $mybb->input['colors'], array('style' => 'width: 200px;', 'rows' => '5'))); + + $form_container->end(); + + $buttons = array(); + $buttons[] = $form->generate_submit_button($lang->save_theme_properties); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "stylesheet_properties") +{ + // Fetch the theme we want to edit this stylesheet in + $query = $db->simple_select("themes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $theme = $db->fetch_array($query); + + if(!$theme['tid'] || $theme['tid'] == 1) + { + flash_message($lang->error_invalid_theme, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $plugins->run_hooks("admin_style_themes_stylesheet_properties"); + + $parent_list = make_parent_theme_list($theme['tid']); + $parent_list = implode(',', $parent_list); + if(!$parent_list) + { + $parent_list = 1; + } + + $query = $db->simple_select("themestylesheets", "*", "name='".$db->escape_string($mybb->input['file'])."' AND tid IN ({$parent_list})", array('order_by' => 'tid', 'order_dir' => 'desc', 'limit' => 1)); + $stylesheet = $db->fetch_array($query); + + // Does the theme not exist? + if(!$stylesheet['sid']) + { + flash_message($lang->error_invalid_stylesheet, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + // Fetch list of all of the stylesheets for this theme + $stylesheets = fetch_theme_stylesheets($theme); + + if(!array_key_exists($stylesheet['cachefile'], $stylesheets) && array_key_exists("css.php?stylesheet=".$stylesheet['tid'], $stylesheets)) + { + $stylesheet['cachefile'] = "css.php?stylesheet=".$stylesheet['tid']; + } + + $this_stylesheet = $stylesheets[$stylesheet['cachefile']]; + unset($stylesheets); + + if($mybb->request_method == "post") + { + // Do we not have a name, or is it just an extension? + if(!$mybb->input['name'] || $mybb->input['name'] == ".css") + { + $errors[] = $lang->error_missing_stylesheet_name; + } + + // Get 30 chars only because we don't want more than that + $mybb->input['name'] = my_substr($mybb->input['name'], 0, 30); + if(get_extension($mybb->input['name']) != "css") + { + // Does not end with '.css' + $errors[] = $lang->sprintf($lang->error_missing_stylesheet_extension, $mybb->input['name']); + } + + if(!$errors) + { + // Theme & stylesheet theme ID do not match, editing inherited - we copy to local theme + if($theme['tid'] != $stylesheet['tid']) + { + $stylesheet['sid'] = copy_stylesheet_to_theme($stylesheet, $theme['tid']); + } + + $attached = array(); + if($mybb->input['attach'] == 1) + { + // Our stylesheet is attached to custom pages in MyBB + foreach($mybb->input as $id => $value) + { + $actions_list = ""; + $attached_to = $value; + + if(strpos($id, 'attached_') !== false) + { + // We have a custom attached file + $attached_id = (int)str_replace('attached_', '', $id); + + if($mybb->input['action_'.$attached_id] == 1) + { + // We have custom actions for attached files + $actions_list = $mybb->input['action_list_'.$attached_id]; + } + + if($actions_list) + { + $attached_to .= "?".$actions_list; + } + + $attached[] = $attached_to; + } + } + } + else if($mybb->input['attach'] == 2) + { + if(!is_array($mybb->input['color'])) + { + $errors[] = $lang->error_no_color_picked; + } + else + { + $attached = $mybb->input['color']; + } + } + + // Update Stylesheet + $update_array = array( + 'name' => $db->escape_string($mybb->input['name']), + 'attachedto' => $db->escape_string(implode('|', $attached)) + ); + + if($stylesheet['name'] != $mybb->input['name']) + { + $update_array['cachefile'] = $db->escape_string(str_replace('/', '', $mybb->input['name'])); + } + + $db->update_query("themestylesheets", $update_array, "sid='{$stylesheet['sid']}'", 1); + + // If the name changed, re-cache our stylesheet + $theme_c = $update_d = false; + if($stylesheet['name'] != $mybb->input['name']) + { + // Update the theme stylesheet list if the name is changed + $theme_c = $theme; + $update_d = true; + + $db->update_query("themestylesheets", array('lastmodified' => TIME_NOW), "sid='{$stylesheet['sid']}'", 1); + if(!cache_stylesheet($theme['tid'], str_replace('/', '', $mybb->input['name']), $theme['stylesheet'])) + { + $db->update_query("themestylesheets", array('cachefile' => "css.php?stylesheet={$stylesheet['sid']}"), "sid='{$stylesheet['sid']}'", 1); + } + @unlink(MYBB_ROOT."cache/themes/theme{$theme['tid']}/{$stylesheet['cachefile']}"); + } + + // Update the CSS file list for this theme + update_theme_stylesheet_list($theme['tid'], $theme_c, $update_d); + + $plugins->run_hooks("admin_style_themes_stylesheet_properties_commit"); + + // Log admin action + log_admin_action($stylesheet['sid'], $mybb->input['name'], $theme['tid'], htmlspecialchars_uni($theme['name'])); + + flash_message($lang->success_stylesheet_properties_updated, 'success'); + admin_redirect("index.php?module=style-themes&action=edit&tid={$theme['tid']}"); + } + } + + $properties = my_unserialize($theme['properties']); + $page->add_breadcrumb_item(htmlspecialchars_uni($theme['name']), "index.php?module=style-themes&action=edit&tid={$mybb->input['tid']}"); + $page->add_breadcrumb_item(htmlspecialchars_uni($stylesheet['name'])." {$lang->properties}", "index.php?module=style-themes&action=edit_properties&tid={$mybb->input['tid']}"); + + $page->output_header("{$lang->themes} - {$lang->stylesheet_properties}"); + + // If the stylesheet and theme do not match, we must be editing something that is inherited + if($this_stylesheet['inherited'][$stylesheet['name']]) + { + $query = $db->simple_select("themes", "name", "tid='{$stylesheet['tid']}'"); + $stylesheet_parent = htmlspecialchars_uni($db->fetch_field($query, 'name')); + + // Show inherited warning + if($stylesheet['tid'] == 1) + { + $page->output_alert($lang->sprintf($lang->stylesheet_inherited_default, $stylesheet_parent)); + } + else + { + $page->output_alert($lang->sprintf($lang->stylesheet_inherited, $stylesheet_parent)); + } + } + + $applied_to = $this_stylesheet['applied_to']; + unset($this_stylesheet); + + if($errors) + { + $page->output_inline_error($errors); + + foreach($mybb->input as $name => $value) + { + if(strpos($name, "attached") !== false) + { + list(, $id) = explode('_', $name); + $id = (int)$id; + + $applied_to[$value] = array(0 => 'global'); + + if($mybb->input['action_'.$id] == 1) + { + $applied_to[$value] = explode(',', $mybb->input['action_list_'.$id]); + } + } + } + } + else + { + $mybb->input['name'] = $stylesheet['name']; + } + + $global_checked[1] = "checked=\"checked\""; + $global_checked[2] = ""; + $global_checked[3] = ""; + + $form = new Form("index.php?module=style-themes&action=stylesheet_properties", "post"); + + $specific_files = "
"; + $count = 0; + if(is_array($applied_to) && $applied_to['global'][0] != "global") + { + $check_actions = ""; + $stylesheet['colors'] = array(); + + if(!is_array($properties['colors'])) + { + $properties['colors'] = array(); + } + + foreach($applied_to as $name => $actions) + { + // Verify this is a color for this theme + if(array_key_exists($name, $properties['colors'])) + { + $stylesheet['colors'][] = $name; + } + + if(count($stylesheet['colors'])) + { + // Colors override files and are handled below. + continue; + } + + // It's a file: + $action_list = ""; + if($actions[0] != "global") + { + $action_list = implode(',', $actions); + } + + if($actions[0] == "global") + { + $global_action_checked[1] = "checked=\"checked\""; + $global_action_checked[2] = ""; + } + else + { + $global_action_checked[2] = "checked=\"checked\""; + $global_action_checked[1] = ""; + } + + $specific_file = "
+
+
+
+ {$lang->specific_actions_desc} + + + + +
".$form->generate_text_box('action_list_'.$count, $action_list, array('id' => 'action_list_'.$count, 'style' => 'width: 190px;'))."
+
+
"; + + $form_container = new FormContainer(); + $form_container->output_row("", "", "style}/images/icons/cross.png\" alt=\"{$lang->delete}\" title=\"{$lang->delete}\" />{$lang->file}  ".$form->generate_text_box("attached_{$count}", $name, array('id' => "attached_{$count}", 'style' => 'width: 200px;')), "attached_{$count}"); + + $form_container->output_row("", "", $specific_file); + + $specific_files .= "
".$form_container->end(true)."
"; + + $check_actions .= "\n\tcheckAction('action_{$count}');"; + + ++$count; + } + + if($check_actions) + { + $global_checked[3] = ""; + $global_checked[2] = "checked=\"checked\""; + $global_checked[1] = ""; + } + + if(!empty($stylesheet['colors'])) + { + $global_checked[3] = "checked=\"checked\""; + $global_checked[2] = ""; + $global_checked[1] = ""; + } + } + + $specific_files .= "
"; + + // Colors + $specific_colors = $specific_colors_option = ''; + + if(is_array($properties['colors'])) + { + $specific_colors = "
"; + $specific_colors_option = '

'; + + $specific_color = " + {$lang->colors_add_edit_desc} +

+ ".$form->generate_select_box('color[]', $properties['colors'], $stylesheet['colors'], array('multiple' => true, 'size' => "5\" style=\"width: 200px;"))." + "; + + $form_container = new FormContainer(); + $form_container->output_row("", "", $specific_color); + $specific_colors .= $form_container->end(true)."
"; + } + + $actions = ' +
+

+

+ '.$specific_files.' + '.$specific_colors_option.' + '.$specific_colors.' +
+ '; + + echo $form->generate_hidden_field("file", htmlspecialchars_uni($stylesheet['name']))."
\n"; + echo $form->generate_hidden_field("tid", $theme['tid'])."
\n"; + + $form_container = new FormContainer("{$lang->edit_stylesheet_properties_for} ".htmlspecialchars_uni($stylesheet['name'])); + $form_container->output_row($lang->file_name, $lang->file_name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name', 'style' => 'width: 200px;')), 'name'); + + $form_container->output_row($lang->attached_to, $lang->attached_to_desc, $actions); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_stylesheet_properties); + + $form->output_submit_wrapper($buttons); + + echo << + +EOF; + + $form->end(); + + $page->output_footer(); +} + +// Shows the page where you can actually edit a particular selector or the whole stylesheet +if($mybb->input['action'] == "edit_stylesheet" && (!isset($mybb->input['mode']) || $mybb->input['mode'] == "simple")) +{ + // Fetch the theme we want to edit this stylesheet in + $query = $db->simple_select("themes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $theme = $db->fetch_array($query); + + if(!$theme['tid'] || $theme['tid'] == 1) + { + flash_message($lang->error_invalid_theme, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $plugins->run_hooks("admin_style_themes_edit_stylesheet_simple"); + + $parent_list = make_parent_theme_list($theme['tid']); + $parent_list = implode(',', $parent_list); + if(!$parent_list) + { + $parent_list = 1; + } + + $query = $db->simple_select("themestylesheets", "*", "name='".$db->escape_string($mybb->input['file'])."' AND tid IN ({$parent_list})", array('order_by' => 'tid', 'order_dir' => 'desc', 'limit' => 1)); + $stylesheet = $db->fetch_array($query); + + // Does the theme not exist? + if(!$stylesheet['sid']) + { + flash_message($lang->error_invalid_stylesheet, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + if($mybb->request_method == "post") + { + $sid = $stylesheet['sid']; + + // Theme & stylesheet theme ID do not match, editing inherited - we copy to local theme + if($theme['tid'] != $stylesheet['tid']) + { + $sid = copy_stylesheet_to_theme($stylesheet, $theme['tid']); + } + + // Insert the modified CSS + $new_stylesheet = $stylesheet['stylesheet']; + + if($mybb->input['serialized'] == 1) + { + $mybb->input['css_bits'] = my_unserialize($mybb->input['css_bits']); + } + + $css_to_insert = ''; + foreach($mybb->input['css_bits'] as $field => $value) + { + if(!trim($value) || !trim($field)) + { + continue; + } + + if($field == "extra") + { + $css_to_insert .= $value."\n"; + } + else + { + $field = str_replace("_", "-", $field); + $css_to_insert .= "{$field}: {$value};\n"; + } + } + + $new_stylesheet = insert_into_css($css_to_insert, $mybb->input['selector'], $new_stylesheet); + + // Now we have the new stylesheet, save it + $updated_stylesheet = array( + "cachefile" => $db->escape_string($stylesheet['name']), + "stylesheet" => $db->escape_string(unfix_css_urls($new_stylesheet)), + "lastmodified" => TIME_NOW + ); + $db->update_query("themestylesheets", $updated_stylesheet, "sid='{$sid}'"); + + // Cache the stylesheet to the file + if(!cache_stylesheet($theme['tid'], $stylesheet['name'], $new_stylesheet)) + { + $db->update_query("themestylesheets", array('cachefile' => "css.php?stylesheet={$sid}"), "sid='{$sid}'", 1); + } + + // Update the CSS file list for this theme + update_theme_stylesheet_list($theme['tid']); + + $plugins->run_hooks("admin_style_themes_edit_stylesheet_simple_commit"); + + // Log admin action + log_admin_action(htmlspecialchars_uni($theme['name']), $stylesheet['name']); + + if(!$mybb->input['ajax']) + { + flash_message($lang->success_stylesheet_updated, 'success'); + + if($mybb->input['save_close']) + { + admin_redirect("index.php?module=style-themes&action=edit&tid={$theme['tid']}"); + } + else + { + admin_redirect("index.php?module=style-themes&action=edit_stylesheet&tid={$theme['tid']}&file={$stylesheet['name']}"); + } + } + else + { + echo "1"; + exit; + } + } + + // Has the file on the file system been modified? + if(resync_stylesheet($stylesheet)) + { + // Need to refetch new stylesheet as it was modified + $query = $db->simple_select("themestylesheets", "stylesheet", "sid='{$stylesheet['sid']}'"); + $stylesheet['stylesheet'] = $db->fetch_field($query, 'stylesheet'); + } + + $css_array = css_to_array($stylesheet['stylesheet']); + $selector_list = get_selectors_as_options($css_array, $mybb->input['selector']); + + // Do we not have any selectors? Send em to the full edit page + if(!$selector_list) + { + flash_message($lang->error_cannot_parse, 'error'); + admin_redirect("index.php?module=style-themes&action=edit_stylesheet&tid={$theme['tid']}&file=".htmlspecialchars_uni($stylesheet['name'])."&mode=advanced"); + exit; + } + + // Fetch list of all of the stylesheets for this theme + $stylesheets = fetch_theme_stylesheets($theme); + $this_stylesheet = $stylesheets[$stylesheet['name']]; + unset($stylesheets); + + $page->extra_header .= " + "; + + $page->add_breadcrumb_item(htmlspecialchars_uni($theme['name']), "index.php?module=style-themes&action=edit&tid={$mybb->input['tid']}"); + $page->add_breadcrumb_item("{$lang->editing} ".htmlspecialchars_uni($stylesheet['name']), "index.php?module=style-themes&action=edit_stylesheet&tid={$mybb->input['tid']}&file=".htmlspecialchars_uni($mybb->input['file'])."&mode=simple"); + + $page->output_header("{$lang->themes} - {$lang->edit_stylesheets}"); + + // If the stylesheet and theme do not match, we must be editing something that is inherited + if($this_stylesheet['inherited'][$stylesheet['name']]) + { + $query = $db->simple_select("themes", "name", "tid='{$stylesheet['tid']}'"); + $stylesheet_parent = htmlspecialchars_uni($db->fetch_field($query, 'name')); + + // Show inherited warning + if($stylesheet['tid'] == 1) + { + $page->output_alert($lang->sprintf($lang->stylesheet_inherited_default, $stylesheet_parent), "ajax_alert"); + } + else + { + $page->output_alert($lang->sprintf($lang->stylesheet_inherited, $stylesheet_parent), "ajax_alert"); + } + } + + $sub_tabs['edit_stylesheet'] = array( + 'title' => $lang->edit_stylesheet_simple_mode, + 'link' => "index.php?module=style-themes&action=edit_stylesheet&tid={$mybb->input['tid']}&file=".htmlspecialchars_uni($mybb->input['file'])."&mode=simple", + 'description' => $lang->edit_stylesheet_simple_mode_desc + ); + + $sub_tabs['edit_stylesheet_advanced'] = array( + 'title' => $lang->edit_stylesheet_advanced_mode, + 'link' => "index.php?module=style-themes&action=edit_stylesheet&tid={$mybb->input['tid']}&file=".htmlspecialchars_uni($mybb->input['file'])."&mode=advanced", + ); + + $page->output_nav_tabs($sub_tabs, 'edit_stylesheet'); + + // Output the selection box + $form = new Form("index.php", "get", "selector_form"); + echo $form->generate_hidden_field("module", "style/themes")."\n"; + echo $form->generate_hidden_field("action", "edit_stylesheet")."\n"; + echo $form->generate_hidden_field("tid", $mybb->input['tid'])."\n"; + echo $form->generate_hidden_field("file", htmlspecialchars_uni($mybb->input['file']))."\n"; + + echo "{$lang->selector}: ".$form->generate_submit_button($lang->go)."

\n"; + + $form->end(); + + // Haven't chosen a selector to edit, show the first one from the stylesheet + if(!$mybb->input['selector']) + { + reset($css_array); + uasort($css_array, "css_selectors_sort_cmp"); + $selector = key($css_array); + $editable_selector = $css_array[$selector]; + } + // Show a specific selector + else + { + $editable_selector = $css_array[$mybb->input['selector']]; + $selector = $mybb->input['selector']; + } + + // Get the properties from this item + $properties = parse_css_properties($editable_selector['values']); + + foreach(array('background', 'color', 'width', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-decoration') as $_p) + { + if(!isset($properties[$_p])) + { + $properties[$_p] = ''; + } + } + + $form = new Form("index.php?module=style-themes&action=edit_stylesheet", "post"); + echo $form->generate_hidden_field("tid", $mybb->input['tid'], array('id' => "tid"))."\n"; + echo $form->generate_hidden_field("file", htmlspecialchars_uni($mybb->input['file']), array('id' => "file"))."\n"; + echo $form->generate_hidden_field("selector", htmlspecialchars_uni($selector), array('id' => 'hidden_selector'))."\n"; + + echo "
"; + $table = new Table; + $table->construct_cell("
".$form->generate_text_box('css_bits[background]', $properties['background'], array('id' => 'css_bits[background]', 'style' => 'width: 260px;'))."
{$lang->background}
", array('style' => 'width: 20%;')); + $table->construct_cell("{$lang->extra_css_atribs}
".$form->generate_text_area('css_bits[extra]', $properties['extra'], array('id' => 'css_bits[extra]', 'style' => 'width: 98%;', 'rows' => '19'))."
", array('rowspan' => 8)); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[color]', $properties['color'], array('id' => 'css_bits[color]', 'style' => 'width: 260px;'))."
{$lang->color}
", array('style' => 'width: 40%;')); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[width]', $properties['width'], array('id' => 'css_bits[width]', 'style' => 'width: 260px;'))."
{$lang->width}
", array('style' => 'width: 40%;')); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[font_family]', $properties['font-family'], array('id' => 'css_bits[font_family]', 'style' => 'width: 260px;'))."
{$lang->font_family}
", array('style' => 'width: 40%;')); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[font_size]', $properties['font-size'], array('id' => 'css_bits[font_size]', 'style' => 'width: 260px;'))."
{$lang->font_size}
", array('style' => 'width: 40%;')); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[font_style]', $properties['font-style'], array('id' => 'css_bits[font_style]', 'style' => 'width: 260px;'))."
{$lang->font_style}
", array('style' => 'width: 40%;')); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[font_weight]', $properties['font-weight'], array('id' => 'css_bits[font_weight]', 'style' => 'width: 260px;'))."
{$lang->font_weight}
", array('style' => 'width: 40%;')); + $table->construct_row(); + $table->construct_cell("
".$form->generate_text_box('css_bits[text_decoration]', $properties['text-decoration'], array('id' => 'css_bits[text_decoration]', 'style' => 'width: 260px;'))."
{$lang->text_decoration}
", array('style' => 'width: 40%;')); + $table->construct_row(); + + $table->output(htmlspecialchars_uni($editable_selector['class_name']).""); + + echo "
"; + + $buttons[] = $form->generate_reset_button($lang->reset); + $buttons[] = $form->generate_submit_button($lang->save_changes, array('id' => 'save', 'name' => 'save')); + $buttons[] = $form->generate_submit_button($lang->save_changes_and_close, array('id' => 'save_close', 'name' => 'save_close')); + + $form->output_submit_wrapper($buttons); + + echo ''; + echo ''; + + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit_stylesheet" && $mybb->input['mode'] == "advanced") +{ + // Fetch the theme we want to edit this stylesheet in + $query = $db->simple_select("themes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $theme = $db->fetch_array($query); + + if(!$theme['tid'] || $theme['tid'] == 1) + { + flash_message($lang->error_invalid_theme, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $plugins->run_hooks("admin_style_themes_edit_stylesheet_advanced"); + + $parent_list = make_parent_theme_list($theme['tid']); + $parent_list = implode(',', $parent_list); + if(!$parent_list) + { + $parent_list = 1; + } + + $query = $db->simple_select("themestylesheets", "*", "name='".$db->escape_string($mybb->input['file'])."' AND tid IN ({$parent_list})", array('order_by' => 'tid', 'order_dir' => 'desc', 'limit' => 1)); + $stylesheet = $db->fetch_array($query); + + // Does the theme not exist? + if(!$stylesheet['sid']) + { + flash_message($lang->error_invalid_stylesheet, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + if($mybb->request_method == "post") + { + $sid = $stylesheet['sid']; + + // Theme & stylesheet theme ID do not match, editing inherited - we copy to local theme + if($theme['tid'] != $stylesheet['tid']) + { + $sid = copy_stylesheet_to_theme($stylesheet, $theme['tid']); + } + + // Now we have the new stylesheet, save it + $updated_stylesheet = array( + "cachefile" => $db->escape_string($stylesheet['name']), + "stylesheet" => $db->escape_string(unfix_css_urls($mybb->input['stylesheet'])), + "lastmodified" => TIME_NOW + ); + $db->update_query("themestylesheets", $updated_stylesheet, "sid='{$sid}'"); + + // Cache the stylesheet to the file + if(!cache_stylesheet($theme['tid'], $stylesheet['name'], $mybb->input['stylesheet'])) + { + $db->update_query("themestylesheets", array('cachefile' => "css.php?stylesheet={$sid}"), "sid='{$sid}'", 1); + } + + // Update the CSS file list for this theme + update_theme_stylesheet_list($theme['tid']); + + $plugins->run_hooks("admin_style_themes_edit_stylesheet_advanced_commit"); + + // Log admin action + log_admin_action(htmlspecialchars_uni($theme['name']), $stylesheet['name']); + + flash_message($lang->success_stylesheet_updated, 'success'); + + if(!$mybb->input['save_close']) + { + admin_redirect("index.php?module=style-themes&action=edit_stylesheet&file=".htmlspecialchars_uni($stylesheet['name'])."&tid={$theme['tid']}&mode=advanced"); + } + else + { + admin_redirect("index.php?module=style-themes&action=edit&tid={$theme['tid']}"); + } + } + + // Fetch list of all of the stylesheets for this theme + $stylesheets = fetch_theme_stylesheets($theme); + $this_stylesheet = $stylesheets[$stylesheet['name']]; + unset($stylesheets); + + if($admin_options['codepress'] != 0) + { + $page->extra_header .= ' + + + + + + + + +'; + } + + $page->add_breadcrumb_item(htmlspecialchars_uni($theme['name']), "index.php?module=style-themes&action=edit&tid={$mybb->input['tid']}"); + $page->add_breadcrumb_item("{$lang->editing} ".htmlspecialchars_uni($stylesheet['name']), "index.php?module=style-themes&action=edit_stylesheet&tid={$mybb->input['tid']}&file=".htmlspecialchars_uni($mybb->input['file'])."&mode=advanced"); + + $page->output_header("{$lang->themes} - {$lang->edit_stylesheet_advanced_mode}"); + + // If the stylesheet and theme do not match, we must be editing something that is inherited + if($this_stylesheet['inherited'][$stylesheet['name']]) + { + $query = $db->simple_select("themes", "name", "tid='{$stylesheet['tid']}'"); + $stylesheet_parent = htmlspecialchars_uni($db->fetch_field($query, 'name')); + + // Show inherited warning + if($stylesheet['tid'] == 1) + { + $page->output_alert($lang->sprintf($lang->stylesheet_inherited_default, $stylesheet_parent)); + } + else + { + $page->output_alert($lang->sprintf($lang->stylesheet_inherited, $stylesheet_parent)); + } + } + + $sub_tabs['edit_stylesheet'] = array( + 'title' => $lang->edit_stylesheet_simple_mode, + 'link' => "index.php?module=style-themes&action=edit_stylesheet&tid={$mybb->input['tid']}&file=".htmlspecialchars_uni($mybb->input['file'])."&mode=simple" + ); + + $sub_tabs['edit_stylesheet_advanced'] = array( + 'title' => $lang->edit_stylesheet_advanced_mode, + 'link' => "index.php?module=style-themes&action=edit_stylesheet&tid={$mybb->input['tid']}&file=".htmlspecialchars_uni($mybb->input['file'])."&mode=advanced", + 'description' => $lang->edit_stylesheet_advanced_mode_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_stylesheet_advanced'); + + // Has the file on the file system been modified? + if(resync_stylesheet($stylesheet)) + { + // Need to refetch new stylesheet as it was modified + $query = $db->simple_select("themestylesheets", "stylesheet", "sid='{$stylesheet['sid']}'"); + $stylesheet['stylesheet'] = $db->fetch_field($query, 'stylesheet'); + } + + $form = new Form("index.php?module=style-themes&action=edit_stylesheet&mode=advanced", "post", "edit_stylesheet"); + echo $form->generate_hidden_field("tid", $mybb->input['tid'])."\n"; + echo $form->generate_hidden_field("file", htmlspecialchars_uni($mybb->input['file']))."\n"; + + $table = new Table; + $table->construct_cell($form->generate_text_area('stylesheet', $stylesheet['stylesheet'], array('id' => 'stylesheet', 'style' => 'width: 99%;', 'class' => '', 'rows' => '30'))); + $table->construct_row(); + $table->output("{$lang->full_stylesheet_for} ".htmlspecialchars_uni($stylesheet['name'])); + + $buttons[] = $form->generate_submit_button($lang->save_changes, array('id' => 'save', 'name' => 'save')); + $buttons[] = $form->generate_submit_button($lang->save_changes_and_close, array('id' => 'save_close', 'name' => 'save_close')); + + $form->output_submit_wrapper($buttons); + + $form->end(); + + if($admin_options['codepress'] != 0) + { + echo ""; + } + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete_stylesheet") +{ + // Fetch the theme we want to edit this stylesheet in + $query = $db->simple_select("themes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $theme = $db->fetch_array($query); + + if(!$theme['tid'] || $theme['tid'] == 1) + { + flash_message($lang->error_invalid_theme, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $plugins->run_hooks("admin_style_themes_delete_stylesheet"); + + $parent_list = make_parent_theme_list($theme['tid']); + $parent_list = implode(',', $parent_list); + if(!$parent_list) + { + $parent_list = 1; + } + + $query = $db->simple_select("themestylesheets", "*", "name='".$db->escape_string($mybb->input['file'])."' AND tid IN ({$parent_list})", array('order_by' => 'tid', 'order_dir' => 'desc', 'limit' => 1)); + $stylesheet = $db->fetch_array($query); + + // Does the theme not exist? or are we trying to delete the master? + if(!$stylesheet['sid'] || $stylesheet['tid'] == 1) + { + flash_message($lang->error_invalid_stylesheet, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=style-themes"); + } + + if($mybb->request_method == "post") + { + $db->delete_query("themestylesheets", "sid='{$stylesheet['sid']}'", 1); + @unlink(MYBB_ROOT."cache/themes/theme{$theme['tid']}/{$stylesheet['cachefile']}"); + + // Update the CSS file list for this theme + update_theme_stylesheet_list($theme['tid'], $theme, true); + + $plugins->run_hooks("admin_style_themes_delete_stylesheet_commit"); + + // Log admin action + log_admin_action($stylesheet['sid'], $stylesheet['name'], $theme['tid'], htmlspecialchars_uni($theme['name'])); + + flash_message($lang->success_stylesheet_deleted, 'success'); + admin_redirect("index.php?module=style-themes&action=edit&tid={$theme['tid']}"); + } + else + { + $page->output_confirm_action("index.php?module=style-themes&action=force&tid={$theme['tid']}", $lang->confirm_stylesheet_deletion); + } +} + +if($mybb->input['action'] == "add_stylesheet") +{ + // Fetch the theme we want to edit this stylesheet in + $query = $db->simple_select("themes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $theme = $db->fetch_array($query); + + if(!$theme['tid'] || $theme['tid'] == 1) + { + flash_message($lang->error_invalid_theme, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $plugins->run_hooks("admin_style_themes_add_stylesheet"); + + // Fetch list of all of the stylesheets for this theme + $stylesheets = fetch_theme_stylesheets($theme); + + if($mybb->request_method == "post") + { + // Remove special characters + $mybb->input['name'] = preg_replace('#([^a-z0-9-_\.]+)#i', '', $mybb->input['name']); + if(!$mybb->input['name'] || $mybb->input['name'] == ".css") + { + $errors[] = $lang->error_missing_stylesheet_name; + } + + // Get 30 chars only because we don't want more than that + $mybb->input['name'] = my_substr($mybb->input['name'], 0, 30); + if(get_extension($mybb->input['name']) != "css") + { + // Does not end with '.css' + $errors[] = $lang->sprintf($lang->error_missing_stylesheet_extension, $mybb->input['name']); + } + + if(!$errors) + { + if($mybb->input['add_type'] == 1) + { + // Import from a current stylesheet + $parent_list = make_parent_theme_list($theme['tid']); + $parent_list = implode(',', $parent_list); + + $query = $db->simple_select("themestylesheets", "stylesheet", "name='".$db->escape_string($mybb->input['import'])."' AND tid IN ({$parent_list})", array('limit' => 1, 'order_by' => 'tid', 'order_dir' => 'desc')); + $stylesheet = $db->fetch_field($query, "stylesheet"); + } + else + { + // Custom stylesheet + $stylesheet = $mybb->input['stylesheet']; + } + + $attached = array(); + + if($mybb->input['attach'] == 1) + { + // Our stylesheet is attached to custom pages in MyBB + foreach($mybb->input as $id => $value) + { + $actions_list = ""; + $attached_to = ""; + + if(strpos($id, 'attached_') !== false) + { + // We have a custom attached file + $attached_id = (int)str_replace('attached_', '', $id); + $attached_to = $value; + + if($mybb->input['action_'.$attached_id] == 1) + { + // We have custom actions for attached files + $actions_list = $mybb->input['action_list_'.$attached_id]; + } + + if($actions_list) + { + $attached_to = $attached_to."?".$actions_list; + } + + $attached[] = $attached_to; + } + } + } + else if($mybb->input['attach'] == 2) + { + if(!is_array($mybb->input['color'])) + { + $errors[] = $lang->error_no_color_picked; + } + else + { + $attached = $mybb->input['color']; + } + } + + // Add Stylesheet + $insert_array = array( + 'name' => $db->escape_string($mybb->input['name']), + 'tid' => $mybb->get_input('tid', 1), + 'attachedto' => implode('|', array_map(array($db, "escape_string"), $attached)), + 'stylesheet' => $db->escape_string($stylesheet), + 'cachefile' => $db->escape_string(str_replace('/', '', $mybb->input['name'])), + 'lastmodified' => TIME_NOW + ); + + $sid = $db->insert_query("themestylesheets", $insert_array); + + if(!cache_stylesheet($theme['tid'], str_replace('/', '', $mybb->input['name']), $stylesheet)) + { + $db->update_query("themestylesheets", array('cachefile' => "css.php?stylesheet={$sid}"), "sid='{$sid}'", 1); + } + + // Update the CSS file list for this theme + update_theme_stylesheet_list($theme['tid'], $theme, true); + + $plugins->run_hooks("admin_style_themes_add_stylesheet_commit"); + + // Log admin action + log_admin_action($sid, $mybb->input['name'], $theme['tid'], htmlspecialchars_uni($theme['name'])); + + flash_message($lang->success_stylesheet_added, 'success'); + admin_redirect("index.php?module=style-themes&action=edit_stylesheet&tid={$mybb->input['tid']}&sid={$sid}&file=".urlencode($mybb->input['name'])); + } + } + + if($admin_options['codepress'] != 0) + { + $page->extra_header .= ' + + + + + + + + +'; + } + + $page->add_breadcrumb_item(htmlspecialchars_uni($theme['name']), "index.php?module=style-themes&action=edit&tid={$mybb->input['tid']}"); + $page->add_breadcrumb_item($lang->add_stylesheet); + $properties = my_unserialize($theme['properties']); + + $page->output_header("{$lang->themes} - {$lang->add_stylesheet}"); + + $sub_tabs['edit_stylesheets'] = array( + 'title' => $lang->edit_stylesheets, + 'link' => "index.php?module=style-themes&action=edit&tid={$mybb->input['tid']}" + ); + + $sub_tabs['add_stylesheet'] = array( + 'title' => $lang->add_stylesheet, + 'link' => "index.php?module=style-themes&action=add_stylesheet&tid={$mybb->input['tid']}", + 'description' => $lang->add_stylesheet_desc + ); + + $sub_tabs['export_theme'] = array( + 'title' => $lang->export_theme, + 'link' => "index.php?module=style-themes&action=export&tid={$mybb->input['tid']}" + ); + + $sub_tabs['duplicate_theme'] = array( + 'title' => $lang->duplicate_theme, + 'link' => "index.php?module=style-themes&action=duplicate&tid={$mybb->input['tid']}", + 'description' => $lang->duplicate_theme_desc + ); + + $page->output_nav_tabs($sub_tabs, 'add_stylesheet'); + + if($errors) + { + $page->output_inline_error($errors); + + foreach($mybb->input as $name => $value) + { + if(strpos($name, "attached") !== false) + { + list(, $id) = explode('_', $name); + $id = (int)$id; + + $mybb->input['applied_to'][$value] = array(0 => 'global'); + + if($mybb->input['action_'.$id] == 1) + { + $mybb->input['applied_to'][$value] = explode(',', $mybb->input['action_list_'.$id]); + } + } + } + + if($mybb->input['add_type'] == 1) + { + $add_checked[1] = "checked=\"checked\""; + $add_checked[2] = ""; + } + else + { + $add_checked[2] = "checked=\"checked\""; + $add_checked[1] = ""; + } + } + else + { + $mybb->input['name'] = $stylesheet['name']; + } + + $global_checked[1] = "checked=\"checked\""; + $global_checked[2] = ""; + $global_checked[3] = ""; + + $form = new Form("index.php?module=style-themes&action=add_stylesheet", "post", "add_stylesheet"); + + echo $form->generate_hidden_field("tid", $mybb->input['tid'])."\n"; + + $specific_files = "
"; + $count = 0; + + if($mybb->input['attach'] == 1 && is_array($mybb->input['applied_to']) && (!isset($mybb->input['applied_to']['global']) || $mybb->input['applied_to']['global'][0] != "global")) + { + $check_actions = ""; + + foreach($mybb->input['applied_to'] as $name => $actions) + { + $action_list = ""; + if($actions[0] != "global") + { + $action_list = implode(',', $actions); + } + + if($actions[0] == "global") + { + $global_action_checked[1] = "checked=\"checked\""; + $global_action_checked[2] = ""; + } + else + { + $global_action_checked[2] = "checked=\"checked\""; + $global_action_checked[1] = ""; + } + + $specific_file = "
+
+
+
+ {$lang->specific_actions_desc} + + + + +
".$form->generate_text_box('action_list_'.$count, $action_list, array('id' => 'action_list_'.$count, 'style' => 'width: 190px;'))."
+
+
"; + + $form_container = new FormContainer(); + $form_container->output_row("", "", "style}/images/icons/cross.png\" alt=\"{$lang->delete}\" title=\"{$lang->delete}\" />{$lang->file}  ".$form->generate_text_box("attached_{$count}", $name, array('id' => "attached_{$count}", 'style' => 'width: 200px;')), "attached_{$count}"); + + $form_container->output_row("", "", $specific_file); + + $specific_files .= "
".$form_container->end(true)."
"; + + $check_actions .= "\n\tcheckAction('action_{$count}');"; + + ++$count; + } + + if($check_actions) + { + $global_checked[3] = ""; + $global_checked[2] = "checked=\"checked\""; + $global_checked[1] = ""; + } + } + else if($mybb->input['attach'] == 2) + { + // Colors + $stylesheet['colors'] = array(); + if(is_array($properties['colors'])) + { + // We might have colors here... + foreach($mybb->input['color'] as $color) + { + // Verify this is a color for this theme + if(array_key_exists($color, $properties['colors'])) + { + $stylesheet['colors'][] = $color; + } + } + + if(!empty($stylesheet['colors'])) + { + $global_checked[3] = "checked=\"checked\""; + $global_checked[2] = ""; + $global_checked[1] = ""; + } + } + } + + $specific_files .= "
"; + + // Colors + $specific_colors = $specific_colors_option = ''; + + if(is_array($properties['colors'])) + { + $specific_colors = "
"; + $specific_colors_option = '
'; + + $specific_color = " + {$lang->colors_add_edit_desc} +

+ ".$form->generate_select_box('color[]', $properties['colors'], $stylesheet['colors'], array('multiple' => true, 'size' => "5\" style=\"width: 200px;"))." + "; + + $form_container = new FormContainer(); + $form_container->output_row("", "", $specific_color); + $specific_colors .= $form_container->end(true)."
"; + } + + $actions = ' +
+

+

+ '.$specific_files.' + '.$specific_colors_option.' + '.$specific_colors.' +
+ '; + + echo $form->generate_hidden_field("sid", $stylesheet['sid'])."
\n"; + + $form_container = new FormContainer("{$lang->add_stylesheet_to} ".htmlspecialchars_uni($theme['name'])); + $form_container->output_row($lang->file_name, $lang->file_name_desc, $form->generate_text_box('name', $mybb->input['name'], array('id' => 'name', 'style' => 'width: 200px;')), 'name'); + + $form_container->output_row($lang->attached_to, $lang->attached_to_desc, $actions); + + $sheetnames = array(); + foreach($stylesheets as $filename => $style) + { + $sheetnames[basename($filename)] = basename($filename); + } + + $actions = "
+
+
+ + + + +
".$form->generate_select_box('import', $sheetnames, $mybb->input['import'], array('id' => 'import'))."
+
+
+
".$form->generate_text_area('stylesheet', $mybb->input['stylesheet'], array('id' => 'stylesheet', 'style' => 'width: 99%;', 'class' => '', 'rows' => '30'))."
+
"; + + $form_container->output_row("", "", $actions); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_stylesheet); + + $form->output_submit_wrapper($buttons); + + if($admin_options['codepress'] != 0) + { + echo ""; + } + + echo ''; + echo ''; + echo ''; + + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "set_default") +{ + if(!verify_post_check($mybb->input['my_post_key'])) + { + flash_message($lang->invalid_post_verify_key2, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $query = $db->simple_select("themes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $theme = $db->fetch_array($query); + + // Does the theme not exist? + if(!$theme['tid'] || $theme['tid'] == 1) + { + flash_message($lang->error_invalid_theme, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $plugins->run_hooks("admin_style_themes_set_default"); + + $cache->update('default_theme', $theme); + + $db->update_query("themes", array('def' => 0)); + $db->update_query("themes", array('def' => 1), "tid='".$mybb->get_input('tid', 1)."'"); + + $plugins->run_hooks("admin_style_themes_set_default_commit"); + + // Log admin action + log_admin_action($theme['tid'], htmlspecialchars_uni($theme['name'])); + + flash_message($lang->success_theme_set_default, 'success'); + admin_redirect("index.php?module=style-themes"); +} + +if($mybb->input['action'] == "force") +{ + $query = $db->simple_select("themes", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $theme = $db->fetch_array($query); + + // Does the theme not exist? + if(!$theme['tid'] || $theme['tid'] == 1) + { + flash_message($lang->error_invalid_theme, 'error'); + admin_redirect("index.php?module=style-themes"); + } + + $plugins->run_hooks("admin_style_themes_force"); + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=style-themes"); + } + + if($mybb->request_method == "post") + { + $updated_users = array( + "style" => $theme['tid'] + ); + + $plugins->run_hooks("admin_style_themes_force_commit"); + + $db->update_query("users", $updated_users); + + // Log admin action + log_admin_action($theme['tid'], htmlspecialchars_uni($theme['name'])); + + flash_message($lang->success_theme_forced, 'success'); + admin_redirect("index.php?module=style-themes"); + } + else + { + $page->output_confirm_action("index.php?module=style-themes&action=force&tid={$theme['tid']}", $lang->confirm_theme_forced); + } +} + +if(!$mybb->input['action']) +{ + $page->output_header($lang->themes); + + $plugins->run_hooks("admin_style_themes_start"); + + $page->output_nav_tabs($sub_tabs, 'themes'); + + $table = new Table; + $table->construct_header($lang->theme); + $table->construct_header($lang->num_users, array("class" => "align_center", "width" => 100)); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 150)); + + build_theme_list(); + + $table->output($lang->themes); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/tools/adminlog.php b/Upload/admin/modules/tools/adminlog.php new file mode 100644 index 0000000..a9ab105 --- /dev/null +++ b/Upload/admin/modules/tools/adminlog.php @@ -0,0 +1,580 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->admin_logs, "index.php?module=tools-adminlog"); + +$sub_tabs['admin_logs'] = array( + 'title' => $lang->admin_logs, + 'link' => "index.php?module=tools-adminlog", + 'description' => $lang->admin_logs_desc +); +$sub_tabs['prune_admin_logs'] = array( + 'title' => $lang->prune_admin_logs, + 'link' => "index.php?module=tools-adminlog&action=prune", + 'description' => $lang->prune_admin_logs_desc +); + +$plugins->run_hooks("admin_tools_adminlog_begin"); + +if($mybb->input['action'] == 'prune') +{ + if(!is_super_admin($mybb->user['uid'])) + { + flash_message($lang->cannot_perform_action_super_admin_general, 'error'); + admin_redirect("index.php?module=tools-adminlog"); + } + + $plugins->run_hooks("admin_tools_adminlog_prune"); + + if($mybb->request_method == 'post') + { + $is_today = false; + if($mybb->input['older_than'] <= 0) + { + $is_today = true; + $mybb->input['older_than'] = 1; + } + $where = 'dateline < '.(TIME_NOW-((int)$mybb->input['older_than']*86400)); + + // Searching for entries by a particular user + if($mybb->input['uid']) + { + $where .= " AND uid='".$mybb->get_input('uid', 1)."'"; + } + + // Searching for entries in a specific module + if($mybb->input['filter_module']) + { + $where .= " AND module='".$db->escape_string($mybb->input['filter_module'])."'"; + } + + $query = $db->delete_query("adminlog", $where); + $num_deleted = $db->affected_rows(); + + $plugins->run_hooks("admin_tools_adminlog_prune_commit"); + + // Log admin action + log_admin_action($mybb->input['older_than'], $mybb->input['uid'], $mybb->input['filter_module'], $num_deleted); + + $success = $lang->success_pruned_admin_logs; + if($is_today == true && $num_deleted > 0) + { + $success .= ' '.$lang->note_logs_locked; + } + elseif($is_today == true && $num_deleted == 0) + { + flash_message($lang->note_logs_locked, 'error'); + admin_redirect("index.php?module=tools-adminlog"); + } + flash_message($success, 'success'); + admin_redirect("index.php?module=tools-adminlog"); + } + $page->add_breadcrumb_item($lang->prune_admin_logs, "index.php?module=tools-adminlog&action=prune"); + $page->output_header($lang->prune_admin_logs); + $page->output_nav_tabs($sub_tabs, 'prune_admin_logs'); + + // Fetch filter options + $sortbysel[$mybb->input['sortby']] = 'selected="selected"'; + $ordersel[$mybb->input['order']] = 'selected="selected"'; + + $user_options[''] = $lang->all_administrators; + $user_options['0'] = '----------'; + + $query = $db->query(" + SELECT DISTINCT l.uid, u.username + FROM ".TABLE_PREFIX."adminlog l + LEFT JOIN ".TABLE_PREFIX."users u ON (l.uid=u.uid) + ORDER BY u.username ASC + "); + while($user = $db->fetch_array($query)) + { + $user_options[$user['uid']] = $user['username']; + } + + $module_options = array(); + $module_options[''] = $lang->all_modules; + $module_options['0'] = '----------'; + $query = $db->query(" + SELECT DISTINCT l.module + FROM ".TABLE_PREFIX."adminlog l + ORDER BY l.module ASC + "); + while($module = $db->fetch_array($query)) + { + $module_options[$module['module']] = str_replace(' ', ' -> ', ucwords(str_replace('/', ' ', $module['module']))); + } + + $form = new Form("index.php?module=tools-adminlog&action=prune", "post"); + $form_container = new FormContainer($lang->prune_administrator_logs); + $form_container->output_row($lang->module, "", $form->generate_select_box('filter_module', $module_options, $mybb->input['filter_module'], array('id' => 'filter_module')), 'filter_module'); + $form_container->output_row($lang->administrator, "", $form->generate_select_box('uid', $user_options, $mybb->input['uid'], array('id' => 'uid')), 'uid'); + if(!$mybb->input['older_than']) + { + $mybb->input['older_than'] = '30'; + } + $form_container->output_row($lang->date_range, "", $lang->older_than.$form->generate_numeric_field('older_than', $mybb->input['older_than'], array('id' => 'older_than', 'style' => 'width: 30px'))." {$lang->days}", 'older_than'); + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->prune_administrator_logs); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $page->output_header($lang->admin_logs); + $page->output_nav_tabs($sub_tabs, 'admin_logs'); + + $perpage = $mybb->get_input('perpage', 1); + if(!$perpage) + { + if(!$mybb->settings['threadsperpage'] || (int)$mybb->settings['threadsperpage'] < 1) + { + $mybb->settings['threadsperpage'] = 20; + } + + $perpage = $mybb->settings['threadsperpage']; + } + + $where = ''; + + $plugins->run_hooks("admin_tools_adminlog_start"); + + // Searching for entries by a particular user + if($mybb->input['uid']) + { + $where .= " AND l.uid='".$mybb->get_input('uid', 1)."'"; + } + + // Searching for entries in a specific module + if($mybb->input['filter_module']) + { + $where .= " AND module='".$db->escape_string($mybb->input['filter_module'])."'"; + } + + // Order? + switch($mybb->input['sortby']) + { + case "username": + $sortby = "u.username"; + break; + default: + $sortby = "l.dateline"; + } + $order = $mybb->input['order']; + if($order != 'asc') + { + $order = 'desc'; + } + + $query = $db->query(" + SELECT COUNT(l.dateline) AS count + FROM ".TABLE_PREFIX."adminlog l + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=l.uid) + WHERE 1=1 {$where} + "); + $rescount = $db->fetch_field($query, "count"); + + // Figure out if we need to display multiple pages. + if($mybb->input['page'] != "last") + { + $pagecnt = $mybb->get_input('page', 1); + } + + $postcount = (int)$rescount; + $pages = $postcount / $perpage; + $pages = ceil($pages); + + if($mybb->input['page'] == "last") + { + $pagecnt = $pages; + } + + if($pagecnt > $pages) + { + $pagecnt = 1; + } + + if($pagecnt) + { + $start = ($pagecnt-1) * $perpage; + } + else + { + $start = 0; + $pagecnt = 1; + } + + $table = new Table; + $table->construct_header($lang->username, array('width' => '10%')); + $table->construct_header($lang->date, array('class' => 'align_center', 'width' => '15%')); + $table->construct_header($lang->information, array('class' => 'align_center', 'width' => '65%')); + $table->construct_header($lang->ipaddress, array('class' => 'align_center', 'width' => '10%')); + + $query = $db->query(" + SELECT l.*, u.username, u.usergroup, u.displaygroup + FROM ".TABLE_PREFIX."adminlog l + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=l.uid) + WHERE 1=1 {$where} + ORDER BY {$sortby} {$order} + LIMIT {$start}, {$perpage} + "); + while($logitem = $db->fetch_array($query)) + { + $information = ''; + $trow = alt_trow(); + $username = format_name($logitem['username'], $logitem['usergroup'], $logitem['displaygroup']); + + $logitem['data'] = my_unserialize($logitem['data']); + $logitem['profilelink'] = build_profile_link($username, $logitem['uid'], "_blank"); + $logitem['dateline'] = my_date('relative', $logitem['dateline']); + + // Get detailed information from meta + $information = get_admin_log_action($logitem); + + $table->construct_cell($logitem['profilelink']); + $table->construct_cell($logitem['dateline'], array('class' => 'align_center')); + $table->construct_cell($information); + $table->construct_cell(my_inet_ntop($db->unescape_binary($logitem['ipaddress'])), array('class' => 'align_center')); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_adminlogs, array('colspan' => '4')); + $table->construct_row(); + } + + $table->output($lang->admin_logs); + + // Do we need to construct the pagination? + if($rescount > $perpage) + { + echo draw_admin_pagination($pagecnt, $perpage, $rescount, "index.php?module=tools-adminlog&perpage=$perpage&uid={$mybb->input['uid']}&fid={$mybb->input['fid']}&sortby={$mybb->input['sortby']}&order={$order}&filter_module=".htmlspecialchars_uni($mybb->input['filter_module']))."
"; + } + + // Fetch filter options + $sortbysel[$mybb->input['sortby']] = 'selected="selected"'; + $ordersel[$mybb->input['order']] = 'selected="selected"'; + + $user_options[''] = $lang->all_administrators; + $user_options['0'] = '----------'; + + $query = $db->query(" + SELECT DISTINCT l.uid, u.username + FROM ".TABLE_PREFIX."adminlog l + LEFT JOIN ".TABLE_PREFIX."users u ON (l.uid=u.uid) + ORDER BY u.username ASC + "); + while($user = $db->fetch_array($query)) + { + $user_options[$user['uid']] = $user['username']; + } + + $module_options = array(); + $module_options[''] = $lang->all_modules; + $module_options['0'] = '----------'; + $query = $db->query(" + SELECT DISTINCT l.module + FROM ".TABLE_PREFIX."adminlog l + ORDER BY l.module ASC + "); + while($module = $db->fetch_array($query)) + { + $module_options[$module['module']] = str_replace(' ', ' -> ', ucwords(str_replace('/', ' ', $module['module']))); + } + + $sort_by = array( + 'dateline' => $lang->date, + 'username' => $lang->username + ); + + $order_array = array( + 'asc' => $lang->asc, + 'desc' => $lang->desc + ); + + $form = new Form("index.php?module=tools-adminlog", "post"); + $form_container = new FormContainer($lang->filter_administrator_logs); + $form_container->output_row($lang->module, "", $form->generate_select_box('filter_module', $module_options, $mybb->input['filter_module'], array('id' => 'filter_module')), 'filter_module'); + $form_container->output_row($lang->administrator, "", $form->generate_select_box('uid', $user_options, $mybb->input['uid'], array('id' => 'uid')), 'uid'); + $form_container->output_row($lang->sort_by, "", $form->generate_select_box('sortby', $sort_by, $mybb->input['sortby'], array('id' => 'sortby'))." {$lang->in} ".$form->generate_select_box('order', $order_array, $order, array('id' => 'order'))." {$lang->order}", 'order'); + $form_container->output_row($lang->results_per_page, "", $form->generate_numeric_field('perpage', $perpage, array('id' => 'perpage')), 'perpage'); + + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->filter_administrator_logs); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +/** + * Returns language-friendly string describing $logitem + * @param array The log item (one row from mybb_adminlogs) + * @return string The description + */ +function get_admin_log_action($logitem) +{ + global $lang, $plugins, $mybb; + + $logitem['module'] = str_replace('/', '-', $logitem['module']); + list($module, $action) = explode('-', $logitem['module']); + $lang_string = 'admin_log_'.$module.'_'.$action.'_'.$logitem['action']; + + // Specific page overrides + switch($lang_string) + { + // == CONFIG == + case 'admin_log_config_banning_add': // Banning IP/Username/Email + case 'admin_log_config_banning_delete': // Removing banned IP/username/emails + switch($logitem['data'][2]) + { + case 1: + $lang_string = 'admin_log_config_banning_'.$logitem['action'].'_ip'; + break; + case 2: + $lang_string = 'admin_log_config_banning_'.$logitem['action'].'_username'; + break; + case 3: + $lang_string = 'admin_log_config_banning_'.$logitem['action'].'_email'; + break; + } + break; + + case 'admin_log_config_help_documents_add': // Help documents and sections + case 'admin_log_config_help_documents_edit': + case 'admin_log_config_help_documents_delete': + $lang_string .= "_{$logitem['data'][2]}"; // adds _section or _document + break; + + case 'admin_log_config_languages_edit': // Editing language variables + $logitem['data'][1] = basename($logitem['data'][1]); + if($logitem['data'][2] == 1) + { + $lang_string = 'admin_log_config_languages_edit_admin'; + } + break; + + case 'admin_log_config_mycode_toggle_status': // Custom MyCode toggle activation + if($logitem['data'][2] == 1) + { + $lang_string .= '_enabled'; + } + else + { + $lang_string .= '_disabled'; + } + break; + case 'admin_log_config_plugins_activate': // Installing plugin + if($logitem['data'][1]) + { + $lang_string .= '_install'; + } + break; + case 'admin_log_config_plugins_deactivate': // Uninstalling plugin + if($logitem['data'][1]) + { + $lang_string .= '_uninstall'; + } + break; + // == FORUM == + case 'admin_log_forum_attachments_delete': // Deleting attachments + if($logitem['data'][2]) + { + $lang_string .= '_post'; + } + break; + case 'admin_log_forum_management_copy': // Forum copy + if($logitem['data'][4]) + { + $lang_string .= '_with_permissions'; + } + break; + case 'admin_log_forum_management_': // add mod, permissions, forum orders + // first parameter already set with action + $lang_string .= $logitem['data'][0]; + if($logitem['data'][0] == 'orders' && $logitem['data'][1]) + { + $lang_string .= '_sub'; // updating forum orders in a subforum + } + break; + case 'admin_log_forum_moderation_queue_': //moderation queue + // first parameter already set with action + $lang_string .= $logitem['data'][0]; + break; + // == HOME == + // == STYLE == + case 'admin_log_style_templates_delete_template': // deleting templates + // global template set + if($logitem['data'][2] == -1) + { + $lang_string .= '_global'; + } + break; + case 'admin_log_style_templates_edit_template': // editing templates + // global template set + if($logitem['data'][2] == -1) + { + $lang_string .= '_global'; + } + break; + // == TOOLS == + case 'admin_log_tools_adminlog_prune': // Admin Log Pruning + if($logitem['data'][1] && !$logitem['data'][2]) + { + $lang_string = 'admin_log_tools_adminlog_prune_user'; + } + elseif($logitem['data'][2] && !$logitem['data'][1]) + { + $lang_string = 'admin_log_tools_adminlog_prune_module'; + } + elseif($logitem['data'][1] && $logitem['data'][2]) + { + $lang_string = 'admin_log_tools_adminlog_prune_user_module'; + } + break; + case 'admin_log_tools_modlog_prune': // Moderator Log Pruning + if($logitem['data'][1] && !$logitem['data'][2]) + { + $lang_string = 'admin_log_tools_modlog_prune_user'; + } + elseif($logitem['data'][2] && !$logitem['data'][1]) + { + $lang_string = 'admin_log_tools_modlog_prune_forum'; + } + elseif($logitem['data'][1] && $logitem['data'][2]) + { + $lang_string = 'admin_log_tools_modlog_prune_user_forum'; + } + break; + case 'admin_log_tools_backupdb_backup': // Create backup + if($logitem['data'][0] == 'download') + { + $lang_string = 'admin_log_tools_backupdb_backup_download'; + } + $logitem['data'][1] = '...'.substr($logitem['data'][1], -20); + break; + case 'admin_log_tools_backupdb_dlbackup': // Download backup + $logitem['data'][0] = '...'.substr($logitem['data'][0], -20); + break; + case 'admin_log_tools_backupdb_delete': // Delete backup + $logitem['data'][0] = '...'.substr($logitem['data'][0], -20); + break; + case 'admin_log_tools_optimizedb_': // Optimize DB + $logitem['data'][0] = @implode(', ', my_unserialize($logitem['data'][0])); + break; + case 'admin_log_tools_recount_rebuild_': // Recount and rebuild + $detail_lang_string = $lang_string.$logitem['data'][0]; + if(isset($lang->$detail_lang_string)) + { + $lang_string = $detail_lang_string; + } + break; + // == USERS == + case 'admin_log_user_admin_permissions_edit': // editing default/group/user admin permissions + if($logitem['data'][0] > 0) + { + // User + $lang_string .= '_user'; + } + elseif($logitem['data'][0] < 0) + { + // Group + $logitem['data'][0] = abs($logitem['data'][0]); + $lang_string .= '_group'; + } + break; + case 'admin_log_user_admin_permissions_delete': // deleting group/user admin permissions + if($logitem['data'][0] > 0) + { + // User + $lang_string .= '_user'; + } + elseif($logitem['data'][0] < 0) + { + // Group + $logitem['data'][0] = abs($logitem['data'][0]); + $lang_string .= '_group'; + } + break; + case 'admin_log_user_banning_': // banning + if($logitem['data'][2] == 0) + { + $lang_string = 'admin_log_user_banning_add_permanent'; + } + else + { + $logitem['data'][2] = my_date($mybb->settings['dateformat'], $logitem['data'][2]); + $lang_string = 'admin_log_user_banning_add_temporary'; + } + break; + case 'admin_log_user_groups_join_requests': + if($logitem['data'][0] == 'approve') + { + $lang_string = 'admin_log_user_groups_join_requests_approve'; + } + else + { + $lang_string = 'admin_log_user_groups_join_requests_deny'; + } + break; + case 'admin_log_user_users_inline_banned': + if($logitem['data'][1] == 0) + { + $lang_string = 'admin_log_user_users_inline_banned_perm'; + } + else + { + $logitem['data'][1] = my_date($mybb->settings['dateformat'], $logitem['data'][1]); + $lang_string = 'admin_log_user_users_inline_banned_temp'; + } + break; + } + + $plugin_array = array('logitem' => &$logitem, 'lang_string' => &$lang_string); + $plugins->run_hooks("admin_tools_get_admin_log_action", $plugin_array); + + if(isset($lang->$lang_string)) + { + array_unshift($logitem['data'], $lang->$lang_string); // First parameter for sprintf is the format string + $string = call_user_func_array(array($lang, 'sprintf'), $logitem['data']); + if(!$string) + { + $string = $lang->$lang_string; // Fall back to the one in the language pack + } + } + else + { + if(isset($logitem['data']['type']) && $logitem['data']['type'] == 'admin_locked_out') + { + $string = $lang->sprintf($lang->admin_log_admin_locked_out, (int) $logitem['data']['uid'], htmlspecialchars_uni($logitem['data']['username'])); + } + else + { + // Build a default string + $string = $logitem['module'].' - '.$logitem['action']; + if(is_array($logitem['data']) && count($logitem['data']) > 0) + { + $string .= '('.implode(', ', $logitem['data']).')'; + } + } + } + return $string; +} + + diff --git a/Upload/admin/modules/tools/backupdb.php b/Upload/admin/modules/tools/backupdb.php new file mode 100644 index 0000000..7a26524 --- /dev/null +++ b/Upload/admin/modules/tools/backupdb.php @@ -0,0 +1,473 @@ +
Please make sure IN_MYBB is defined."); +} + +// Allows us to refresh cache to prevent over flowing +function clear_overflow($fp, &$contents) +{ + global $mybb; + + if($mybb->input['method'] == 'disk') + { + if($mybb->input['filetype'] == 'gzip') + { + gzwrite($fp, $contents); + } + else + { + fwrite($fp, $contents); + } + } + else + { + if($mybb->input['filetype'] == "gzip") + { + echo gzencode($contents); + } + else + { + echo $contents; + } + } + + $contents = ''; +} + +$page->add_breadcrumb_item($lang->database_backups, "index.php?module=tools-backupdb"); + +$plugins->run_hooks("admin_tools_backupdb_begin"); + +if($mybb->input['action'] == "dlbackup") +{ + if(empty($mybb->input['file'])) + { + flash_message($lang->error_file_not_specified, 'error'); + admin_redirect("index.php?module=tools-backupdb"); + } + + $plugins->run_hooks("admin_tools_backupdb_dlbackup"); + + $file = basename($mybb->input['file']); + $ext = get_extension($file); + + if(file_exists(MYBB_ADMIN_DIR.'backups/'.$file) && filetype(MYBB_ADMIN_DIR.'backups/'.$file) == 'file' && ($ext == 'gz' || $ext == 'sql')) + { + $plugins->run_hooks("admin_tools_backupdb_dlbackup_commit"); + + // Log admin action + log_admin_action($file); + + header('Content-disposition: attachment; filename='.$file); + header("Content-type: ".$ext); + header("Content-length: ".filesize(MYBB_ADMIN_DIR.'backups/'.$file)); + echo file_get_contents(MYBB_ADMIN_DIR.'backups/'.$file); + } + else + { + flash_message($lang->error_invalid_backup, 'error'); + admin_redirect("index.php?module=tools-backupdb"); + } +} + +if($mybb->input['action'] == "delete") +{ + if($mybb->input['no']) + { + admin_redirect("index.php?module=tools-backupdb"); + } + + $file = basename($mybb->input['file']); + + if(!trim($mybb->input['file']) || !file_exists(MYBB_ADMIN_DIR.'backups/'.$file)) + { + flash_message($lang->error_backup_doesnt_exist, 'error'); + admin_redirect("index.php?module=tools-backupdb"); + } + + $plugins->run_hooks("admin_tools_backupdb_delete"); + + if($mybb->request_method == "post") + { + $delete = @unlink(MYBB_ADMIN_DIR.'backups/'.$file); + + if($delete) + { + $plugins->run_hooks("admin_tools_backupdb_delete_commit"); + + // Log admin action + log_admin_action($file); + + flash_message($lang->success_backup_deleted, 'success'); + admin_redirect("index.php?module=tools-backupdb"); + } + else + { + flash_message($lang->error_backup_not_deleted, 'error'); + admin_redirect("index.php?module=tools-backupdb"); + } + } + else + { + $page->output_confirm_action("index.php?module=tools-backupdb&action=delete&file={$mybb->input['file']}", $lang->confirm_backup_deletion); + } +} + +if($mybb->input['action'] == "backup") +{ + $plugins->run_hooks("admin_tools_backupdb_backup"); + + if($mybb->request_method == "post") + { + if(!is_array($mybb->input['tables'])) + { + flash_message($lang->error_tables_not_selected, 'error'); + admin_redirect("index.php?module=tools-backupdb&action=backup"); + } + + @set_time_limit(0); + + if($mybb->input['method'] == 'disk') + { + $file = MYBB_ADMIN_DIR.'backups/backup_'.date("_Ymd_His_").random_str(16); + + if($mybb->input['filetype'] == 'gzip') + { + if(!function_exists('gzopen')) // check zlib-ness + { + flash_message($lang->error_no_zlib, 'error'); + admin_redirect("index.php?module=tools-backupdb&action=backup"); + } + + $fp = gzopen($file.'.incomplete.sql.gz', 'w9'); + } + else + { + $fp = fopen($file.'.incomplete.sql', 'w'); + } + } + else + { + $file = 'backup_'.substr(md5($mybb->user['uid'].TIME_NOW), 0, 10).random_str(54); + if($mybb->input['filetype'] == 'gzip') + { + if(!function_exists('gzopen')) // check zlib-ness + { + flash_message($lang->error_no_zlib, 'error'); + admin_redirect("index.php?module=tools-backupdb&action=backup"); + } + + // Send headers for gzip file + header('Content-Encoding: gzip'); + header('Content-Type: application/x-gzip'); + header('Content-Disposition: attachment; filename="'.$file.'.sql.gz"'); + } + else + { + // Send standard headers for .sql + header('Content-Type: text/x-sql'); + header('Content-Disposition: attachment; filename="'.$file.'.sql"'); + } + } + $db->set_table_prefix(''); + + $time = date('dS F Y \a\t H:i', TIME_NOW); + $header = "-- MyBB Database Backup\n-- Generated: {$time}\n-- -------------------------------------\n\n"; + $contents = $header; + foreach($mybb->input['tables'] as $table) + { + if(!$db->table_exists($db->escape_string($table))) + { + continue; + } + if($mybb->input['analyzeoptimize'] == 1) + { + $db->optimize_table($table); + $db->analyze_table($table); + } + + $field_list = array(); + $fields_array = $db->show_fields_from($table); + foreach($fields_array as $field) + { + $field_list[] = $field['Field']; + } + + $fields = "`".implode("`,`", $field_list)."`"; + if($mybb->input['contents'] != 'data') + { + $structure = $db->show_create_table($table).";\n"; + $contents .= $structure; + clear_overflow($fp, $contents); + } + + if($mybb->input['contents'] != 'structure') + { + if($db->engine == 'mysqli') + { + $query = mysqli_query($db->read_link, "SELECT * FROM {$db->table_prefix}{$table}", MYSQLI_USE_RESULT); + } + else + { + $query = $db->simple_select($table); + } + + while($row = $db->fetch_array($query)) + { + $insert = "INSERT INTO {$table} ($fields) VALUES ("; + $comma = ''; + foreach($field_list as $field) + { + if(!isset($row[$field]) || is_null($row[$field])) + { + $insert .= $comma."NULL"; + } + else if($db->engine == 'mysqli') + { + $insert .= $comma."'".mysqli_real_escape_string($db->read_link, $row[$field])."'"; + } + else + { + $insert .= $comma."'".$db->escape_string($row[$field])."'"; + } + $comma = ','; + } + $insert .= ");\n"; + $contents .= $insert; + clear_overflow($fp, $contents); + } + $db->free_result($query); + } + } + + $db->set_table_prefix(TABLE_PREFIX); + + if($mybb->input['method'] == 'disk') + { + if($mybb->input['filetype'] == 'gzip') + { + gzwrite($fp, $contents); + gzclose($fp); + rename($file.'.incomplete.sql.gz', $file.'.sql.gz'); + } + else + { + fwrite($fp, $contents); + fclose($fp); + rename($file.'.incomplete.sql', $file.'.sql'); + } + + if($mybb->input['filetype'] == 'gzip') + { + $ext = '.sql.gz'; + } + else + { + $ext = '.sql'; + } + + $plugins->run_hooks("admin_tools_backupdb_backup_disk_commit"); + + // Log admin action + log_admin_action("disk", $file.$ext); + + $file_from_admindir = 'index.php?module=tools-backupdb&action=dlbackup&file='.basename($file).$ext; + flash_message("{$lang->success_backup_created}

{$lang->backup_saved_to}
{$file}{$ext} ({$lang->download})

", 'success'); + admin_redirect("index.php?module=tools-backupdb"); + } + else + { + $plugins->run_hooks("admin_tools_backupdb_backup_download_commit"); + + // Log admin action + log_admin_action("download"); + + if($mybb->input['filetype'] == 'gzip') + { + echo gzencode($contents); + } + else + { + echo $contents; + } + } + + exit; + } + + $page->extra_header = " \n"; + + $page->add_breadcrumb_item($lang->new_database_backup); + $page->output_header($lang->new_database_backup); + + $sub_tabs['database_backup'] = array( + 'title' => $lang->database_backups, + 'link' => "index.php?module=tools-backupdb" + ); + + $sub_tabs['new_backup'] = array( + 'title' => $lang->new_backup, + 'link' => "index.php?module=tools-backupdb&action=backup", + 'description' => $lang->new_backup_desc + ); + + $page->output_nav_tabs($sub_tabs, 'new_backup'); + + // Check if file is writable, before allowing submission + if(!is_writable(MYBB_ADMIN_DIR."/backups")) + { + $lang->update_button = ''; + $page->output_alert($lang->alert_not_writable); + $cannot_write = true; + } + + $table = new Table; + $table->construct_header($lang->table_selection); + $table->construct_header($lang->backup_options); + + $table_selects = array(); + $table_list = $db->list_tables($config['database']['database']); + foreach($table_list as $id => $table_name) + { + $table_selects[$table_name] = $table_name; + } + + $form = new Form("index.php?module=tools-backupdb&action=backup", "post", "table_selection", 0, "table_selection"); + + $table->construct_cell("{$lang->table_select_desc}\n

\n{$lang->select_all}
\n{$lang->deselect_all}
\n{$lang->select_forum_tables}\n

\n
".$form->generate_select_box("tables[]", $table_selects, false, array('multiple' => true, 'id' => 'table_select', 'size' => 20))."
", array('rowspan' => 5, 'width' => '50%', 'style' => 'border-bottom: 0px')); + $table->construct_row(); + + $table->construct_cell("{$lang->file_type}
\n{$lang->file_type_desc}
\n
".$form->generate_radio_button("filetype", "gzip", $lang->gzip_compressed, array('checked' => 1))."
\n".$form->generate_radio_button("filetype", "plain", $lang->plain_text)."
", array('width' => '50%')); + $table->construct_row(); + $table->construct_cell("{$lang->save_method}
\n{$lang->save_method_desc}
".$form->generate_radio_button("method", "disk", $lang->backup_directory)."
\n".$form->generate_radio_button("method", "download", $lang->download, array('checked' => 1))."
", array('width' => '50%')); + $table->construct_row(); + $table->construct_cell("{$lang->backup_contents}
\n{$lang->backup_contents_desc}
".$form->generate_radio_button("contents", "both", $lang->structure_and_data, array('checked' => 1))."
\n".$form->generate_radio_button("contents", "structure", $lang->structure_only)."
\n".$form->generate_radio_button("contents", "data", $lang->data_only)."
", array('width' => '50%')); + $table->construct_row(); + $table->construct_cell("{$lang->analyze_and_optimize}
\n{$lang->analyze_and_optimize_desc}
".$form->generate_yes_no_radio("analyzeoptimize")."
", array('width' => '50%')); + $table->construct_row(); + + $table->output($lang->new_database_backup); + + $buttons[] = $form->generate_submit_button($lang->perform_backup); + $form->output_submit_wrapper($buttons); + + $form->end(); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $page->add_breadcrumb_item($lang->backups); + $page->output_header($lang->database_backups); + + $sub_tabs['database_backup'] = array( + 'title' => $lang->database_backups, + 'link' => "index.php?module=tools-backupdb", + 'description' => $lang->database_backups_desc + ); + + $sub_tabs['new_backup'] = array( + 'title' => $lang->new_backup, + 'link' => "index.php?module=tools-backupdb&action=backup", + ); + + $plugins->run_hooks("admin_tools_backupdb_start"); + + $page->output_nav_tabs($sub_tabs, 'database_backup'); + + $backups = array(); + $dir = MYBB_ADMIN_DIR.'backups/'; + $handle = opendir($dir); + + if($handle !== false) + { + while(($file = readdir($handle)) !== false) + { + if(filetype(MYBB_ADMIN_DIR.'backups/'.$file) == 'file') + { + $ext = get_extension($file); + if($ext == 'gz' || $ext == 'sql') + { + $backups[@filemtime(MYBB_ADMIN_DIR.'backups/'.$file)] = array( + "file" => $file, + "time" => @filemtime(MYBB_ADMIN_DIR.'backups/'.$file), + "type" => $ext + ); + } + } + } + closedir($handle); + } + + $count = count($backups); + krsort($backups); + + $table = new Table; + $table->construct_header($lang->backup_filename); + $table->construct_header($lang->file_size, array("class" => "align_center")); + $table->construct_header($lang->creation_date); + $table->construct_header($lang->controls, array("class" => "align_center")); + + foreach($backups as $backup) + { + $time = "-"; + if($backup['time']) + { + $time = my_date('relative', $backup['time']); + } + + $table->construct_cell("{$backup['file']}"); + $table->construct_cell(get_friendly_size(filesize(MYBB_ADMIN_DIR.'backups/'.$backup['file'])), array("class" => "align_center")); + $table->construct_cell($time); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_backup_deletion}')\">{$lang->delete}", array("class" => "align_center")); + $table->construct_row(); + } + + if($count == 0) + { + $table->construct_cell($lang->no_backups, array('colspan' => 4)); + $table->construct_row(); + } + + $table->output($lang->existing_database_backups); + $page->output_footer(); +} diff --git a/Upload/admin/modules/tools/cache.php b/Upload/admin/modules/tools/cache.php new file mode 100644 index 0000000..8ce4264 --- /dev/null +++ b/Upload/admin/modules/tools/cache.php @@ -0,0 +1,276 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->cache_manager, "index.php?module=tools-cache"); + +$plugins->run_hooks("admin_tools_cache_begin"); + +if($mybb->input['action'] == 'view') +{ + if(!trim($mybb->input['title'])) + { + flash_message($lang->error_no_cache_specified, 'error'); + admin_redirect("index.php?module=tools-cache"); + } + + $plugins->run_hooks("admin_tools_cache_view"); + + // Rebuilds forum settings + if($mybb->input['title'] == 'settings') + { + $cachedsettings = (array)$mybb->settings; + if(isset($cachedsettings['internal'])) + { + unset($cachedsettings['internal']); + } + + $cacheitem = array( + 'title' => 'settings', + 'cache' => serialize($cachedsettings) + ); + } + else + { + $query = $db->simple_select("datacache", "*", "title = '".$db->escape_string($mybb->input['title'])."'"); + $cacheitem = $db->fetch_array($query); + } + + if(!$cacheitem) + { + flash_message($lang->error_incorrect_cache, 'error'); + admin_redirect("index.php?module=tools-cache"); + } + + $cachecontents = my_unserialize($cacheitem['cache']); + if(empty($cachecontents)) + { + $cachecontents = $lang->error_empty_cache; + } + ob_start(); + print_r($cachecontents); + $cachecontents = htmlspecialchars_uni(ob_get_contents()); + ob_end_clean(); + + $page->add_breadcrumb_item($lang->view); + $page->output_header($lang->cache_manager); + + $table = new Table; + + $table->construct_cell("
\n{$cachecontents}\n
"); + $table->construct_row(); + $table->output($lang->cache." {$cacheitem['title']}"); + + $page->output_footer(); + +} + +if($mybb->input['action'] == "rebuild" || $mybb->input['action'] == "reload") +{ + if(!verify_post_check($mybb->input['my_post_key'])) + { + flash_message($lang->invalid_post_verify_key2, 'error'); + admin_redirect("index.php?module=tools-cache"); + } + + $plugins->run_hooks("admin_tools_cache_rebuild"); + + // Rebuilds forum settings + if($mybb->input['title'] == 'settings') + { + rebuild_settings(); + + $plugins->run_hooks("admin_tools_cache_rebuild_commit"); + + // Log admin action + log_admin_action($mybb->input['title']); + + flash_message($lang->success_cache_reloaded, 'success'); + admin_redirect("index.php?module=tools-cache"); + } + + if(method_exists($cache, "update_{$mybb->input['title']}")) + { + $func = "update_{$mybb->input['title']}"; + $cache->$func(); + + $plugins->run_hooks("admin_tools_cache_rebuild_commit"); + + // Log admin action + log_admin_action($mybb->input['title']); + + flash_message($lang->success_cache_rebuilt, 'success'); + admin_redirect("index.php?module=tools-cache"); + } + elseif(method_exists($cache, "reload_{$mybb->input['title']}")) + { + $func = "reload_{$mybb->input['title']}"; + $cache->$func(); + + $plugins->run_hooks("admin_tools_cache_rebuild_commit"); + + // Log admin action + log_admin_action($mybb->input['title']); + + flash_message($lang->success_cache_reloaded, 'success'); + admin_redirect("index.php?module=tools-cache"); + } + elseif(function_exists("update_{$mybb->input['title']}")) + { + $func = "update_{$mybb->input['title']}"; + $func(); + + $plugins->run_hooks("admin_tools_cache_rebuild_commit"); + + // Log admin action + log_admin_action($mybb->input['title']); + + flash_message($lang->success_cache_rebuilt, 'success'); + admin_redirect("index.php?module=tools-cache"); + } + elseif(function_exists("reload_{$mybb->input['title']}")) + { + $func = "reload_{$mybb->input['title']}"; + $func(); + + $plugins->run_hooks("admin_tools_cache_rebuild_commit"); + + // Log admin action + log_admin_action($mybb->input['title']); + + flash_message($lang->success_cache_reloaded, 'success'); + admin_redirect("index.php?module=tools-cache"); + } + else + { + flash_message($lang->error_cannot_rebuild, 'error'); + admin_redirect("index.php?module=tools-cache"); + } +} + +if($mybb->input['action'] == "rebuild_all") +{ + if(!verify_post_check($mybb->input['my_post_key'])) + { + flash_message($lang->invalid_post_verify_key2, 'error'); + admin_redirect("index.php?module=tools-cache"); + } + + $plugins->run_hooks("admin_tools_cache_rebuild_all"); + + $query = $db->simple_select("datacache"); + while($cacheitem = $db->fetch_array($query)) + { + if(method_exists($cache, "update_{$cacheitem['title']}")) + { + $func = "update_{$cacheitem['title']}"; + $cache->$func(); + } + elseif(method_exists($cache, "reload_{$cacheitem['title']}")) + { + $func = "reload_{$cacheitem['title']}"; + $cache->$func(); + } + elseif(function_exists("update_{$cacheitem['title']}")) + { + $func = "update_{$cacheitem['title']}"; + $func(); + } + elseif(function_exists("reload_{$cacheitem['title']}")) + { + $func = "reload_{$cacheitem['title']}"; + $func(); + } + } + + // Rebuilds forum settings + rebuild_settings(); + + $plugins->run_hooks("admin_tools_cache_rebuild_all_commit"); + + // Log admin action + log_admin_action(); + + flash_message($lang->success_cache_reloaded, 'success'); + admin_redirect("index.php?module=tools-cache"); +} + +if(!$mybb->input['action']) +{ + $page->output_header($lang->cache_manager); + + $sub_tabs['cache_manager'] = array( + 'title' => $lang->cache_manager, + 'link' => "index.php?module=tools-cache", + 'description' => $lang->cache_manager_description + ); + + $plugins->run_hooks("admin_tools_cache_start"); + + $page->output_nav_tabs($sub_tabs, 'cache_manager'); + + $table = new Table; + $table->construct_header($lang->name); + $table->construct_header($lang->size, array("class" => "align_center", "width" => 100)); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 150)); + + $query = $db->simple_select("datacache"); + while($cacheitem = $db->fetch_array($query)) + { + $table->construct_cell("{$cacheitem['title']}"); + $table->construct_cell(get_friendly_size(strlen($cacheitem['cache'])), array("class" => "align_center")); + + if(method_exists($cache, "update_".$cacheitem['title'])) + { + $table->construct_cell("post_code}\">".$lang->rebuild_cache."", array("class" => "align_center")); + } + elseif(method_exists($cache, "reload_".$cacheitem['title'])) + { + $table->construct_cell("post_code}\">".$lang->reload_cache."", array("class" => "align_center")); + } + elseif(function_exists("update_".$cacheitem['title'])) + { + $table->construct_cell("post_code}\">".$lang->rebuild_cache."", array("class" => "align_center")); + } + elseif(function_exists("reload_".$cacheitem['title'])) + { + $table->construct_cell("post_code}\">".$lang->reload_cache."", array("class" => "align_center")); + } + else + { + $table->construct_cell(""); + } + + $table->construct_row(); + } + + // Rebuilds forum settings + $cachedsettings = (array)$mybb->settings; + if(isset($cachedsettings['internal'])) + { + unset($cachedsettings['internal']); + } + + $table->construct_cell("settings"); + $table->construct_cell(get_friendly_size(strlen(serialize($cachedsettings))), array("class" => "align_center")); + $table->construct_cell("post_code}\">".$lang->reload_cache."", array("class" => "align_center")); + + $table->construct_row(); + + $table->output("".$lang->cache_manager); + + $page->output_footer(); +} + diff --git a/Upload/admin/modules/tools/file_verification.php b/Upload/admin/modules/tools/file_verification.php new file mode 100644 index 0000000..a262641 --- /dev/null +++ b/Upload/admin/modules/tools/file_verification.php @@ -0,0 +1,128 @@ +
Please make sure IN_MYBB is defined."); +} + +@set_time_limit(0); + +$page->add_breadcrumb_item($lang->file_verification, "index.php?module=tools-file_verification"); + +$plugins->run_hooks("admin_tools_file_verification_begin"); + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_tools_file_verification_check"); + + if($mybb->request_method == "post") + { + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=tools-system_health"); + } + + $page->add_breadcrumb_item($lang->checking, "index.php?module=tools-file_verification"); + + $page->output_header($lang->file_verification." - ".$lang->checking); + + $file = explode("\n", fetch_remote_file("http://dev.mybboard.pl/checksums/ppm_{$mybb->version_code}.txt")); + + if(strstr($file[0], "output_inline_error($lang->error_communication); + $page->output_footer(); + exit; + } + + // Parser-up our checksum file from the MyBB Server + foreach($file as $line) + { + $parts = explode(" ", $line, 2); + if(empty($parts[0]) || empty($parts[1])) + { + continue; + } + + if(substr($parts[1], 0, 7) == "./admin") + { + $parts[1] = "./{$mybb->config['admin_dir']}".substr($parts[1], 7); + } + + if(file_exists(MYBB_ROOT."forums.php") && !file_exists(MYBB_ROOT."portal.php")) + { + if(trim($parts[1]) == "./index.php") + { + $parts[1] = "./forums.php"; + } + elseif($parts[1] == "./portal.php") + { + $parts[1] = "./index.php"; + } + } + + $checksums[trim($parts[1])][] = $parts[0]; + } + + $bad_files = verify_files(); + + $plugins->run_hooks("admin_tools_file_verification_check_commit_start"); + + $table = new Table; + $table->construct_header($lang->file); + $table->construct_header($lang->status, array("class" => "align_center", "width" => 100)); + + foreach($bad_files as $file) + { + switch($file['status']) + { + case "changed": + $file['status'] = $lang->changed; + $color = "#F22B48"; + break; + case "missing": + $file['status'] = $lang->missing; + $color = "#5B5658"; + break; + } + + $table->construct_cell("".htmlspecialchars_uni(substr($file['path'], 2)).""); + + $table->construct_cell("{$file['status']}", array("class" => "align_center")); + $table->construct_row(); + } + + $no_errors = false; + if($table->num_rows() == 0) + { + $no_errors = true; + $table->construct_cell($lang->no_corrupt_files_found, array('colspan' => 3)); + $table->construct_row(); + } + + if($no_errors) + { + $table->output($lang->file_verification.": ".$lang->no_problems_found); + } + else + { + $table->output($lang->file_verification.": ".$lang->found_problems); + } + + $page->output_footer(); + exit; + } + + $page->output_confirm_action("index.php?module=tools-file_verification", $lang->file_verification_message, $lang->file_verification); +} + diff --git a/Upload/admin/modules/tools/index.html b/Upload/admin/modules/tools/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/modules/tools/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/modules/tools/mailerrors.php b/Upload/admin/modules/tools/mailerrors.php new file mode 100644 index 0000000..94a0dba --- /dev/null +++ b/Upload/admin/modules/tools/mailerrors.php @@ -0,0 +1,265 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->system_email_log, "index.php?module=tools-mailerrors"); + +$plugins->run_hooks("admin_tools_mailerrors_begin"); + +if($mybb->input['action'] == "prune" && $mybb->request_method == "post") +{ + $plugins->run_hooks("admin_tools_mailerrors_prune"); + + if($mybb->input['delete_all']) + { + $db->delete_query("mailerrors"); + $num_deleted = $db->affected_rows(); + + $plugins->run_hooks("admin_tools_mailerrors_prune_delete_all_commit"); + + // Log admin action + log_admin_action($num_deleted); + + flash_message($lang->all_logs_deleted, 'success'); + admin_redirect("index.php?module=tools-mailerrors"); + } + else if(is_array($mybb->input['log'])) + { + $log_ids = implode(",", array_map("intval", $mybb->input['log'])); + if($log_ids) + { + $db->delete_query("mailerrors", "eid IN ({$log_ids})"); + $num_deleted = $db->affected_rows(); + } + } + + $plugins->run_hooks("admin_tools_mailerrors_prune_commit"); + + // Log admin action + log_admin_action($num_deleted); + + flash_message($lang->selected_logs_deleted, 'success'); + admin_redirect("index.php?module=tools-mailerrors"); +} + +if($mybb->input['action'] == "view") +{ + $query = $db->simple_select("mailerrors", "*", "eid='".(int)$mybb->input['eid']."'"); + $log = $db->fetch_array($query); + + if(!$log['eid']) + { + exit; + } + + $plugins->run_hooks("admin_tools_mailerrors_view"); + + $log['toaddress'] = htmlspecialchars_uni($log['toaddress']); + $log['fromaddress'] = htmlspecialchars_uni($log['fromaddress']); + $log['subject'] = htmlspecialchars_uni($log['subject']); + $log['error'] = htmlspecialchars_uni($log['error']); + $log['smtperror'] = htmlspecialchars_uni($log['smtpcode']); + $log['dateline'] = date($mybb->settings['dateformat'], $log['dateline']).", ".date($mybb->settings['timeformat'], $log['dateline']); + $log['message'] = nl2br(htmlspecialchars_uni($log['message'])); + + ?> + + + input['action']) +{ + $per_page = 20; + + if($mybb->input['page'] && $mybb->input['page'] > 1) + { + $mybb->input['page'] = $mybb->get_input('page', 1); + $start = ($mybb->input['page']*$per_page)-$per_page; + } + else + { + $mybb->input['page'] = 1; + $start = 0; + } + + $additional_criteria = array(); + + $plugins->run_hooks("admin_tools_mailerrors_start"); + + $page->output_header($lang->system_email_log); + + $sub_tabs['mailerrors'] = array( + 'title' => $lang->system_email_log, + 'link' => "index.php?module=tools-mailerrors", + 'description' => $lang->system_email_log_desc + ); + + $page->output_nav_tabs($sub_tabs, 'mailerrors'); + + $form = new Form("index.php?module=tools-mailerrors&action=prune", "post"); + + // Begin criteria filtering + if($mybb->input['subject']) + { + $additional_sql_criteria .= " AND subject LIKE '%".$db->escape_string_like($mybb->input['subject'])."%'"; + $additional_criteria[] = "subject='".htmlspecialchars_uni($mybb->input['subject'])."'"; + $form->generate_hidden_field("subject", $mybb->input['subject']); + } + + if($mybb->input['fromaddress']) + { + $additional_sql_criteria .= " AND fromaddress LIKE '%".$db->escape_string_like($mybb->input['fromaddress'])."%'"; + $additional_criteria[] = "fromaddress='".urlencode($mybb->input['fromaddress'])."'"; + $form->generate_hidden_field("fromaddress", $mybb->input['fromaddress']); + } + + if($mybb->input['toaddress']) + { + $additional_sql_criteria .= " AND toaddress LIKE '%".$db->escape_string_like($mybb->input['toaddress'])."%'"; + $additional_criteria[] = "toaddress='".urlencode($mybb->input['toaddress'])."'"; + $form->generate_hidden_field("toaddress", $mybb->input['toaddress']); + } + + if($mybb->input['error']) + { + $additional_sql_criteria .= " AND error LIKE '%".$db->escape_string_like($mybb->input['error'])."%'"; + $additional_criteria[] = "error='".urlencode($mybb->input['error'])."'"; + $form->generate_hidden_field("error", $mybb->input['error']); + } + + if($additional_criteria) + { + $additional_criteria = "&".implode("&", $additional_criteria); + } + + $table = new Table; + $table->construct_header($form->generate_check_box("checkall", 1, '', array('class' => 'checkall'))); + $table->construct_header($lang->subject); + $table->construct_header($lang->to, array("class" => "align_center", "width" => "20%")); + $table->construct_header($lang->error_message, array("class" => "align_center", "width" => "30%")); + $table->construct_header($lang->date_sent, array("class" => "align_center", "width" => "20%")); + + $query = $db->query(" + SELECT * + FROM ".TABLE_PREFIX."mailerrors + WHERE 1=1 {$additional_sql_criteria} + ORDER BY dateline DESC + LIMIT {$start}, {$per_page} + "); + while($log = $db->fetch_array($query)) + { + $log['subject'] = htmlspecialchars_uni($log['subject']); + $log['toemail'] = htmlspecialchars_uni($log['toemail']); + $log['error'] = htmlspecialchars_uni($log['error']); + $log['dateline'] = date($mybb->settings['dateformat'], $log['dateline']).", ".date($mybb->settings['timeformat'], $log['dateline']); + + $table->construct_cell($form->generate_check_box("log[{$log['eid']}]", $log['eid'], '')); + $table->construct_cell("{$log['subject']}"); + $find_from = ""; + $table->construct_cell("{$find_from}
{$log['toaddress']}
"); + $table->construct_cell($log['error']); + $table->construct_cell($log['dateline'], array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_logs, array("colspan" => 5)); + $table->construct_row(); + $table->output($lang->system_email_log); + } + else + { + $table->output($lang->system_email_log); + $buttons[] = $form->generate_submit_button($lang->delete_selected, array('onclick' => "return confirm('{$lang->confirm_delete_logs}');")); + $buttons[] = $form->generate_submit_button($lang->delete_all, array('name' => 'delete_all', 'onclick' => "return confirm('{$lang->confirm_delete_all_logs}');")); + $form->output_submit_wrapper($buttons); + } + + $form->end(); + + $query = $db->simple_select("mailerrors l", "COUNT(eid) AS logs", "1=1 {$additional_sql_criteria}"); + $total_rows = $db->fetch_field($query, "logs"); + + echo "
".draw_admin_pagination($mybb->input['page'], $per_page, $total_rows, "index.php?module=tools-mailerrors&page={page}{$additional_criteria}"); + + $form = new Form("index.php?module=tools-mailerrors", "post"); + $form_container = new FormContainer($lang->filter_system_email_log); + $form_container->output_row($lang->subject_contains, "", $form->generate_text_box('subject', $mybb->input['subject'], array('id' => 'subject')), 'subject'); + $form_container->output_row($lang->error_message_contains, "", $form->generate_text_box('error', $mybb->input['error'], array('id' => 'error')), 'error'); + $form_container->output_row($lang->to_address_contains, "", $form->generate_text_box('toaddress', $mybb->input['toaddress'], array('id' => 'toaddress')), 'toaddress'); + $form_container->output_row($lang->from_address_contains, "", $form->generate_text_box('fromaddress', $mybb->input['fromaddress'], array('id' => 'fromaddress')), 'fromaddress'); + + $form_container->end(); + $buttons = array(); + $buttons[] = $form->generate_submit_button($lang->filter_system_email_log); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} +?> \ No newline at end of file diff --git a/Upload/admin/modules/tools/maillogs.php b/Upload/admin/modules/tools/maillogs.php new file mode 100644 index 0000000..d4dc941 --- /dev/null +++ b/Upload/admin/modules/tools/maillogs.php @@ -0,0 +1,453 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->user_email_log, "index.php?module=tools-maillogs"); + +$plugins->run_hooks("admin_tools_maillogs_begin"); + +if($mybb->input['action'] == "prune" && $mybb->request_method == "post") +{ + $plugins->run_hooks("admin_tools_maillogs_prune"); + + if($mybb->input['delete_all']) + { + $db->delete_query("maillogs"); + $num_deleted = $db->affected_rows(); + + $plugins->run_hooks("admin_tools_maillogs_prune_delete_all_commit"); + + // Log admin action + log_admin_action($num_deleted); + + flash_message($lang->all_logs_deleted, 'success'); + admin_redirect("index.php?module=tools-maillogs"); + } + else if(is_array($mybb->input['log'])) + { + $log_ids = implode(",", array_map("intval", $mybb->input['log'])); + if($log_ids) + { + $db->delete_query("maillogs", "mid IN ({$log_ids})"); + $num_deleted = $db->affected_rows(); + } + } + + $plugins->run_hooks("admin_tools_mailerrors_prune_commit"); + + // Log admin action + log_admin_action($num_deleted); + + flash_message($lang->selected_logs_deleted, 'success'); + admin_redirect("index.php?module=tools-maillogs"); +} + +if($mybb->input['action'] == "view") +{ + $query = $db->simple_select("maillogs", "*", "mid='".$mybb->get_input('mid', 1)."'"); + $log = $db->fetch_array($query); + + if(!$log['mid']) + { + exit; + } + + $plugins->run_hooks("admin_tools_maillogs_view"); + + $log['toemail'] = htmlspecialchars_uni($log['toemail']); + $log['fromemail'] = htmlspecialchars_uni($log['fromemail']); + $log['subject'] = htmlspecialchars_uni($log['subject']); + $log['dateline'] = date($mybb->settings['dateformat'], $log['dateline']).", ".date($mybb->settings['timeformat'], $log['dateline']); + if($mybb->settings['mail_logging'] == 1) + { + $log['message'] = $lang->na; + } + else + { + $log['message'] = nl2br(htmlspecialchars_uni($log['message'])); + } + + ?> + + input['action']) +{ + if(!$mybb->settings['threadsperpage'] || (int)$mybb->settings['threadsperpage'] < 1) + { + $mybb->settings['threadsperpage'] = 20; + } + + $per_page = $mybb->settings['threadsperpage']; + + if(!$per_page) + { + $per_page = 20; + } + + if($mybb->input['page'] && $mybb->input['page'] > 1) + { + $mybb->input['page'] = $mybb->get_input('page', 1); + $start = ($mybb->input['page']*$per_page)-$per_page; + } + else + { + $mybb->input['page'] = 1; + $start = 0; + } + + $additional_criteria = array(); + + $plugins->run_hooks("admin_tools_maillogs_start"); + + // Filter form was submitted - play around with the values + if($mybb->request_method == "post") + { + if($mybb->input['from_type'] == "user") + { + $mybb->input['fromname'] = $mybb->input['from_value']; + } + else if($mybb->input['from_type'] == "email") + { + $mybb->input['fromemail'] = $mybb->input['from_value']; + } + + if($mybb->input['to_type'] == "user") + { + $mybb->input['toname'] = $mybb->input['to_value']; + } + else if($mybb->input['to_type'] == "email") + { + $mybb->input['toemail'] = $mybb->input['to_value']; + } + } + + $touid = (int)$mybb->input['touid']; + $toname = $db->escape_string($mybb->input['toname']); + $toemail = $db->escape_string_like($mybb->input['toemail']); + + $fromuid = (int)$mybb->input['fromuid']; + $fromname = $db->escape_string($mybb->input['fromname']); + $fromemail = $db->escape_string_like($mybb->input['fromemail']); + + $subject = $db->escape_string_like($mybb->input['subject']); + + // Begin criteria filtering + if($mybb->input['subject']) + { + $additional_sql_criteria .= " AND l.subject LIKE '%{$subject}%'"; + $additional_criteria[] = "subject=".urlencode($mybb->input['subject']); + } + + if($mybb->input['fromuid']) + { + $query = $db->simple_select("users", "uid, username", "uid = '{$fromuid}'"); + $user = $db->fetch_array($query); + $from_filter = $user['username']; + + $additional_sql_criteria .= " AND l.fromuid = '{$fromuid}'"; + $additional_criteria[] = "fromuid={$fromuid}"; + } + else if($mybb->input['fromname']) + { + $query = $db->simple_select("users", "uid, username", "LOWER(username) = '{$fromname}'"); + $user = $db->fetch_array($query); + $from_filter = $user['username']; + + if(!$user['uid']) + { + flash_message($lang->error_invalid_user, 'error'); + admin_redirect("index.php?module=tools-maillogs"); + } + + $additional_sql_criteria .= "AND l.fromuid = '{$user['uid']}'"; + $additional_criteria[] = "fromuid={$user['uid']}"; + } + + if($mybb->input['fromemail']) + { + $additional_sql_criteria .= " AND l.fromemail LIKE '%{$fromemail}%'"; + $additional_criteria[] = "fromemail=".urlencode($mybb->input['fromemail']); + $from_filter = $mybb->input['fromemail']; + } + + if($mybb->input['touid']) + { + $query = $db->simple_select("users", "uid, username", "uid = '{$touid}'"); + $user = $db->fetch_array($query); + $to_filter = $user['username']; + + $additional_sql_criteria .= " AND l.touid = '{$touid}'"; + $additional_criteria[] = "touid={$touid}"; + } + else if($mybb->input['toname']) + { + $user = get_user_by_username($toname, array('fields' => 'username')); + $to_filter = $user['username']; + + if(!$user['uid']) + { + flash_message($lang->error_invalid_user, 'error'); + admin_redirect("index.php?module=tools-maillogs"); + } + + $additional_sql_criteria .= "AND l.touid='{$user['uid']}'"; + $additional_criteria[] = "touid={$user['uid']}"; + } + + if($mybb->input['toemail']) + { + $additional_sql_criteria .= " AND l.toemail LIKE '%{$toemail}%'"; + $additional_criteria[] = "toemail=".urlencode($mybb->input['toemail']); + $to_filter = $mybb->input['toemail']; + } + + if(!empty($additional_criteria)) + { + $additional_criteria = "&".implode("&", $additional_criteria); + } + else + { + $additional_criteria = ''; + } + + $page->output_header($lang->user_email_log); + + $sub_tabs['maillogs'] = array( + 'title' => $lang->user_email_log, + 'link' => "index.php?module=tools-maillogs", + 'description' => $lang->user_email_log_desc + ); + + $page->output_nav_tabs($sub_tabs, 'maillogs'); + + $form = new Form("index.php?module=tools-maillogs&action=prune", "post"); + + $table = new Table; + $table->construct_header($form->generate_check_box("checkall", 1, '', array('class' => 'checkall'))); + $table->construct_header($lang->subject, array("colspan" => 2)); + $table->construct_header($lang->from, array("class" => "align_center", "width" => "20%")); + $table->construct_header($lang->to, array("class" => "align_center", "width" => "20%")); + $table->construct_header($lang->date_sent, array("class" => "align_center", "width" => "20%")); + $table->construct_header($lang->ip_address, array("class" => "align_center", 'width' => '10%')); + + $query = $db->query(" + SELECT l.*, r.username AS to_username, f.username AS from_username, t.subject AS thread_subject + FROM ".TABLE_PREFIX."maillogs l + LEFT JOIN ".TABLE_PREFIX."users r ON (r.uid=l.touid) + LEFT JOIN ".TABLE_PREFIX."users f ON (f.uid=l.fromuid) + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=l.tid) + WHERE 1=1 {$additional_sql_criteria} + ORDER BY l.dateline DESC + LIMIT {$start}, {$per_page} + "); + while($log = $db->fetch_array($query)) + { + $table->construct_cell($form->generate_check_box("log[{$log['mid']}]", $log['mid'], ''), array("width" => 1)); + $log['subject'] = htmlspecialchars_uni($log['subject']); + $log['dateline'] = date($mybb->settings['dateformat'], $log['dateline']).", ".date($mybb->settings['timeformat'], $log['dateline']); + + if($log['type'] == 2) + { + if($log['thread_subject']) + { + $log['thread_subject'] = htmlspecialchars_uni($log['thread_subject']); + $thread_link = "".$log['thread_subject'].""; + } + else + { + $thread_link = $lang->deleted; + } + $table->construct_cell("style}/images/icons/maillogs_thread.png\" title=\"{$lang->sent_using_send_thread_feature}\" alt=\"\" />", array("width" => 1)); + $table->construct_cell("{$log['subject']}
{$lang->thread} {$thread_link}"); + + if($log['fromuid'] > 0) + { + $find_from = ""; + } + + if(!$log['from_username'] && $log['fromuid'] > 0) + { + $table->construct_cell("{$find_from}
{$lang->deleted_user}
"); + } + elseif($log['fromuid'] == 0) + { + $log['fromemail'] = htmlspecialchars_uni($log['fromemail']); + $table->construct_cell("{$find_from}
{$log['fromemail']}
"); + } + else + { + $table->construct_cell("{$find_from}"); + } + + $log['toemail'] = htmlspecialchars_uni($log['toemail']); + $table->construct_cell($log['toemail']); + } + elseif($log['type'] == 1) + { + $table->construct_cell("style}/images/icons/maillogs_user.png\" title=\"{$lang->email_sent_to_user}\" alt=\"\" />", array("width" => 1)); + $table->construct_cell("{$log['subject']}"); + + if($log['fromuid'] > 0) + { + $find_from = ""; + } + + if(!$log['from_username'] && $log['fromuid'] > 0) + { + $table->construct_cell("{$find_from}
{$lang->deleted_user}
"); + } + elseif($log['fromuid'] == 0) + { + $log['fromemail'] = htmlspecialchars_uni($log['fromemail']); + $table->construct_cell("{$find_from}
{$log['fromemail']}
"); + } + else + { + $table->construct_cell("{$find_from}"); + } + + $find_to = ""; + if(!$log['to_username']) + { + $table->construct_cell("{$find_to}
{$lang->deleted_user}
"); + } + else + { + $table->construct_cell("{$find_to}"); + } + } + elseif($log['type'] == 3) + { + $table->construct_cell("style}/images/icons/maillogs_contact.png\" title=\"{$lang->email_sent_using_contact_form}\" alt=\"\" />", array("width" => 1)); + $table->construct_cell("{$log['subject']}"); + + if($log['fromuid'] > 0) + { + $find_from = ""; + } + + if(!$log['from_username'] && $log['fromuid'] > 0) + { + $table->construct_cell("{$find_from}
{$lang->deleted_user}
"); + } + elseif($log['fromuid'] == 0) + { + $log['fromemail'] = htmlspecialchars_uni($log['fromemail']); + $table->construct_cell("{$find_from}
{$log['fromemail']}
"); + } + else + { + $table->construct_cell("{$find_from}"); + } + + $log['toemail'] = htmlspecialchars_uni($log['toemail']); + $table->construct_cell($log['toemail']); + } + + $table->construct_cell($log['dateline'], array("class" => "align_center")); + $table->construct_cell(my_inet_ntop($db->unescape_binary($log['ipaddress'])), array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_logs, array("colspan" => "7")); + $table->construct_row(); + $table->output($lang->user_email_log); + } + else + { + $table->output($lang->user_email_log); + $buttons[] = $form->generate_submit_button($lang->delete_selected, array('onclick' => "return confirm('{$lang->confirm_delete_logs}');")); + $buttons[] = $form->generate_submit_button($lang->delete_all, array('name' => 'delete_all', 'onclick' => "return confirm('{$lang->confirm_delete_all_logs}');")); + $form->output_submit_wrapper($buttons); + } + + $form->end(); + + $query = $db->simple_select("maillogs l", "COUNT(l.mid) as logs", "1=1 {$additional_sql_criteria}"); + $total_rows = $db->fetch_field($query, "logs"); + + echo "
".draw_admin_pagination($mybb->input['page'], $per_page, $total_rows, "index.php?module=tools-maillogs&page={page}{$additional_criteria}"); + + $form = new Form("index.php?module=tools-maillogs", "post"); + $form_container = new FormContainer($lang->filter_user_email_log); + $user_email = array( + "user" => $lang->username_is, + "email" => $lang->email_contains + ); + $form_container->output_row($lang->subject_contains, "", $form->generate_text_box('subject', $mybb->input['subject'], array('id' => 'subject')), 'subject'); + if($from_username) + { + $from_type = "user"; + } + else if($mybb->input['fromemail']) + { + $from_type = "email"; + } + $form_container->output_row($lang->from, "", $form->generate_select_box('from_type', $user_email, $from_type)." ".$form->generate_text_box('from_value', $from_filter, array('id' => 'from_value')), 'from_value'); + if($to_username) + { + $to_type = "user"; + } + else if($mybb->input['toemail']) + { + $to_type = "email"; + } + $form_container->output_row($lang->to, "", $form->generate_select_box('to_type', $user_email, $to_type)." ".$form->generate_text_box('to_value', $to_filter, array('id' => 'to_value')), 'to_value'); + $form_container->end(); + $buttons = array(); + $buttons[] = $form->generate_submit_button($lang->filter_user_email_log); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} +?> \ No newline at end of file diff --git a/Upload/admin/modules/tools/modlog.php b/Upload/admin/modules/tools/modlog.php new file mode 100644 index 0000000..fb2ca5b --- /dev/null +++ b/Upload/admin/modules/tools/modlog.php @@ -0,0 +1,340 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->mod_logs, "index.php?module=tools-modlog"); + +$sub_tabs['mod_logs'] = array( + 'title' => $lang->mod_logs, + 'link' => "index.php?module=tools-modlog", + 'description' => $lang->mod_logs_desc +); +$sub_tabs['prune_mod_logs'] = array( + 'title' => $lang->prune_mod_logs, + 'link' => "index.php?module=tools-modlog&action=prune", + 'description' => $lang->prune_mod_logs_desc +); + +$plugins->run_hooks("admin_tools_modlog_begin"); + +if($mybb->input['action'] == 'prune') +{ + $plugins->run_hooks("admin_tools_modlog_prune"); + + if($mybb->request_method == 'post') + { + $is_today = false; + if($mybb->input['older_than'] <= 0) + { + $is_today = true; + $mybb->input['older_than'] = 1; + } + $where = 'dateline < '.(TIME_NOW-((int)$mybb->input['older_than']*86400)); + + // Searching for entries by a particular user + if($mybb->input['uid']) + { + $where .= " AND uid='".$mybb->get_input('uid', 1)."'"; + } + + // Searching for entries in a specific module + if($mybb->input['fid'] > 0) + { + $where .= " AND fid='".$db->escape_string($mybb->input['fid'])."'"; + } + else + { + $mybb->input['fid'] = 0; + } + + $db->delete_query("moderatorlog", $where); + $num_deleted = $db->affected_rows(); + + $plugins->run_hooks("admin_tools_modlog_prune_commit"); + + if(!is_array($forum_cache)) + { + $forum_cache = cache_forums(); + } + + // Log admin action + log_admin_action($mybb->input['older_than'], $mybb->input['uid'], $mybb->input['fid'], $num_deleted, $forum_cache[$mybb->input['fid']]['name']); + + $success = $lang->success_pruned_mod_logs; + if($is_today == true && $num_deleted > 0) + { + $success .= ' '.$lang->note_logs_locked; + } + elseif($is_today == true && $num_deleted == 0) + { + flash_message($lang->note_logs_locked, 'error'); + admin_redirect("index.php?module=tools-modlog"); + } + flash_message($success, 'success'); + admin_redirect("index.php?module=tools-modlog"); + } + $page->add_breadcrumb_item($lang->prune_mod_logs, "index.php?module=tools-modlog&action=prune"); + $page->output_header($lang->prune_mod_logs); + $page->output_nav_tabs($sub_tabs, 'prune_mod_logs'); + + // Fetch filter options + $sortbysel[$mybb->input['sortby']] = 'selected="selected"'; + $ordersel[$mybb->input['order']] = 'selected="selected"'; + + $user_options[''] = $lang->all_moderators; + $user_options['0'] = '----------'; + + $query = $db->query(" + SELECT DISTINCT l.uid, u.username + FROM ".TABLE_PREFIX."moderatorlog l + LEFT JOIN ".TABLE_PREFIX."users u ON (l.uid=u.uid) + ORDER BY u.username ASC + "); + while($user = $db->fetch_array($query)) + { + $user_options[$user['uid']] = $user['username']; + } + + $form = new Form("index.php?module=tools-modlog&action=prune", "post"); + $form_container = new FormContainer($lang->prune_moderator_logs); + $form_container->output_row($lang->forum, "", $form->generate_forum_select('fid', $mybb->input['fid'], array('id' => 'fid', 'main_option' => $lang->all_forums)), 'fid'); + $form_container->output_row($lang->forum_moderator, "", $form->generate_select_box('uid', $user_options, $mybb->input['uid'], array('id' => 'uid')), 'uid'); + if(!$mybb->input['older_than']) + { + $mybb->input['older_than'] = '30'; + } + $form_container->output_row($lang->date_range, "", $lang->older_than.$form->generate_numeric_field('older_than', $mybb->input['older_than'], array('id' => 'older_than', 'style' => 'width: 30px')).' '.$lang->days, 'older_than'); + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->prune_moderator_logs); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_tools_modlog_start"); + + $page->output_header($lang->mod_logs); + + $page->output_nav_tabs($sub_tabs, 'mod_logs'); + + $perpage = $mybb->get_input('perpage', 1); + if(!$perpage) + { + if(!$mybb->settings['threadsperpage'] || (int)$mybb->settings['threadsperpage'] < 1) + { + $mybb->settings['threadsperpage'] = 20; + } + + $perpage = $mybb->settings['threadsperpage']; + } + + $where = 'WHERE 1=1'; + + // Searching for entries by a particular user + if($mybb->input['uid']) + { + $where .= " AND l.uid='".$mybb->get_input('uid', 1)."'"; + } + + // Searching for entries in a specific forum + if($mybb->input['fid'] > 0) + { + $where .= " AND l.fid='".$mybb->get_input('fid', 1)."'"; + } + + // Order? + switch($mybb->input['sortby']) + { + case "username": + $sortby = "u.username"; + break; + case "forum": + $sortby = "f.name"; + break; + case "thread": + $sortby = "t.subject"; + break; + default: + $sortby = "l.dateline"; + } + $order = $mybb->input['order']; + if($order != "asc") + { + $order = "desc"; + } + + $query = $db->query(" + SELECT COUNT(l.dateline) AS count + FROM ".TABLE_PREFIX."moderatorlog l + {$where} + "); + $rescount = $db->fetch_field($query, "count"); + + // Figure out if we need to display multiple pages. + if($mybb->input['page'] != "last") + { + $pagecnt = $mybb->get_input('page', 1); + } + + $postcount = (int)$rescount; + $pages = $postcount / $perpage; + $pages = ceil($pages); + + if($mybb->input['page'] == "last") + { + $pagecnt = $pages; + } + + if($pagecnt > $pages) + { + $pagecnt = 1; + } + + if($pagecnt) + { + $start = ($pagecnt-1) * $perpage; + } + else + { + $start = 0; + $pagecnt = 1; + } + + $table = new Table; + $table->construct_header($lang->username, array('width' => '10%')); + $table->construct_header($lang->date, array("class" => "align_center", 'width' => '15%')); + $table->construct_header($lang->action, array("class" => "align_center", 'width' => '35%')); + $table->construct_header($lang->information, array("class" => "align_center", 'width' => '30%')); + $table->construct_header($lang->ipaddress, array("class" => "align_center", 'width' => '10%')); + + $query = $db->query(" + SELECT l.*, u.username, u.usergroup, u.displaygroup, t.subject AS tsubject, f.name AS fname, p.subject AS psubject + FROM ".TABLE_PREFIX."moderatorlog l + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=l.uid) + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=l.tid) + LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=l.fid) + LEFT JOIN ".TABLE_PREFIX."posts p ON (p.pid=l.pid) + {$where} + ORDER BY {$sortby} {$order} + LIMIT {$start}, {$perpage} + "); + while($logitem = $db->fetch_array($query)) + { + $information = ''; + $logitem['action'] = htmlspecialchars_uni($logitem['action']); + $logitem['dateline'] = my_date('relative', $logitem['dateline']); + $trow = alt_trow(); + $username = format_name($logitem['username'], $logitem['usergroup'], $logitem['displaygroup']); + $logitem['profilelink'] = build_profile_link($username, $logitem['uid'], "_blank"); + if($logitem['tsubject']) + { + $information = "{$lang->thread} ".htmlspecialchars_uni($logitem['tsubject'])."
"; + } + if($logitem['fname']) + { + $information .= "{$lang->forum} ".htmlspecialchars_uni($logitem['fname'])."
"; + } + if($logitem['psubject']) + { + $information .= "{$lang->post} ".htmlspecialchars_uni($logitem['psubject']).""; + } + + if(!$logitem['tsubject'] || !$logitem['fname'] || !$logitem['psubject']) + { + $data = my_unserialize($logitem['data']); + if($data['uid']) + { + $information = "{$lang->user_info} ".htmlspecialchars_uni($data['username']).""; + } + if($data['aid']) + { + $information = "{$lang->announcement} ".htmlspecialchars_uni($data['subject']).""; + } + } + + $table->construct_cell($logitem['profilelink']); + $table->construct_cell($logitem['dateline'], array("class" => "align_center")); + $table->construct_cell($logitem['action'], array("class" => "align_center")); + $table->construct_cell($information); + $table->construct_cell(my_inet_ntop($db->unescape_binary($logitem['ipaddress'])), array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_modlogs, array("colspan" => "5")); + $table->construct_row(); + } + + $table->output($lang->mod_logs); + + // Do we need to construct the pagination? + if($rescount > $perpage) + { + echo draw_admin_pagination($pagecnt, $perpage, $rescount, "index.php?module=tools-modlog&perpage=$perpage&uid={$mybb->input['uid']}&fid={$mybb->input['fid']}&sortby={$mybb->input['sortby']}&order={$order}")."
"; + } + + // Fetch filter options + $sortbysel[$mybb->input['sortby']] = "selected=\"selected\""; + $ordersel[$mybb->input['order']] = "selected=\"selected\""; + + $user_options[''] = $lang->all_moderators; + $user_options['0'] = '----------'; + + $query = $db->query(" + SELECT DISTINCT l.uid, u.username + FROM ".TABLE_PREFIX."moderatorlog l + LEFT JOIN ".TABLE_PREFIX."users u ON (l.uid=u.uid) + ORDER BY u.username ASC + "); + while($user = $db->fetch_array($query)) + { + $selected = ''; + if($mybb->input['uid'] == $user['uid']) + { + $selected = "selected=\"selected\""; + } + $user_options[$user['uid']] = $user['username']; + } + + $sort_by = array( + 'dateline' => $lang->date, + 'username' => $lang->username, + 'forum' => $lang->forum_name, + 'thread' => $lang->thread_subject + ); + + $order_array = array( + 'asc' => $lang->asc, + 'desc' => $lang->desc + ); + + $form = new Form("index.php?module=tools-modlog", "post"); + $form_container = new FormContainer($lang->filter_moderator_logs); + $form_container->output_row($lang->forum, "", $form->generate_forum_select('fid', $mybb->input['fid'], array('id' => 'fid', 'main_option' => $lang->all_forums)), 'fid'); + $form_container->output_row($lang->forum_moderator, "", $form->generate_select_box('uid', $user_options, $mybb->input['uid'], array('id' => 'uid')), 'uid'); + $form_container->output_row($lang->sort_by, "", $form->generate_select_box('sortby', $sort_by, $mybb->input['sortby'], array('id' => 'sortby'))." {$lang->in} ".$form->generate_select_box('order', $order_array, $order, array('id' => 'order'))." {$lang->order}", 'order'); + $form_container->output_row($lang->results_per_page, "", $form->generate_numeric_field('perpage', $perpage, array('id' => 'perpage')), 'perpage'); + + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->filter_moderator_logs); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/tools/module_meta.php b/Upload/admin/modules/tools/module_meta.php new file mode 100644 index 0000000..9374df5 --- /dev/null +++ b/Upload/admin/modules/tools/module_meta.php @@ -0,0 +1,122 @@ +
Please make sure IN_MYBB is defined."); +} + +function tools_meta() +{ + global $page, $lang, $plugins; + + $sub_menu = array(); + $sub_menu['10'] = array("id" => "system_health", "title" => $lang->system_health, "link" => "index.php?module=tools-system_health"); + $sub_menu['20'] = array("id" => "cache", "title" => $lang->cache_manager, "link" => "index.php?module=tools-cache"); + $sub_menu['30'] = array("id" => "tasks", "title" => $lang->task_manager, "link" => "index.php?module=tools-tasks"); + $sub_menu['40'] = array("id" => "recount_rebuild", "title" => $lang->recount_and_rebuild, "link" => "index.php?module=tools-recount_rebuild"); + $sub_menu['50'] = array("id" => "php_info", "title" => $lang->view_php_info, "link" => "index.php?module=tools-php_info"); + $sub_menu['60'] = array("id" => "backupdb", "title" => $lang->database_backups, "link" => "index.php?module=tools-backupdb"); + $sub_menu['70'] = array("id" => "optimizedb", "title" => $lang->optimize_database, "link" => "index.php?module=tools-optimizedb"); + $sub_menu['80'] = array("id" => "file_verification", "title" => $lang->file_verification, "link" => "index.php?module=tools-file_verification"); + + $sub_menu = $plugins->run_hooks("admin_tools_menu", $sub_menu); + + $page->add_menu_item($lang->tools_and_maintenance, "tools", "index.php?module=tools", 50, $sub_menu); + + return true; +} + +function tools_action_handler($action) +{ + global $page, $lang, $plugins; + + $page->active_module = "tools"; + + $actions = array( + 'php_info' => array('active' => 'php_info', 'file' => 'php_info.php'), + 'tasks' => array('active' => 'tasks', 'file' => 'tasks.php'), + 'backupdb' => array('active' => 'backupdb', 'file' => 'backupdb.php'), + 'optimizedb' => array('active' => 'optimizedb', 'file' => 'optimizedb.php'), + 'cache' => array('active' => 'cache', 'file' => 'cache.php'), + 'recount_rebuild' => array('active' => 'recount_rebuild', 'file' => 'recount_rebuild.php'), + 'maillogs' => array('active' => 'maillogs', 'file' => 'maillogs.php'), + 'mailerrors' => array('active' => 'mailerrors', 'file' => 'mailerrors.php'), + 'adminlog' => array('active' => 'adminlog', 'file' => 'adminlog.php'), + 'modlog' => array('active' => 'modlog', 'file' => 'modlog.php'), + 'warninglog' => array('active' => 'warninglog', 'file' => 'warninglog.php'), + 'spamlog' => array('active' => 'spamlog', 'file' => 'spamlog.php'), + 'system_health' => array('active' => 'system_health', 'file' => 'system_health.php'), + 'file_verification' => array('active' => 'file_verification', 'file' => 'file_verification.php'), + 'statistics' => array('active' => 'statistics', 'file' => 'statistics.php'), + ); + + $actions = $plugins->run_hooks("admin_tools_action_handler", $actions); + + $sub_menu = array(); + $sub_menu['10'] = array("id" => "adminlog", "title" => $lang->administrator_log, "link" => "index.php?module=tools-adminlog"); + $sub_menu['20'] = array("id" => "modlog", "title" => $lang->moderator_log, "link" => "index.php?module=tools-modlog"); + $sub_menu['30'] = array("id" => "maillogs", "title" => $lang->user_email_log, "link" => "index.php?module=tools-maillogs"); + $sub_menu['40'] = array("id" => "mailerrors", "title" => $lang->system_mail_log, "link" => "index.php?module=tools-mailerrors"); + $sub_menu['50'] = array("id" => "warninglog", "title" => $lang->user_warning_log, "link" => "index.php?module=tools-warninglog"); + $sub_menu['60'] = array("id" => "spamlog", "title" => $lang->spam_log, "link" => "index.php?module=tools-spamlog"); + $sub_menu['70'] = array("id" => "statistics", "title" => $lang->statistics, "link" => "index.php?module=tools-statistics"); + + $sub_menu = $plugins->run_hooks("admin_tools_menu_logs", $sub_menu); + + if(!isset($actions[$action])) + { + $page->active_action = "system_health"; + } + + $sidebar = new SidebarItem($lang->logs); + $sidebar->add_menu_items($sub_menu, $actions[$action]['active']); + + $page->sidebar .= $sidebar->get_markup(); + + if(isset($actions[$action])) + { + $page->active_action = $actions[$action]['active']; + return $actions[$action]['file']; + } + else + { + return "system_health.php"; + } +} + +function tools_admin_permissions() +{ + global $lang, $plugins; + + $admin_permissions = array( + "system_health" => $lang->can_access_system_health, + "cache" => $lang->can_manage_cache, + "tasks" => $lang->can_manage_tasks, + "backupdb" => $lang->can_manage_db_backup, + "optimizedb" => $lang->can_optimize_db, + "recount_rebuild" => $lang->can_recount_and_rebuild, + "adminlog" => $lang->can_manage_admin_logs, + "modlog" => $lang->can_manage_mod_logs, + "maillogs" => $lang->can_manage_user_mail_log, + "mailerrors" => $lang->can_manage_system_mail_log, + "warninglog" => $lang->can_manage_user_warning_log, + "spamlog" => $lang->can_manage_spam_log, + "php_info" => $lang->can_view_php_info, + "file_verification" => $lang->can_manage_file_verification, + "statistics" => $lang->can_view_statistics, + ); + + $admin_permissions = $plugins->run_hooks("admin_tools_permissions", $admin_permissions); + + return array("name" => $lang->tools_and_maintenance, "permissions" => $admin_permissions, "disporder" => 50); +} + diff --git a/Upload/admin/modules/tools/optimizedb.php b/Upload/admin/modules/tools/optimizedb.php new file mode 100644 index 0000000..49a79fb --- /dev/null +++ b/Upload/admin/modules/tools/optimizedb.php @@ -0,0 +1,112 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->optimize_database, "index.php?module=tools-optimizedb"); + +$plugins->run_hooks("admin_tools_optimizedb_begin"); + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_tools_optimizedb_start"); + + if($mybb->request_method == "post") + { + if(!is_array($mybb->input['tables'])) + { + flash_message($lang->error_no_tables_selected, 'error'); + admin_redirect("index.php?module=tools-optimizedb"); + } + + @set_time_limit(0); + + $db->set_table_prefix(''); + + foreach($mybb->input['tables'] as $table) + { + if($db->table_exists($db->escape_string($table))) + { + $db->optimize_table($table); + $db->analyze_table($table); + } + } + + $db->set_table_prefix(TABLE_PREFIX); + + $plugins->run_hooks("admin_tools_optimizedb_start_begin"); + + // Log admin action + log_admin_action(serialize($mybb->input['tables'])); + + flash_message($lang->success_tables_optimized, 'success'); + admin_redirect("index.php?module=tools-optimizedb"); + } + + $page->extra_header = " \n"; + + $page->output_header($lang->optimize_database); + + $table = new Table; + $table->construct_header($lang->table_selection); + + $table_selects = array(); + $table_list = $db->list_tables($config['database']['database']); + foreach($table_list as $id => $table_name) + { + $table_selects[$table_name] = $table_name; + } + + $form = new Form("index.php?module=tools-optimizedb", "post", "table_selection", 0, "table_selection"); + + $table->construct_cell("{$lang->tables_select_desc}\n

\n{$lang->select_all}
\n{$lang->deselect_all}
\n{$lang->select_forum_tables}\n

\n
".$form->generate_select_box("tables[]", $table_selects, false, array('multiple' => true, 'id' => 'table_select', 'size' => 20))."
", array('rowspan' => 5, 'width' => '50%')); + $table->construct_row(); + + $table->output($lang->optimize_database); + + $buttons[] = $form->generate_submit_button($lang->optimize_selected_tables); + $form->output_submit_wrapper($buttons); + + $form->end(); + + $page->output_footer(); +} + diff --git a/Upload/admin/modules/tools/php_info.php b/Upload/admin/modules/tools/php_info.php new file mode 100644 index 0000000..48a8e61 --- /dev/null +++ b/Upload/admin/modules/tools/php_info.php @@ -0,0 +1,42 @@ +
Please make sure IN_MYBB is defined."); +} + +if($mybb->input['action'] == 'phpinfo') +{ + $plugins->run_hooks("admin_tools_php_info_phpinfo"); + + // Log admin action + log_admin_action(); + + phpinfo(); + exit; +} + +$page->add_breadcrumb_item($lang->php_info, "index.php?module=tools-php_info"); + +$plugins->run_hooks("admin_tools_php_info_begin"); + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_tools_php_info_start"); + + $page->output_header($lang->php_info); + + echo ""; + + $page->output_footer(); +} + diff --git a/Upload/admin/modules/tools/recount_rebuild.php b/Upload/admin/modules/tools/recount_rebuild.php new file mode 100644 index 0000000..27205dd --- /dev/null +++ b/Upload/admin/modules/tools/recount_rebuild.php @@ -0,0 +1,716 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->recount_rebuild, "index.php?module=tools-recount_rebuild"); + +$plugins->run_hooks("admin_tools_recount_rebuild"); + +function acp_rebuild_forum_counters() +{ + global $db, $mybb, $lang; + + $query = $db->simple_select("forums", "COUNT(*) as num_forums"); + $num_forums = $db->fetch_field($query, 'num_forums'); + + $page = $mybb->get_input('page', 1); + $per_page = (int)$mybb->input['forumcounters']; + if($per_page <= 0) + { + $per_page = 50; + } + $start = ($page-1) * $per_page; + $end = $start + $per_page; + + $query = $db->simple_select("forums", "fid", '', array('order_by' => 'fid', 'order_dir' => 'asc', 'limit_start' => $start, 'limit' => $per_page)); + while($forum = $db->fetch_array($query)) + { + $update['parentlist'] = make_parent_list($forum['fid']); + $db->update_query("forums", $update, "fid='{$forum['fid']}'"); + rebuild_forum_counters($forum['fid']); + } + + check_proceed($num_forums, $end, ++$page, $per_page, "forumcounters", "do_rebuildforumcounters", $lang->success_rebuilt_forum_counters); +} + +function acp_rebuild_thread_counters() +{ + global $db, $mybb, $lang; + + $query = $db->simple_select("threads", "COUNT(*) as num_threads"); + $num_threads = $db->fetch_field($query, 'num_threads'); + + $page = $mybb->get_input('page', 1); + $per_page = (int)$mybb->input['threadcounters']; + if($per_page <= 0) + { + $per_page = 500; + } + $start = ($page-1) * $per_page; + $end = $start + $per_page; + + $query = $db->simple_select("threads", "tid", '', array('order_by' => 'tid', 'order_dir' => 'asc', 'limit_start' => $start, 'limit' => $per_page)); + while($thread = $db->fetch_array($query)) + { + rebuild_thread_counters($thread['tid']); + } + + check_proceed($num_threads, $end, ++$page, $per_page, "threadcounters", "do_rebuildthreadcounters", $lang->success_rebuilt_thread_counters); +} + +function acp_rebuild_poll_counters() +{ + global $db, $mybb, $lang; + + $query = $db->simple_select("polls", "COUNT(*) as num_polls"); + $num_polls = $db->fetch_field($query, 'num_polls'); + + $page = $mybb->get_input('page', 1); + $per_page = (int)$mybb->input['pollcounters']; + if($per_page <= 0) + { + $per_page = 500; + } + $start = ($page-1) * $per_page; + $end = $start + $per_page; + + $query = $db->simple_select("polls", "pid", '', array('order_by' => 'pid', 'order_dir' => 'asc', 'limit_start' => $start, 'limit' => $per_page)); + while($poll = $db->fetch_array($query)) + { + rebuild_poll_counters($poll['pid']); + } + + check_proceed($num_polls, $end, ++$page, $per_page, "pollcounters", "do_rebuildpollcounters", $lang->success_rebuilt_poll_counters); +} + +function acp_recount_user_posts() +{ + global $db, $mybb, $lang; + + $query = $db->simple_select("users", "COUNT(uid) as num_users"); + $num_users = $db->fetch_field($query, 'num_users'); + + $page = $mybb->get_input('page', 1); + $per_page = (int)$mybb->input['userposts']; + if($per_page <= 0) + { + $per_page = 500; + } + $start = ($page-1) * $per_page; + $end = $start + $per_page; + + $query = $db->simple_select("forums", "fid", "usepostcounts = 0"); + while($forum = $db->fetch_array($query)) + { + $fids[] = $forum['fid']; + } + if(is_array($fids)) + { + $fids = implode(',', $fids); + } + if($fids) + { + $fids = " AND p.fid NOT IN($fids)"; + } + else + { + $fids = ""; + } + + $query = $db->simple_select("users", "uid", '', array('order_by' => 'uid', 'order_dir' => 'asc', 'limit_start' => $start, 'limit' => $per_page)); + while($user = $db->fetch_array($query)) + { + $query2 = $db->query(" + SELECT COUNT(p.pid) AS post_count + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + WHERE p.uid='{$user['uid']}' AND t.visible > 0 AND p.visible > 0{$fids} + "); + $num_posts = $db->fetch_field($query2, "post_count"); + + $db->update_query("users", array("postnum" => (int)$num_posts), "uid='{$user['uid']}'"); + } + + check_proceed($num_users, $end, ++$page, $per_page, "userposts", "do_recountuserposts", $lang->success_rebuilt_user_post_counters); +} + +function acp_recount_user_threads() +{ + global $db, $mybb, $lang; + + $query = $db->simple_select("users", "COUNT(uid) as num_users"); + $num_users = $db->fetch_field($query, 'num_users'); + + $page = $mybb->get_input('page', 1); + $per_page = (int)$mybb->input['userthreads']; + if($per_page <= 0) + { + $per_page = 500; + } + $start = ($page-1) * $per_page; + $end = $start + $per_page; + + $query = $db->simple_select("forums", "fid", "usethreadcounts = 0"); + while($forum = $db->fetch_array($query)) + { + $fids[] = $forum['fid']; + } + if(is_array($fids)) + { + $fids = implode(',', $fids); + } + if($fids) + { + $fids = " AND t.fid NOT IN($fids)"; + } + else + { + $fids = ""; + } + + $query = $db->simple_select("users", "uid", '', array('order_by' => 'uid', 'order_dir' => 'asc', 'limit_start' => $start, 'limit' => $per_page)); + while($user = $db->fetch_array($query)) + { + $query2 = $db->query(" + SELECT COUNT(t.tid) AS thread_count + FROM ".TABLE_PREFIX."threads t + WHERE t.uid='{$user['uid']}' AND t.visible > 0 AND t.closed NOT LIKE 'moved|%'{$fids} + "); + $num_threads = $db->fetch_field($query2, "thread_count"); + + $db->update_query("users", array("threadnum" => (int)$num_threads), "uid='{$user['uid']}'"); + } + + check_proceed($num_users, $end, ++$page, $per_page, "userthreads", "do_recountuserthreads", $lang->success_rebuilt_user_thread_counters); +} + +function acp_recount_reputation() +{ + global $db, $mybb, $lang; + + $query = $db->simple_select("users", "COUNT(uid) as num_users"); + $num_users = $db->fetch_field($query, 'num_users'); + + $page = $mybb->get_input('page', 1); + $per_page = (int)$mybb->input['reputation']; + if($per_page <= 0) + { + $per_page = 500; + } + $start = ($page-1) * $per_page; + $end = $start + $per_page; + + $query = $db->simple_select("users", "uid", '', array('order_by' => 'uid', 'order_dir' => 'asc', 'limit_start' => $start, 'limit' => $per_page)); + while($user = $db->fetch_array($query)) + { + $query2 = $db->query(" + SELECT SUM(reputation) as total_rep + FROM ".TABLE_PREFIX."reputation + WHERE `uid`='{$user['uid']}' + "); + $total_rep = $db->fetch_field($query2, "total_rep"); + + $db->update_query("users", array("reputation" => (int)$total_rep), "uid='{$user['uid']}'"); + } + + check_proceed($num_users, $end, ++$page, $per_page, "reputation", "do_recountreputation", $lang->success_rebuilt_reputation); +} + +function acp_recount_warning() +{ + global $db, $mybb, $lang; + + $query = $db->simple_select("users", "COUNT(uid) as num_users"); + $num_users = $db->fetch_field($query, 'num_users'); + + $page = $mybb->get_input('page', 1); + $per_page = (int)$mybb->input['warning']; + if($per_page <= 0) + { + $per_page = 500; + } + $start = ($page-1) * $per_page; + $end = $start + $per_page; + + $query = $db->simple_select("users", "uid", '', array('order_by' => 'uid', 'order_dir' => 'asc', 'limit_start' => $start, 'limit' => $per_page)); + while($user = $db->fetch_array($query)) + { + $query2 = $db->query(" + SELECT SUM(points) as warn_lev + FROM ".TABLE_PREFIX."warnings + WHERE uid='{$user['uid']}' AND expired='0' + "); + $warn_lev = $db->fetch_field($query2, "warn_lev"); + + $db->update_query("users", array("warningpoints" => (int)$warn_lev), "uid='{$user['uid']}'"); + } + + check_proceed($num_users, $end, ++$page, $per_page, "warning", "do_recountwarning", $lang->success_rebuilt_warning); +} + +function acp_recount_private_messages() +{ + global $db, $mybb, $lang; + + $query = $db->simple_select("users", "COUNT(uid) as num_users"); + $num_users = $db->fetch_field($query, 'num_users'); + + $page = $mybb->get_input('page', 1); + $per_page = (int)$mybb->input['privatemessages']; + if($per_page <= 0) + { + $per_page = 500; + } + $start = ($page-1) * $per_page; + $end = $start + $per_page; + + require_once MYBB_ROOT."inc/functions_user.php"; + + $query = $db->simple_select("users", "uid", '', array('order_by' => 'uid', 'order_dir' => 'asc', 'limit_start' => $start, 'limit' => $per_page)); + while($user = $db->fetch_array($query)) + { + update_pm_count($user['uid']); + } + + check_proceed($num_users, $end, ++$page, $per_page, "privatemessages", "do_recountprivatemessages", $lang->success_rebuilt_private_messages); +} + +function acp_recount_referrals() +{ + global $db, $mybb, $lang; + + $query = $db->simple_select("users", "COUNT(uid) as num_users"); + $num_users = $db->fetch_field($query, 'num_users'); + + $page = $mybb->get_input('page', 1); + $per_page = (int)$mybb->input['referral']; + $start = ($page-1) * $per_page; + $end = $start + $per_page; + + $query = $db->simple_select("users", "uid", '', array('order_by' => 'uid', 'order_dir' => 'asc', 'limit_start' => $start, 'limit' => $per_page)); + while($user = $db->fetch_array($query)) + { + $query2 = $db->query(" + SELECT COUNT(uid) as num_referrers + FROM ".TABLE_PREFIX."users + WHERE referrer='{$user['uid']}' + "); + $num_referrers = $db->fetch_field($query2, "num_referrers"); + + $db->update_query("users", array("referrals" => (int)$num_referrers), "uid='{$user['uid']}'"); + } + + check_proceed($num_users, $end, ++$page, $per_page, "referral", "do_recountreferral", $lang->success_rebuilt_referral); +} + +function acp_recount_thread_ratings() +{ + global $db, $mybb, $lang; + + $query = $db->simple_select("threads", "COUNT(*) as num_threads"); + $num_threads = $db->fetch_field($query, 'num_threads'); + + $page = $mybb->get_input('page', 1); + $per_page = (int)$mybb->input['threadrating']; + if($per_page <= 0) + { + $per_page = 500; + } + $start = ($page-1) * $per_page; + $end = $start + $per_page; + + $query = $db->simple_select("threads", "tid", '', array('order_by' => 'tid', 'order_dir' => 'asc', 'limit_start' => $start, 'limit' => $per_page)); + while($thread = $db->fetch_array($query)) + { + $query2 = $db->query(" + SELECT COUNT(tid) as num_ratings, SUM(rating) as total_rating + FROM ".TABLE_PREFIX."threadratings + WHERE tid='{$thread['tid']}' + "); + $recount = $db->fetch_array($query2); + + $db->update_query("threads", array("numratings" => (int)$recount['num_ratings'], "totalratings" => (int)$recount['total_rating']), "tid='{$thread['tid']}'"); + } + + check_proceed($num_threads, $end, ++$page, $per_page, "threadrating", "do_recountthreadrating", $lang->success_rebuilt_thread_ratings); +} + +function acp_rebuild_attachment_thumbnails() +{ + global $db, $mybb, $lang; + + $query = $db->simple_select("attachments", "COUNT(aid) as num_attachments"); + $num_attachments = $db->fetch_field($query, 'num_attachments'); + + $page = $mybb->get_input('page', 1); + $per_page = (int)$mybb->input['attachmentthumbs']; + if($per_page <= 0) + { + $per_page = 20; + } + $start = ($page-1) * $per_page; + $end = $start + $per_page; + + require_once MYBB_ROOT."inc/functions_image.php"; + + $query = $db->simple_select("attachments", "*", '', array('order_by' => 'aid', 'order_dir' => 'asc', 'limit_start' => $start, 'limit' => $per_page)); + while($attachment = $db->fetch_array($query)) + { + $ext = my_strtolower(my_substr(strrchr($attachment['filename'], "."), 1)); + if($ext == "gif" || $ext == "png" || $ext == "jpg" || $ext == "jpeg" || $ext == "jpe") + { + $thumbname = str_replace(".attach", "_thumb.$ext", $attachment['attachname']); + $thumbnail = generate_thumbnail(MYBB_ROOT."uploads/".$attachment['attachname'], MYBB_ROOT."uploads/", $thumbname, $mybb->settings['attachthumbh'], $mybb->settings['attachthumbw']); + if($thumbnail['code'] == 4) + { + $thumbnail['filename'] = "SMALL"; + } + $db->update_query("attachments", array("thumbnail" => $thumbnail['filename']), "aid='{$attachment['aid']}'"); + } + } + + check_proceed($num_attachments, $end, ++$page, $per_page, "attachmentthumbs", "do_rebuildattachmentthumbs", $lang->success_rebuilt_attachment_thumbnails); +} + +function check_proceed($current, $finish, $next_page, $per_page, $name, $name2, $message) +{ + global $page, $lang, $plugins; + + if($finish >= $current) + { + flash_message($message, 'success'); + admin_redirect("index.php?module=tools-recount_rebuild"); + } + else + { + $page->output_header(); + + $form = new Form("index.php?module=tools-recount_rebuild", 'post'); + + echo $form->generate_hidden_field("page", $next_page); + echo $form->generate_hidden_field($name, $per_page); + echo $form->generate_hidden_field($name2, $lang->go); + echo "
\n"; + echo "

{$lang->confirm_proceed_rebuild}

\n"; + echo "
\n"; + echo ""; + echo "

\n"; + echo $form->generate_submit_button($lang->proceed, array('class' => 'button_yes', 'id' => 'proceed_button')); + echo "

\n"; + echo "
\n"; + + $form->end(); + + $page->output_footer(); + exit; + } +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_tools_recount_rebuild_start"); + + if($mybb->request_method == "post") + { + require_once MYBB_ROOT."inc/functions_rebuild.php"; + + if(!isset($mybb->input['page']) || $mybb->get_input('page', 1) < 1) + { + $mybb->input['page'] = 1; + } + + if(isset($mybb->input['do_rebuildforumcounters'])) + { + $plugins->run_hooks("admin_tools_recount_rebuild_forum_counters"); + + if($mybb->input['page'] == 1) + { + // Log admin action + log_admin_action("forum"); + } + if(!(int)$mybb->input['forumcounters']) + { + $mybb->input['forumcounters'] = 50; + } + + acp_rebuild_forum_counters(); + } + elseif(isset($mybb->input['do_rebuildthreadcounters'])) + { + $plugins->run_hooks("admin_tools_recount_rebuild_thread_counters"); + + if($mybb->input['page'] == 1) + { + // Log admin action + log_admin_action("thread"); + } + if(!(int)$mybb->input['threadcounters']) + { + $mybb->input['threadcounters'] = 500; + } + + acp_rebuild_thread_counters(); + } + elseif(isset($mybb->input['do_recountuserposts'])) + { + $plugins->run_hooks("admin_tools_recount_rebuild_user_posts"); + + if($mybb->input['page'] == 1) + { + // Log admin action + log_admin_action("userposts"); + } + if(!(int)$mybb->input['userposts']) + { + $mybb->input['userposts'] = 500; + } + + acp_recount_user_posts(); + } + elseif(isset($mybb->input['do_recountuserthreads'])) + { + $plugins->run_hooks("admin_tools_recount_rebuild_user_threads"); + + if($mybb->input['page'] == 1) + { + // Log admin action + log_admin_action("userthreads"); + } + if(!(int)$mybb->input['userthreads']) + { + $mybb->input['userthreads'] = 500; + } + + acp_recount_user_threads(); + } + elseif(isset($mybb->input['do_rebuildattachmentthumbs'])) + { + $plugins->run_hooks("admin_tools_recount_rebuild_attachment_thumbs"); + + if($mybb->input['page'] == 1) + { + // Log admin action + log_admin_action("attachmentthumbs"); + } + + if(!(int)$mybb->input['attachmentthumbs']) + { + $mybb->input['attachmentthumbs'] = 500; + } + + acp_rebuild_attachment_thumbnails(); + } + elseif(isset($mybb->input['do_recountreputation'])) + { + $plugins->run_hooks("admin_tools_recount_recount_reputation"); + + if($mybb->input['page'] == 1) + { + // Log admin action + log_admin_action("reputation"); + } + + if(!(int)$mybb->input['reputation']) + { + $mybb->input['reputation'] = 500; + } + + acp_recount_reputation(); + } + elseif(isset($mybb->input['do_recountwarning'])) + { + $plugins->run_hooks("admin_tools_recount_recount_warning"); + + if($mybb->input['page'] == 1) + { + // Log admin action + log_admin_action("warning"); + } + + if(!(int)$mybb->input['warning']) + { + $mybb->input['warning'] = 500; + } + + acp_recount_warning(); + } + elseif(isset($mybb->input['do_recountprivatemessages'])) + { + $plugins->run_hooks("admin_tools_recount_recount_private_messages"); + + if($mybb->input['page'] == 1) + { + // Log admin action + log_admin_action("privatemessages"); + } + + if(!(int)$mybb->input['privatemessages']) + { + $mybb->input['privatemessages'] = 500; + } + + acp_recount_private_messages(); + } + elseif(isset($mybb->input['do_recountreferral'])) + { + $plugins->run_hooks("admin_tools_recount_recount_referral"); + + if($mybb->input['page'] == 1) + { + // Log admin action + log_admin_action("referral"); + } + + if(!(int)$mybb->input['referral']) + { + $mybb->input['referral'] = 500; + } + + acp_recount_referrals(); + } + elseif(isset($mybb->input['do_recountthreadrating'])) + { + $plugins->run_hooks("admin_tools_recount_recount_thread_ratings"); + + if($mybb->input['page'] == 1) + { + // Log admin action + log_admin_action("threadrating"); + } + + if(!(int)$mybb->input['threadrating']) + { + $mybb->input['threadrating'] = 500; + } + + acp_recount_thread_ratings(); + } + elseif(isset($mybb->input['do_rebuildpollcounters'])) + { + $plugins->run_hooks("admin_tools_recount_rebuild_poll_counters"); + + if($mybb->input['page'] == 1) + { + // Log admin action + log_admin_action("poll"); + } + + if(!(int)$mybb->input['pollcounters']) + { + $mybb->input['pollcounters'] = 500; + } + + acp_rebuild_poll_counters(); + } + else + { + $plugins->run_hooks("admin_tools_recount_rebuild_stats"); + + $cache->update_stats(); + + // Log admin action + log_admin_action("stats"); + + flash_message($lang->success_rebuilt_forum_stats, 'success'); + admin_redirect("index.php?module=tools-recount_rebuild"); + } + } + + $page->output_header($lang->recount_rebuild); + + $sub_tabs['recount_rebuild'] = array( + 'title' => $lang->recount_rebuild, + 'link' => "index.php?module=tools-recount_rebuild", + 'description' => $lang->recount_rebuild_desc + ); + + $page->output_nav_tabs($sub_tabs, 'recount_rebuild'); + + $form = new Form("index.php?module=tools-recount_rebuild", "post"); + + $form_container = new FormContainer($lang->recount_rebuild); + $form_container->output_row_header($lang->name); + $form_container->output_row_header($lang->data_per_page, array('width' => 50)); + $form_container->output_row_header(" "); + + $form_container->output_cell("
{$lang->rebuild_forum_counters_desc}
"); + $form_container->output_cell($form->generate_numeric_field("forumcounters", 50, array('style' => 'width: 150px;'))); + $form_container->output_cell($form->generate_submit_button($lang->go, array("name" => "do_rebuildforumcounters"))); + $form_container->construct_row(); + + $form_container->output_cell("
{$lang->rebuild_thread_counters_desc}
"); + $form_container->output_cell($form->generate_numeric_field("threadcounters", 500, array('style' => 'width: 150px;'))); + $form_container->output_cell($form->generate_submit_button($lang->go, array("name" => "do_rebuildthreadcounters"))); + $form_container->construct_row(); + + $form_container->output_cell("
{$lang->rebuild_poll_counters_desc}
"); + $form_container->output_cell($form->generate_numeric_field("pollcounters", 500, array('style' => 'width: 150px;'))); + $form_container->output_cell($form->generate_submit_button($lang->go, array("name" => "do_rebuildpollcounters"))); + $form_container->construct_row(); + + $form_container->output_cell("
{$lang->recount_user_posts_desc}
"); + $form_container->output_cell($form->generate_numeric_field("userposts", 500, array('style' => 'width: 150px;'))); + $form_container->output_cell($form->generate_submit_button($lang->go, array("name" => "do_recountuserposts"))); + $form_container->construct_row(); + + $form_container->output_cell("
{$lang->recount_user_threads_desc}
"); + $form_container->output_cell($form->generate_numeric_field("userthreads", 500, array('style' => 'width: 150px;'))); + $form_container->output_cell($form->generate_submit_button($lang->go, array("name" => "do_recountuserthreads"))); + $form_container->construct_row(); + + $form_container->output_cell("
{$lang->rebuild_attachment_thumbs_desc}
"); + $form_container->output_cell($form->generate_numeric_field("attachmentthumbs", 20, array('style' => 'width: 150px;'))); + $form_container->output_cell($form->generate_submit_button($lang->go, array("name" => "do_rebuildattachmentthumbs"))); + $form_container->construct_row(); + + $form_container->output_cell("
{$lang->recount_stats_desc}
"); + $form_container->output_cell($lang->na); + $form_container->output_cell($form->generate_submit_button($lang->go, array("name" => "do_recountstats"))); + $form_container->construct_row(); + + $form_container->output_cell("
{$lang->recount_reputation_desc}
"); + $form_container->output_cell($form->generate_numeric_field("reputation", 500, array('style' => 'width: 150px;'))); + $form_container->output_cell($form->generate_submit_button($lang->go, array("name" => "do_recountreputation"))); + $form_container->construct_row(); + + $form_container->output_cell("
{$lang->recount_warning_desc}
"); + $form_container->output_cell($form->generate_numeric_field("warning", 500, array('style' => 'width: 150px;'))); + $form_container->output_cell($form->generate_submit_button($lang->go, array("name" => "do_recountwarning"))); + $form_container->construct_row(); + + $form_container->output_cell("
{$lang->recount_private_messages_desc}
"); + $form_container->output_cell($form->generate_numeric_field("privatemessages", 500, array('style' => 'width: 150px;'))); + $form_container->output_cell($form->generate_submit_button($lang->go, array("name" => "do_recountprivatemessages"))); + $form_container->construct_row(); + + $form_container->output_cell("
{$lang->recount_referrals_desc}
"); + $form_container->output_cell($form->generate_numeric_field("referral", 500, array('style' => 'width: 150px;'))); + $form_container->output_cell($form->generate_submit_button($lang->go, array("name" => "do_recountreferral"))); + $form_container->construct_row(); + + $form_container->output_cell("
{$lang->recount_thread_ratings_desc}
"); + $form_container->output_cell($form->generate_numeric_field("threadrating", 500, array('style' => 'width: 150px;'))); + $form_container->output_cell($form->generate_submit_button($lang->go, array("name" => "do_recountthreadrating"))); + $form_container->construct_row(); + + $plugins->run_hooks("admin_tools_recount_rebuild_output_list"); + + $form_container->end(); + + $form->end(); + + $page->output_footer(); +} + diff --git a/Upload/admin/modules/tools/spamlog.php b/Upload/admin/modules/tools/spamlog.php new file mode 100644 index 0000000..d6921d7 --- /dev/null +++ b/Upload/admin/modules/tools/spamlog.php @@ -0,0 +1,297 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->spam_logs, "index.php?module=tools-spamlog"); + +$sub_tabs['spam_logs'] = array( + 'title' => $lang->spam_logs, + 'link' => "index.php?module=tools-spamlog", + 'description' => $lang->spam_logs_desc +); +$sub_tabs['prune_spam_logs'] = array( + 'title' => $lang->prune_spam_logs, + 'link' => "index.php?module=tools-spamlog&action=prune", + 'description' => $lang->prune_spam_logs_desc +); + +$plugins->run_hooks("admin_tools_spamlog_begin"); + +if($mybb->input['action'] == 'prune') +{ + if(!is_super_admin($mybb->user['uid'])) + { + flash_message($lang->cannot_perform_action_super_admin_general, 'error'); + admin_redirect("index.php?module=tools-spamlog"); + } + + $plugins->run_hooks("admin_tools_spamlog_prune"); + + if($mybb->request_method == 'post') + { + $is_today = false; + if($mybb->input['older_than'] <= 0) + { + $is_today = true; + $mybb->input['older_than'] = 1; + } + $where = 'dateline < '.(TIME_NOW-((int)$mybb->input['older_than']*86400)); + + // Searching for entries in a specific module + if($mybb->input['filter_username']) + { + $where .= " AND username='".$db->escape_string($mybb->input['filter_username'])."'"; + } + + // Searching for entries in a specific module + if($mybb->input['filter_email']) + { + $where .= " AND email='".$db->escape_string($mybb->input['filter_email'])."'"; + } + + $query = $db->delete_query("spamlog", $where); + $num_deleted = $db->affected_rows(); + + $plugins->run_hooks("admin_tools_spamlog_prune_commit"); + + // Log admin action + log_admin_action($mybb->input['older_than'], $mybb->input['filter_username'], $mybb->input['filter_email'], $num_deleted); + + $success = $lang->success_pruned_spam_logs; + if($is_today == true && $num_deleted > 0) + { + $success .= ' '.$lang->note_logs_locked; + } + elseif($is_today == true && $num_deleted == 0) + { + flash_message($lang->note_logs_locked, 'error'); + admin_redirect('index.php?module=tools-spamlog'); + } + flash_message($success, 'success'); + admin_redirect('index.php?module=tools-spamlog'); + } + $page->add_breadcrumb_item($lang->prune_spam_logs, 'index.php?module=tools-spamlog&action=prune'); + $page->output_header($lang->prune_spam_logs); + $page->output_nav_tabs($sub_tabs, 'prune_spam_logs'); + + // Fetch filter options + $sortbysel[$mybb->input['sortby']] = 'selected="selected"'; + $ordersel[$mybb->input['order']] = 'selected="selected"'; + + $form = new Form("index.php?module=tools-spamlog&action=prune", "post"); + $form_container = new FormContainer($lang->prune_spam_logs); + $form_container->output_row($lang->spam_username, "", $form->generate_text_box('filter_username', $mybb->input['filter_username'], array('id' => 'filter_username')), 'filter_username'); + $form_container->output_row($lang->spam_email, "", $form->generate_text_box('filter_email', $mybb->input['filter_email'], array('id' => 'filter_email')), 'filter_email'); + if(!$mybb->input['older_than']) + { + $mybb->input['older_than'] = '30'; + } + $form_container->output_row($lang->date_range, "", $lang->older_than.$form->generate_numeric_field('older_than', $mybb->input['older_than'], array('id' => 'older_than', 'style' => 'width: 30px'))." {$lang->days}", 'older_than'); + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->prune_spam_logs); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_tools_spamlog_start"); + + $page->output_header($lang->spam_logs); + + $page->output_nav_tabs($sub_tabs, 'spam_logs'); + + $perpage = $mybb->get_input('perpage', 1); + if(!$perpage) + { + $perpage = 20; + } + + $where = 'WHERE 1=1'; + + // Searching for entries witha specific username + if($mybb->input['username']) + { + $where .= " AND l.username='".$db->escape_string($mybb->input['username'])."'"; + } + + // Searching for entries with a specific email + if($mybb->input['email'] > 0) + { + $where .= " AND l.email='".$db->escape_string($mybb->input['email'])."'"; + } + + // Searching for entries with a specific IP + if($mybb->input['email'] > 0) + { + $where .= " AND l.ipaddress='".$db->escape_binary(my_inet_pton($mybb->input['ipaddress']))."'"; + } + + // Order? + switch($mybb->input['sortby']) + { + case "username": + $sortby = "l.username"; + break; + case "email": + $sortby = "l.email"; + break; + case "ipaddress": + $sortby = "l.ipaddress"; + break; + default: + $sortby = "l.dateline"; + } + $order = $mybb->input['order']; + if($order != "asc") + { + $order = "desc"; + } + + // Pagination stuff + $sql = " + SELECT COUNT(sid) as count + FROM ".TABLE_PREFIX."spamlog + {$where}; + "; + $rescount = $db->fetch_field($query, "count"); + + // Figure out if we need to display multiple pages. + if($mybb->input['page'] != "last") + { + $pagecnt = $mybb->get_input('page', 1); + } + + $logcount = (int)$rescount; + $pages = $logcount / $perpage; + $pages = ceil($pages); + + if($mybb->input['page'] == "last") + { + $pagecnt = $pages; + } + + if($pagecnt > $pages) + { + $pagecnt = 1; + } + + if($pagecnt) + { + $start = ($pagecnt-1) * $perpage; + } + else + { + $start = 0; + $pagecnt = 1; + } + + // Build the base URL for pagination links + $url = 'index.php?module=tools-spamlog'; + + // The actual query + $sql = " + SELECT * FROM ".TABLE_PREFIX."spamlog l {$where} + ORDER BY {$sortby} {$order} + LIMIT {$start}, {$perpage} + "; + $query = $db->query($sql); + + + $table = new Table; + $table->construct_header($lang->spam_username, array('width' => '20%')); + $table->construct_header($lang->spam_email, array("class" => "align_center", 'width' => '20%')); + $table->construct_header($lang->spam_ip, array("class" => "align_center", 'width' => '20%')); + $table->construct_header($lang->spam_date, array("class" => "align_center", 'width' => '20%')); + $table->construct_header($lang->spam_confidence, array("class" => "align_center", 'width' => '20%')); + + while($row = $db->fetch_array($query)) + { + $username = htmlspecialchars_uni($row['username']); + $email = htmlspecialchars_uni($row['email']); + $ip_address = my_inet_ntop($db->unescape_binary($row['ipaddress'])); + + $dateline = ''; + if($row['dateline'] > 0) + { + $dateline = my_date('relative', $row['dateline']); + } + + $confidence = '0%'; + $data = @my_unserialize($row['data']); + if(is_array($data) && !empty($data)) + { + if(isset($data['confidence'])) + { + $confidence = (double)$data['confidence'].'%'; + } + } + + $table->construct_cell($username); + $table->construct_cell($email); + $table->construct_cell($ip_address); + $table->construct_cell($dateline); + $table->construct_cell($confidence); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_spam_logs, array("colspan" => "5")); + $table->construct_row(); + } + + $table->output($lang->spam_logs); + + // Do we need to construct the pagination? + if($rescount > $perpage) + { + echo draw_admin_pagination($pagecnt, $perpage, $rescount, "index.php?module=tools-modlog&perpage=$perpage&uid={$mybb->input['uid']}&fid={$mybb->input['fid']}&sortby={$mybb->input['sortby']}&order={$order}")."
"; + } + + // Fetch filter options + $sortbysel[$mybb->input['sortby']] = "selected=\"selected\""; + $ordersel[$mybb->input['order']] = "selected=\"selected\""; + + $sort_by = array( + 'dateline' => $lang->spam_date, + 'username' => $lang->spam_username, + 'email' => $lang->spam_email, + 'ipaddress' => $lang->spam_ip, + ); + + $order_array = array( + 'asc' => $lang->asc, + 'desc' => $lang->desc + ); + + $form = new Form("index.php?module=tools-spamlog", "post"); + $form_container = new FormContainer($lang->filter_spam_logs); + $form_container->output_row($lang->spam_username, "", $form->generate_text_box('username', $mybb->input['username'], array('id' => 'username')), 'suername'); + $form_container->output_row($lang->spam_email, "", $form->generate_text_box('email', $mybb->input['email'], array('id' => 'email')), 'email'); + $form_container->output_row($lang->spam_ip, "", $form->generate_text_box('ipaddress', $mybb->input['ipaddress'], array('id' => 'ipaddress')), 'ipaddress'); + $form_container->output_row($lang->sort_by, "", $form->generate_select_box('sortby', $sort_by, $mybb->input['sortby'], array('id' => 'sortby'))." {$lang->in} ".$form->generate_select_box('order', $order_array, $order, array('id' => 'order'))." {$lang->order}", 'order'); + $form_container->output_row($lang->results_per_page, "", $form->generate_numeric_field('perpage', $perpage, array('id' => 'perpage')), 'perpage'); + + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->filter_spam_logs); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/tools/statistics.php b/Upload/admin/modules/tools/statistics.php new file mode 100644 index 0000000..98d8f07 --- /dev/null +++ b/Upload/admin/modules/tools/statistics.php @@ -0,0 +1,273 @@ +
Please make sure IN_MYBB is defined."); +} + +if($mybb->input['action'] == "do_graph") +{ + $range = array( + 'start' => (int)$mybb->input['start'], + 'end' => (int)$mybb->input['end'] + ); + create_graph($mybb->input['type'], $range); + die; +} + +$page->add_breadcrumb_item($lang->statistics, "index.php?module=tools-statistics"); + +$sub_tabs['overall_statistics'] = array( + 'title' => $lang->overall_statistics, + 'link' => "index.php?module=tools-statistics", + 'description' => $lang->overall_statistics_desc +); + +$plugins->run_hooks("admin_tools_statistics_begin"); + +if(!$mybb->input['action']) +{ + $query = $db->simple_select("stats", "COUNT(*) as total"); + if($db->fetch_field($query, "total") == 0) + { + flash_message($lang->error_no_statistics_available_yet, 'error'); + admin_redirect("index.php?module=tools"); + } + + $per_page = 20; + + $plugins->run_hooks("admin_tools_statistics_overall_begin"); + + // Do we have date range criteria? + if($mybb->input['from_year']) + { + $start_dateline = mktime(0, 0, 0, (int)$mybb->input['from_month'], (int)$mybb->input['from_day'], (int)$mybb->input['from_year']); + $end_dateline = mktime(23, 59, 59, (int)$mybb->input['to_month'], (int)$mybb->input['to_day'], (int)$mybb->input['to_year']); + $range = "&start={$start_dateline}&end={$end_dateline}"; + } + + // Otherwise default to the last 30 days + if(!$mybb->input['from_year'] || $start_dateline > TIME_NOW || $end_dateline > mktime(23, 59, 59)) + { + $start_dateline = TIME_NOW-(60*60*24*30); + $end_dateline = TIME_NOW; + + list($mybb->input['from_day'], $mybb->input['from_month'], $mybb->input['from_year']) = explode('-', date('j-n-Y', $start_dateline)); + list($mybb->input['to_day'], $mybb->input['to_month'], $mybb->input['to_year']) = explode('-', date('j-n-Y', $end_dateline)); + + $range = "&start={$start_dateline}&end={$end_dateline}"; + } + + $last_dateline = 0; + + if($mybb->input['page'] && $mybb->input['page'] > 1) + { + $mybb->input['page'] = $mybb->get_input('page', 1); + $start = ($mybb->input['page']*$per_page)-$per_page; + } + else + { + $mybb->input['page'] = 1; + $start = 0; + } + + $query = $db->simple_select("stats", "*", "dateline >= '".(int)$start_dateline."' AND dateline <= '".(int)$end_dateline."'", array('order_by' => 'dateline', 'order_dir' => 'asc')); + + $stats = array(); + while($stat = $db->fetch_array($query)) + { + if($last_dateline) + { + $stat['change_users'] = ($stat['numusers'] - $stats[$last_dateline]['numusers']); + $stat['change_threads'] = ($stat['numthreads'] - $stats[$last_dateline]['numthreads']); + $stat['change_posts'] = ($stat['numposts'] - $stats[$last_dateline]['numposts']); + } + + $stats[$stat['dateline']] = $stat; + + $last_dateline = $stat['dateline']; + } + + if(empty($stats)) + { + flash_message($lang->error_no_results_found_for_criteria, 'error'); + admin_redirect("index.php?module=tools"); + } + + krsort($stats, SORT_NUMERIC); + + $page->add_breadcrumb_item($lang->overall_statistics, "index.php?module=tools-statistics"); + + $page->output_header($lang->statistics." - ".$lang->overall_statistics); + + $page->output_nav_tabs($sub_tabs, 'overall_statistics'); + + // Date range fields + $form = new Form("index.php?module=tools-statistics", "post", "overall"); + echo "
{$lang->date_range}\n"; + echo "{$lang->from} ".$form->generate_date_select('from', $mybb->input['from_day'], $mybb->input['from_month'], $mybb->input['from_year']); + echo " {$lang->to} ".$form->generate_date_select('to', $mybb->input['to_day'], $mybb->input['to_month'], $mybb->input['to_year']); + echo " ".$form->generate_submit_button($lang->view); + echo "
\n"; + $form->end(); + + echo "
{$lang->users}\n"; + echo "\n"; + echo "
\n"; + + echo "
{$lang->threads}\n"; + echo "\n"; + echo "
\n"; + + echo "
{$lang->posts}\n"; + echo "\n"; + echo "
\n"; + + $total_rows = count($stats); + + $table = new Table; + $table->construct_header($lang->date); + $table->construct_header($lang->users); + $table->construct_header($lang->threads); + $table->construct_header($lang->posts); + $query = $db->simple_select("stats", "*", "dateline >= '".(int)$start_dateline."' AND dateline <= '".(int)$end_dateline."'", array('order_by' => 'dateline', 'order_dir' => 'desc', 'limit_start' => $start, 'limit' => $per_page)); + while($stat = $db->fetch_array($query)) + { + $table->construct_cell("".date($mybb->settings['dateformat'], $stat['dateline']).""); + $table->construct_cell(my_number_format($stat['numusers'])." ".generate_growth_string($stats[$stat['dateline']]['change_users']).""); + $table->construct_cell(my_number_format($stat['numthreads'])." ".generate_growth_string($stats[$stat['dateline']]['change_threads']).""); + $table->construct_cell(my_number_format($stat['numposts'])." ".generate_growth_string($stats[$stat['dateline']]['change_posts']).""); + $table->construct_row(); + } + $table->output($lang->overall_statistics); + + $url_range = "&from_month=".(int)$mybb->input['from_month']."&from_day=".(int)$mybb->input['from_day']."&from_year=".(int)$mybb->input['from_year']; + $url_range .= "&to_month=".(int)$mybb->input['to_month']."&to_day=".(int)$mybb->input['to_day']."&to_year=".(int)$mybb->input['to_year']; + + echo draw_admin_pagination($mybb->input['page'], $per_page, $total_rows, "index.php?module=tools-statistics{$url_range}&page={page}"); + + $page->output_footer(); +} + +function generate_growth_string($number) +{ + global $lang, $cp_style; + + if($number === null) + { + return ""; + } + + $number = (int)$number; + $friendly_number = my_number_format(abs($number)); + + if($number > 0) + { + $growth_string = "(\"{$lang-increase}\" title=\"{$lang->increase}\" style=\"vertical-align: middle; margin-top: -2px;\" /> {$friendly_number})"; + } + elseif($number == 0) + { + $growth_string = "(\"{$lang-no_change}\" title=\"{$lang->no_change}\" style=\"vertical-align: middle; margin-top: -2px;\" /> {$friendly_number})"; + } + else + { + $growth_string = "(\"{$lang-decrease}\" title=\"{$lang->decrease}\" style=\"vertical-align: middle; margin-top: -2px;\" /> {$friendly_number})"; + } + + return $growth_string; +} + +function create_graph($type, $range=null) +{ + global $db; + + // Do we have date range criteria? + if($range['end'] || $range['start']) + { + $start = (int)$range['start']; + $end = (int)$range['end']; + } + // Otherwise default to the last 30 days + else + { + $start = TIME_NOW-(60*60*24*30); + $end = TIME_NOW; + } + + $allowed_types = array('users', 'threads', 'posts'); + if(!in_array($type, $allowed_types)) + { + die; + } + + require_once MYBB_ROOT.'inc/class_graph.php'; + + $points = $stats = $datelines = array(); + if($start == 0) + { + $query = $db->simple_select("stats", "dateline,num{$type}", "dateline <= '".(int)$end."'", array('order_by' => 'dateline', 'order_dir' => 'desc', 'limit' => 2)); + while($stat = $db->fetch_array($query)) + { + $stats[] = $stat['num'.$type]; + $datelines[] = $stat['dateline']; + $x_labels[] = date("m/j", $stat['dateline']); + } + $points[$datelines[0]] = 0; + $points[$datelines[1]] = $stats[0]-$stats[1]; + ksort($points, SORT_NUMERIC); + } + elseif($end == 0) + { + $query = $db->simple_select("stats", "dateline,num{$type}", "dateline >= '".(int)$start."'", array('order_by' => 'dateline', 'order_dir' => 'asc', 'limit' => 2)); + while($stat = $db->fetch_array($query)) + { + $stats[] = $stat['num'.$type]; + $datelines[] = $stat['dateline']; + $x_labels[] = date("m/j", $stat['dateline']); + } + $points[$datelines[0]] = 0; + $points[$datelines[1]] = $stats[1]-$stats[0]; + ksort($points, SORT_NUMERIC); + } + else + { + $query = $db->simple_select("stats", "dateline,num{$type}", "dateline >= '".(int)$start."' AND dateline <= '".(int)$end."'", array('order_by' => 'dateline', 'order_dir' => 'asc')); + while($stat = $db->fetch_array($query)) + { + $points[$stat['dateline']] = $stat['num'.$type]; + $datelines[] = $stat['dateline']; + $x_labels[] = date("m/j", $stat['dateline']); + } + } + + sort($datelines, SORT_NUMERIC); + + // Find our year(s) label + $start_year = date('Y', $datelines[0]); + $last_year = date('Y', $datelines[count($datelines)-1]); + if(($last_year - $start_year) == 0) + { + $bottom_label = $start_year; + } + else + { + $bottom_label = $start_year." - ".$last_year; + } + + // Create the graph outline + $graph = new Graph(); + $graph->add_points(array_values($points)); + $graph->add_x_labels($x_labels); + $graph->set_bottom_label($bottom_label); + $graph->render(); + $graph->output(); +} diff --git a/Upload/admin/modules/tools/system_health.php b/Upload/admin/modules/tools/system_health.php new file mode 100644 index 0000000..09121a1 --- /dev/null +++ b/Upload/admin/modules/tools/system_health.php @@ -0,0 +1,971 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->system_health, "index.php?module=tools-system_health"); + +$sub_tabs['system_health'] = array( + 'title' => $lang->system_health, + 'link' => "index.php?module=tools-system_health", + 'description' => $lang->system_health_desc +); + +$sub_tabs['utf8_conversion'] = array( + 'title' => $lang->utf8_conversion, + 'link' => "index.php?module=tools-system_health&action=utf8_conversion", + 'description' => $lang->utf8_conversion_desc2 +); + +$sub_tabs['template_check'] = array( + 'title' => $lang->check_templates, + 'link' => "index.php?module=tools-system_health&action=check_templates", + 'description' => $lang->check_templates_desc +); + +$plugins->run_hooks("admin_tools_system_health_begin"); + +if($mybb->input['action'] == "do_check_templates" && $mybb->request_method == "post") +{ + $query = $db->simple_select("templates", "*", "", array("order_by" => "sid, title", "order_dir" => "ASC")); + + if(!$db->num_rows($query)) + { + flash_message($lang->error_invalid_input, 'error'); + admin_redirect("index.php?module=tools-system_health"); + } + + $plugins->run_hooks("admin_tools_system_health_template_do_check_start"); + + $t_cache = array(); + while($template = $db->fetch_array($query)) + { + if(check_template($template['template']) == true) + { + $t_cache[$template['sid']][] = $template; + } + } + + if(empty($t_cache)) + { + flash_message($lang->success_templates_checked, 'success'); + admin_redirect("index.php?module=tools-system_health"); + } + + $plugins->run_hooks("admin_tools_system_health_template_do_check"); + + $page->add_breadcrumb_item($lang->check_templates); + $page->output_header($lang->check_templates); + + $page->output_nav_tabs($sub_tabs, 'template_check'); + $page->output_inline_error(array($lang->check_templates_info_desc)); + + $templatesets = array( + -2 => array( + "title" => "MyBB Master Templates" + ) + ); + $query = $db->simple_select("templatesets", "*"); + while($set = $db->fetch_array($query)) + { + $templatesets[$set['sid']] = $set; + } + + $count = 0; + foreach($t_cache as $sid => $templates) + { + if(!$done_set[$sid]) + { + $table = new Table(); + $table->construct_header($templatesets[$sid]['title'], array("colspan" => 2)); + + $done_set[$sid] = 1; + ++$count; + } + + if($sid == -2) + { + // Some cheeky clown has altered the master templates! + $table->construct_cell($lang->error_master_templates_altered, array("colspan" => 2)); + $table->construct_row(); + } + + foreach($templates as $template) + { + if($sid == -2) + { + $table->construct_cell($template['title'], array('colspan' => 2)); + } + else + { + $popup = new PopupMenu("template_{$template['tid']}", $lang->options); + $popup->add_item($lang->full_edit, "index.php?module=style-templates&action=edit_template&title=".urlencode($template['title'])."&sid={$sid}"); + + $table->construct_cell("{$template['title']}", array('width' => '80%')); + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + } + + $table->construct_row(); + } + + if($done_set[$sid] && !$done_output[$sid]) + { + $done_output[$sid] = 1; + if($count == 1) + { + $table->output($lang->check_templates); + } + else + { + $table->output(); + } + } + } + + $page->output_footer(); +} + +if($mybb->input['action'] == "check_templates") +{ + $page->add_breadcrumb_item($lang->check_templates); + $page->output_header($lang->check_templates); + + $plugins->run_hooks("admin_tools_system_health_template_check"); + + $page->output_nav_tabs($sub_tabs, 'template_check'); + + if($errors) + { + $page->output_inline_error($errors); + } + + $form = new Form("index.php?module=tools-system_health", "post", "check_set"); + echo $form->generate_hidden_field("action", "do_check_templates"); + + $form_container = new FormContainer($lang->check_templates); + $form_container->output_row($lang->check_templates_title, "", $lang->check_templates_info); + $form_container->end(); + + $buttons = array(); + $buttons[] = $form->generate_submit_button($lang->proceed); + + $form->output_submit_wrapper($buttons); + + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "utf8_conversion") +{ + if($db->type == "sqlite" || $db->type == "pgsql") + { + flash_message($lang->error_not_supported, 'error'); + admin_redirect("index.php?module=tools-system_health"); + } + + $plugins->run_hooks("admin_tools_system_health_utf8_conversion"); + + if($mybb->request_method == "post" || ($mybb->input['do'] == "all" && !empty($mybb->input['table']))) + { + if(!empty($mybb->input['mb4']) && version_compare($db->get_version(), '5.5.3', '<')) + { + flash_message($lang->error_utf8mb4_version, 'error'); + admin_redirect("index.php?module=tools-system_health&action=utf8_conversion"); + } + @set_time_limit(0); + + $old_table_prefix = $db->table_prefix; + $db->set_table_prefix(''); + + if(!$db->table_exists($db->escape_string($mybb->input['table']))) + { + $db->set_table_prefix($old_table_prefix); + flash_message($lang->error_invalid_table, 'error'); + admin_redirect("index.php?module=tools-system_health&action=utf8_conversion"); + } + + $db->set_table_prefix($old_table_prefix); + + $page->add_breadcrumb_item($lang->utf8_conversion, "index.php?module=tools-system_health&action=utf8_conversion"); + + $page->output_header($lang->system_health." - ".$lang->utf8_conversion); + + $sub_tabs['system_health'] = array( + 'title' => $lang->system_health, + 'link' => "index.php?module=tools-system_health", + 'description' => $lang->system_health_desc + ); + + $sub_tabs['utf8_conversion'] = array( + 'title' => $lang->utf8_conversion, + 'link' => "index.php?module=tools-system_health&action=utf8_conversion", + 'description' => $lang->utf8_conversion_desc2 + ); + + $page->output_nav_tabs($sub_tabs, 'utf8_conversion'); + + $old_table_prefix = $db->table_prefix; + $db->set_table_prefix(''); + + $table = new Table; + + $table1 = $db->show_create_table($db->escape_string($mybb->input['table'])); + preg_match("#CHARSET=([a-zA-Z0-9_]+)\s?#i", $table1, $matches); + $charset = $matches[1]; + + if(!empty($mybb->input['mb4'])) + { + $table->construct_cell("".$lang->sprintf($lang->converting_to_utf8mb4, $mybb->input['table'], $charset).""); + } + else + { + $table->construct_cell("".$lang->sprintf($lang->converting_to_utf8, $mybb->input['table'], $charset).""); + } + $table->construct_row(); + + $table->construct_cell($lang->please_wait); + $table->construct_row(); + + $table->output($converting_table." {$mybb->input['table']}"); + + $db->set_table_prefix($old_table_prefix); + + $page->output_footer(false); + + $old_table_prefix = $db->table_prefix; + $db->set_table_prefix(''); + + flush(); + + $types = array( + 'text' => 'blob', + 'mediumtext' => 'mediumblob', + 'longtext' => 'longblob', + 'char' => 'varbinary', + 'varchar' => 'varbinary', + 'tinytext' => 'tinyblob' + ); + + $blob_types = array( 'blob', 'tinyblob', 'mediumblog', 'longblob', 'text', 'tinytext', 'mediumtext', 'longtext' ); + + // Get next table in list + $convert_to_binary = ''; + $convert_to_utf8 = ''; + $comma = ''; + + if(!empty($mybb->input['mb4'])) + { + $character_set = 'utf8mb4'; + $collation = 'utf8mb4_general_ci'; + } + else + { + $character_set = 'utf8'; + $collation = 'utf8_general_ci'; + } + + // Set table default charset + $db->write_query("ALTER TABLE {$mybb->input['table']} DEFAULT CHARACTER SET {$character_set} COLLATE {$collation}"); + + // Fetch any fulltext keys + if($db->supports_fulltext($mybb->input['table'])) + { + $table_structure = $db->show_create_table($mybb->input['table']); + switch($db->type) + { + case "mysql": + case "mysqli": + preg_match_all("#FULLTEXT KEY `?([a-zA-Z0-9_]+)`? \(([a-zA-Z0-9_`,']+)\)#i", $table_structure, $matches); + if(is_array($matches)) + { + foreach($matches[0] as $key => $matched) + { + $db->write_query("ALTER TABLE {$mybb->input['table']} DROP INDEX {$matches[1][$key]}"); + $fulltext_to_create[$matches[1][$key]] = $matches[2][$key]; + } + } + } + } + + // Find out which columns need converting and build SQL statements + $query = $db->query("SHOW FULL COLUMNS FROM {$mybb->input['table']}"); + while($column = $db->fetch_array($query)) + { + list($type) = explode('(', $column['Type']); + if(array_key_exists($type, $types)) + { + // Build the actual strings for converting the columns + $names = "CHANGE `{$column['Field']}` `{$column['Field']}` "; + + if(($db->type == 'mysql' || $db->type == 'mysqli') && in_array($type, $blob_types)) + { + if($column['Null'] == 'YES') + { + $attributes = 'NULL'; + } + else + { + $attributes = 'NOT NULL'; + } + } + else + { + $attributes = " DEFAULT "; + if($column['Default'] == 'NULL') + { + $attributes .= "NULL "; + } + else + { + $attributes .= "'".$db->escape_string($column['Default'])."' "; + + if($column['Null'] == 'YES') + { + $attributes .= 'NULL'; + } + else + { + $attributes .= 'NOT NULL'; + } + } + } + + $convert_to_binary .= $comma.$names.preg_replace('/'.$type.'/i', $types[$type], $column['Type']).' '.$attributes; + $convert_to_utf8 .= "{$comma}{$names}{$column['Type']} CHARACTER SET {$character_set} COLLATE {$collation} {$attributes}"; + + $comma = $lang->comma; + } + } + + if(!empty($convert_to_binary)) + { + // This converts the columns to UTF-8 while also doing the same for data + $db->write_query("ALTER TABLE {$mybb->input['table']} {$convert_to_binary}"); + $db->write_query("ALTER TABLE {$mybb->input['table']} {$convert_to_utf8}"); + } + + // Any fulltext indexes to recreate? + if(is_array($fulltext_to_create)) + { + foreach($fulltext_to_create as $name => $fields) + { + $db->create_fulltext_index($mybb->input['table'], $fields, $name); + } + } + + $db->set_table_prefix($old_table_prefix); + + $plugins->run_hooks("admin_tools_system_health_utf8_conversion_commit"); + + // Log admin action + log_admin_action($mybb->input['table']); + + flash_message($lang->sprintf($lang->success_table_converted, $mybb->input['table']), 'success'); + + if($mybb->input['do'] == "all") + { + $old_table_prefix = $db->table_prefix; + $db->set_table_prefix(''); + + $tables = $db->list_tables($mybb->config['database']['database']); + foreach($tables as $key => $tablename) + { + if(substr($tablename, 0, strlen(TABLE_PREFIX)) == TABLE_PREFIX) + { + $table = $db->show_create_table($tablename); + preg_match("#CHARSET=([a-zA-Z0-9_]+)\s?#i", $table, $matches); + if(empty($mybb->input['mb4']) && (fetch_iconv_encoding($matches[1]) == 'utf-8' || $matches[1] == 'utf8mb4') && $mybb->input['table'] != $tablename) + { + continue; + } + elseif(!empty($mybb->input['mb4']) && fetch_iconv_encoding($matches[1]) != 'utf-8' && $mybb->input['table'] != $tablename) + { + continue; + } + + $mybb_tables[$key] = $tablename; + } + } + + asort($mybb_tables); + reset($mybb_tables); + + $is_next = false; + $nexttable = ""; + + foreach($mybb_tables as $key => $tablename) + { + if($is_next == true) + { + $nexttable = $tablename; + break; + } + else if($mybb->input['table'] == $tablename) + { + $is_next = true; + } + } + + $db->set_table_prefix($old_table_prefix); + + if($nexttable) + { + $nexttable = $db->escape_string($nexttable); + $mb4 = ''; + if(!empty($mybb->input['mb4'])) + { + $mb4 = "&mb4=1"; + } + admin_redirect("index.php?module=tools-system_health&action=utf8_conversion&do=all&table={$nexttable}{$mb4}"); + exit; + } + } + + admin_redirect("index.php?module=tools-system_health&action=utf8_conversion"); + + exit; + } + + if($mybb->input['table'] || $mybb->input['do'] == "all") + { + if(!empty($mybb->input['mb4']) && version_compare($db->get_version(), '5.5.3', '<')) + { + flash_message($lang->error_utf8mb4_version, 'error'); + admin_redirect("index.php?module=tools-system_health&action=utf8_conversion"); + } + + $old_table_prefix = $db->table_prefix; + $db->set_table_prefix(''); + + if($mybb->input['do'] != "all" && !$db->table_exists($db->escape_string($mybb->input['table']))) + { + $db->set_table_prefix($old_table_prefix); + flash_message($lang->error_invalid_table, 'error'); + admin_redirect("index.php?module=tools-system_health&action=utf8_conversion"); + } + + if($mybb->input['do'] == "all") + { + $tables = $db->list_tables($mybb->config['database']['database']); + foreach($tables as $key => $tablename) + { + if(substr($tablename, 0, strlen(TABLE_PREFIX)) == TABLE_PREFIX) + { + $table = $db->show_create_table($tablename); + preg_match("#CHARSET=([a-zA-Z0-9_]+)\s?#i", $table, $matches); + if(empty($mybb->input['mb4']) && (fetch_iconv_encoding($matches[1]) == 'utf-8' || $matches[1] == 'utf8mb4')) + { + continue; + } + elseif(!empty($mybb->input['mb4']) && fetch_iconv_encoding($matches[1]) != 'utf-8') + { + continue; + } + $mybb_tables[$key] = $tablename; + } + } + + if(is_array($mybb_tables)) + { + asort($mybb_tables); + reset($mybb_tables); + $nexttable = current($mybb_tables); + $table = $db->show_create_table($db->escape_string($nexttable)); + $mybb->input['table'] = $nexttable; + } + else + { + $db->set_table_prefix($old_table_prefix); + flash_message($lang->success_all_tables_already_converted, 'success'); + admin_redirect("index.php?module=tools-system_health"); + } + } + else + { + $table = $db->show_create_table($db->escape_string($mybb->input['table'])); + } + + $page->add_breadcrumb_item($lang->utf8_conversion, "index.php?module=tools-system_health&action=utf8_conversion"); + + $db->set_table_prefix($old_table_prefix); + + $page->output_header($lang->system_health." - ".$lang->utf8_conversion); + + $sub_tabs['system_health'] = array( + 'title' => $lang->system_health, + 'link' => "index.php?module=tools-system_health", + 'description' => $lang->system_health_desc + ); + + $sub_tabs['utf8_conversion'] = array( + 'title' => $lang->utf8_conversion, + 'link' => "index.php?module=tools-system_health&action=utf8_conversion", + 'description' => $lang->utf8_conversion_desc2 + ); + + $page->output_nav_tabs($sub_tabs, 'utf8_conversion'); + + $old_table_prefix = $db->table_prefix; + $db->set_table_prefix(''); + + preg_match("#CHARSET=([a-zA-Z0-9_]+)\s?#i", $table, $matches); + $charset = $matches[1]; + + $mb4 = ''; + if(!empty($mybb->input['mb4'])) + { + $mb4 = "&mb4=1"; + } + + $form = new Form("index.php?module=tools-system_health&action=utf8_conversion{$mb4}", "post", "utf8_conversion"); + echo $form->generate_hidden_field("table", $mybb->input['table']); + + if($mybb->input['do'] == "all") + { + echo $form->generate_hidden_field("do", "all"); + } + + $table = new Table; + + if(!empty($mybb->input['mb4'])) + { + $table->construct_cell("".$lang->sprintf($lang->convert_all_to_utf8mb4, $charset).""); + $lang->notice_process_long_time .= "

{$lang->notice_mb4_warning}"; + } + else + { + if($mybb->input['do'] == "all") + { + $table->construct_cell("".$lang->sprintf($lang->convert_all_to_utf, $charset).""); + } + else + { + $table->construct_cell("".$lang->sprintf($lang->convert_to_utf8, $mybb->input['table'], $charset).""); + } + } + + $table->construct_row(); + + $table->construct_cell($lang->notice_process_long_time); + $table->construct_row(); + + if($mybb->input['do'] == "all") + { + $table->output($lang->convert_tables); + $buttons[] = $form->generate_submit_button($lang->convert_database_tables); + } + else + { + $table->output($lang->convert_table.": {$mybb->input['table']}"); + $buttons[] = $form->generate_submit_button($lang->convert_database_table); + } + + $form->output_submit_wrapper($buttons); + + $form->end(); + + $db->set_table_prefix($old_table_prefix); + + $page->output_footer(); + + exit; + } + + if(!$mybb->config['database']['encoding']) + { + flash_message($lang->error_db_encoding_not_set, 'error'); + admin_redirect("index.php?module=tools-system_health"); + } + + $tables = $db->list_tables($mybb->config['database']['database']); + + $old_table_prefix = $db->table_prefix; + $db->set_table_prefix(''); + + $encodings = array(); + + foreach($tables as $key => $tablename) + { + if(substr($tablename, 0, strlen($old_table_prefix)) == $old_table_prefix) + { + $table = $db->show_create_table($tablename); + preg_match("#CHARSET=([a-zA-Z0-9_]+)\s?#i", $table, $matches); + $encodings[$key] = fetch_iconv_encoding($matches[1]); + $mybb_tables[$key] = $tablename; + } + } + + $db->set_table_prefix($old_table_prefix); + + $page->add_breadcrumb_item($lang->utf8_conversion, "index.php?module=tools-system_health&action=utf8_conversion"); + + $page->output_header($lang->system_health." - ".$lang->utf8_conversion); + + $page->output_nav_tabs($sub_tabs, 'utf8_conversion'); + + asort($mybb_tables); + + $unique = array_unique($encodings); + + $convert_utf8 = $convert_utf8mb4 = false; + foreach($unique as $encoding) + { + if($encoding == 'utf-8') + { + $convert_utf8mb4 = true; + } + elseif($encoding != 'utf8mb4') + { + $convert_utf8 = true; + } + } + + if(count($unique) > 1) + { + $page->output_error("

{$lang->warning_multiple_encodings}

"); + } + + if(in_array('utf8mb4', $unique) && $mybb->config['database']['encoding'] != 'utf8mb4') + { + $page->output_error("

{$lang->warning_utf8mb4_config}

"); + } + + $table = new Table; + $table->construct_header($lang->table); + $table->construct_header($lang->status_utf8, array("class" => "align_center")); + $table->construct_header($lang->status_utf8mb4, array("class" => "align_center")); + + $all_utf8 = $all_utf8mb4 = '-'; + if($convert_utf8) + { + $all_utf8 = "{$lang->convert_all}"; + } + if($convert_utf8mb4) + { + $all_utf8mb4 = "{$lang->convert_all}"; + } + $table->construct_cell("{$lang->all_tables}"); + $table->construct_cell($all_utf8, array("class" => "align_center", 'width' => '15%')); + $table->construct_cell($all_utf8mb4, array("class" => "align_center", 'width' => '25%')); + $table->construct_row(); + + $db_version = $db->get_version(); + + foreach($mybb_tables as $key => $tablename) + { + if($encodings[$key] != 'utf-8' && $encodings[$key] != 'utf8mb4') + { + $status = "style}/images/icons/cross.png) no-repeat; padding-left: 20px;\">{$lang->convert_now}"; + } + else + { + $status = "style}/images/icons/tick.png\" alt=\"{$lang->ok}\" />"; + } + if(version_compare($db_version, '5.5.3', '<')) + { + $utf8mb4 = $lang->not_available; + } + elseif($encodings[$key] == 'utf8mb4') + { + $utf8mb4 = "style}/images/icons/tick.png\" alt=\"{$lang->ok}\" />"; + } + elseif($encodings[$key] == 'utf-8') + { + $utf8mb4 = "style}/images/icons/cross.png) no-repeat; padding-left: 20px;\">{$lang->convert_now}"; + } + else + { + $utf8mb4 = "-"; + } + $table->construct_cell("{$tablename}"); + $table->construct_cell($status, array("class" => "align_center", 'width' => '15%')); + $table->construct_cell($utf8mb4, array("class" => "align_center", 'width' => '25%')); + $table->construct_row(); + } + + $table->output("
{$lang->utf8_conversion}
"); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $page->output_header($lang->system_health); + + $plugins->run_hooks("admin_tools_system_health_start"); + + $page->output_nav_tabs($sub_tabs, 'system_health'); + + $table = new Table; + $table->construct_header($lang->totals, array("colspan" => 2)); + $table->construct_header($lang->attachments, array("colspan" => 2)); + + $query = $db->simple_select("attachments", "COUNT(*) AS numattachs, SUM(filesize) as spaceused, SUM(downloads*filesize) as bandwidthused", "visible='1' AND pid > '0'"); + $attachs = $db->fetch_array($query); + + $table->construct_cell("{$lang->total_database_size}", array('width' => '25%')); + $table->construct_cell(get_friendly_size($db->fetch_size()), array('width' => '25%')); + $table->construct_cell("{$lang->attachment_space_used}", array('width' => '200')); + $table->construct_cell(get_friendly_size((int)$attachs['spaceused']), array('width' => '200')); + $table->construct_row(); + + if($attachs['spaceused'] > 0) + { + $attach_average_size = round($attachs['spaceused']/$attachs['numattachs']); + $bandwidth_average_usage = round($attachs['bandwidthused']); + } + else + { + $attach_average_size = 0; + $bandwidth_average_usage = 0; + } + + $table->construct_cell("{$lang->total_cache_size}", array('width' => '25%')); + $table->construct_cell(get_friendly_size($cache->size_of()), array('width' => '25%')); + $table->construct_cell("{$lang->estimated_attachment_bandwidth_usage}", array('width' => '25%')); + $table->construct_cell(get_friendly_size($bandwidth_average_usage), array('width' => '25%')); + $table->construct_row(); + + + $table->construct_cell("{$lang->max_upload_post_size}", array('width' => '200')); + $table->construct_cell(@ini_get('upload_max_filesize').' / '.@ini_get('post_max_size'), array('width' => '200')); + $table->construct_cell("{$lang->average_attachment_size}", array('width' => '25%')); + $table->construct_cell(get_friendly_size($attach_average_size), array('width' => '25%')); + $table->construct_row(); + + $table->output($lang->stats); + + $table->construct_header($lang->task); + $table->construct_header($lang->run_time, array("width" => 200, "class" => "align_center")); + + $task_cache = $cache->read("tasks"); + $nextrun = $task_cache['nextrun']; + + $query = $db->simple_select("tasks", "*", "nextrun >= '{$nextrun}' AND enabled='1'", array("order_by" => "nextrun", "order_dir" => "asc", 'limit' => 3)); + while($task = $db->fetch_array($query)) + { + $task['title'] = htmlspecialchars_uni($task['title']); + $next_run = date($mybb->settings['dateformat'], $task['nextrun']).", ".date($mybb->settings['timeformat'], $task['nextrun']); + $table->construct_cell("{$task['title']}"); + $table->construct_cell($next_run, array("class" => "align_center")); + + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_tasks, array('colspan' => 2)); + $table->construct_row(); + } + + $table->output($lang->next_3_tasks); + + if(isset($mybb->admin['permissions']['tools']['backupdb']) && $mybb->admin['permissions']['tools']['backupdb'] == 1) + { + $backups = array(); + $dir = MYBB_ADMIN_DIR.'backups/'; + $handle = opendir($dir); + while(($file = readdir($handle)) !== false) + { + if(filetype(MYBB_ADMIN_DIR.'backups/'.$file) == 'file') + { + $ext = get_extension($file); + if($ext == 'gz' || $ext == 'sql') + { + $backups[@filemtime(MYBB_ADMIN_DIR.'backups/'.$file)] = array( + "file" => $file, + "time" => @filemtime(MYBB_ADMIN_DIR.'backups/'.$file), + "type" => $ext + ); + } + } + } + + $count = count($backups); + krsort($backups); + + $table = new Table; + $table->construct_header($lang->name); + $table->construct_header($lang->backup_time, array("width" => 200, "class" => "align_center")); + + $backupscnt = 0; + foreach($backups as $backup) + { + ++$backupscnt; + + if($backupscnt == 4) + { + break; + } + + $time = "-"; + if($backup['time']) + { + $time = my_date('relative', $backup['time']); + } + + $table->construct_cell("{$backup['file']}"); + $table->construct_cell($time, array("class" => "align_center")); + $table->construct_row(); + } + + if($count == 0) + { + $table->construct_cell($lang->no_backups, array('colspan' => 2)); + $table->construct_row(); + } + + $table->output($lang->existing_db_backups); + } + + if(is_writable(MYBB_ROOT.'inc/settings.php')) + { + $message_settings = "{$lang->writable}"; + } + else + { + $message_settings = "{$lang->not_writable}
{$lang->please_chmod_777}"; + ++$errors; + } + + if(is_writable(MYBB_ROOT.'inc/config.php')) + { + $message_config = "{$lang->writable}"; + } + else + { + $message_config = "{$lang->not_writable}
{$lang->please_chmod_777}"; + ++$errors; + } + + if(is_writable('.'.$mybb->settings['uploadspath'])) + { + $message_upload = "{$lang->writable}"; + } + else + { + $message_upload = "{$lang->not_writable}
{$lang->please_chmod_777}"; + ++$errors; + } + + if(is_writable('../'.$mybb->settings['avataruploadpath'])) + { + $message_avatar = "{$lang->writable}"; + } + else + { + $message_avatar = "{$lang->not_writable}
{$lang->please_chmod_777}"; + ++$errors; + } + + if(is_writable(MYBB_ROOT.'inc/languages/')) + { + $message_language = "{$lang->writable}"; + } + else + { + $message_language = "{$lang->not_writable}
{$lang->please_chmod_777}"; + ++$errors; + } + + if(is_writable(MYBB_ROOT.$config['admin_dir'].'/backups/')) + { + $message_backup = "{$lang->writable}"; + } + else + { + $message_backup = "{$lang->not_writable}
{$lang->please_chmod_777}"; + ++$errors; + } + + if(is_writable(MYBB_ROOT.'/cache/')) + { + $message_cache = "{$lang->writable}"; + } + else + { + $message_cache = "{$lang->not_writable}
{$lang->please_chmod_777}"; + ++$errors; + } + + if(is_writable(MYBB_ROOT.'/cache/themes/')) + { + $message_themes = "{$lang->writable}"; + } + else + { + $message_themes = "{$lang->not_writable}
{$lang->please_chmod_777}"; + ++$errors; + } + + if($errors) + { + $page->output_error("

{$errors} {$lang->error_chmod} {$lang->chmod_info} MyBB Docs.

"); + } + else + { + $page->output_success("

{$lang->success_chmod}

"); + } + + $table = new Table; + $table->construct_header($lang->file); + $table->construct_header($lang->location, array("colspan" => 2, 'width' => 250)); + + $table->construct_cell("{$lang->config_file}"); + $table->construct_cell("./inc/config.php"); + $table->construct_cell($message_config); + $table->construct_row(); + + $table->construct_cell("{$lang->settings_file}"); + $table->construct_cell("./inc/settings.php"); + $table->construct_cell($message_settings); + $table->construct_row(); + + $table->construct_cell("{$lang->file_upload_dir}"); + $table->construct_cell($mybb->settings['uploadspath']); + $table->construct_cell($message_upload); + $table->construct_row(); + + $table->construct_cell("{$lang->avatar_upload_dir}"); + $table->construct_cell($mybb->settings['avataruploadpath']); + $table->construct_cell($message_avatar); + $table->construct_row(); + + $table->construct_cell("{$lang->language_files}"); + $table->construct_cell("./inc/languages"); + $table->construct_cell($message_language); + $table->construct_row(); + + $table->construct_cell("{$lang->backup_dir}"); + $table->construct_cell('./'.$config['admin_dir'].'/backups'); + $table->construct_cell($message_backup); + $table->construct_row(); + + $table->construct_cell("{$lang->cache_dir}"); + $table->construct_cell('./cache'); + $table->construct_cell($message_cache); + $table->construct_row(); + + $table->construct_cell("{$lang->themes_dir}"); + $table->construct_cell('./cache/themes'); + $table->construct_cell($message_themes); + $table->construct_row(); + + $plugins->run_hooks("admin_tools_system_health_output_chmod_list"); + + $table->output($lang->chmod_files_and_dirs); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/tools/tasks.php b/Upload/admin/modules/tools/tasks.php new file mode 100644 index 0000000..c347990 --- /dev/null +++ b/Upload/admin/modules/tools/tasks.php @@ -0,0 +1,770 @@ +
Please make sure IN_MYBB is defined."); +} + +require_once MYBB_ROOT."/inc/functions_task.php"; + +$page->add_breadcrumb_item($lang->task_manager, "index.php?module=tools-tasks"); + +$plugins->run_hooks("admin_tools_tasks_begin"); + +/** + * Validates a string or array of values + * + * @param mixed Comma-separated list or array of values + * @param int Minimum value + * @param int Maximum value + * @param string Set "string" to return in a comma-separated list, or "array" to return in an array + * @return mixed String or array of valid values OR false if string/array is invalid + */ +function check_time_values($value, $min, $max, $return_type) +{ + // If the values aren't in an array form, make them into an array + if(!is_array($value)) + { + // Empty value == * + if($value === '') + { + return ($return_type == 'string') ? '*' : array('*'); + } + $implode = 1; + $value = explode(',', $value); + } + // If * is in the array, always return with * because it overrides all + if(in_array('*', $value)) + { + return ($return_type == 'string') ? '*' : array('*'); + } + // Validate each value in array + foreach($value as $time) + { + if($time < $min || $time > $max) + { + return false; + } + } + // Return based on return type + if($return_type == 'string') + { + $value = implode(',', $value); + } + return $value; +} + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_tools_tasks_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + if(!trim($mybb->input['description'])) + { + $errors[] = $lang->error_missing_description; + } + + if(!file_exists(MYBB_ROOT."inc/tasks/".$mybb->input['file'].".php")) + { + $errors[] = $lang->error_invalid_task_file; + } + + $mybb->input['minute'] = check_time_values($mybb->input['minute'], 0, 59, 'string'); + if($mybb->input['minute'] === false) + { + $errors[] = $lang->error_invalid_minute; + } + + $mybb->input['hour'] = check_time_values($mybb->input['hour'], 0, 59, 'string'); + if($mybb->input['hour'] === false) + { + $errors[] = $lang->error_invalid_hour; + } + + if($mybb->input['day'] != "*" && $mybb->input['day'] != '') + { + $mybb->input['day'] = check_time_values($mybb->input['day'], 1, 31, 'string'); + if($mybb->input['day'] === false) + { + $errors[] = $lang->error_invalid_day; + } + $mybb->input['weekday'] = array('*'); + } + else + { + $mybb->input['weekday'] = check_time_values($mybb->input['weekday'], 0, 6, 'array'); + if($mybb->input['weekday'] === false) + { + $errors[] = $lang->error_invalid_weekday; + } + $mybb->input['day'] = '*'; + } + + $mybb->input['month'] = check_time_values($mybb->input['month'], 1, 12, 'array'); + if($mybb->input['month'] === false) + { + $errors[] = $lang->error_invalid_month; + } + + if(!$errors) + { + $new_task = array( + "title" => $db->escape_string($mybb->input['title']), + "description" => $db->escape_string($mybb->input['description']), + "file" => $db->escape_string($mybb->input['file']), + "minute" => $db->escape_string($mybb->input['minute']), + "hour" => $db->escape_string($mybb->input['hour']), + "day" => $db->escape_string($mybb->input['day']), + "month" => $db->escape_string(implode(',', $mybb->input['month'])), + "weekday" => $db->escape_string(implode(',', $mybb->input['weekday'])), + "enabled" => (int)$mybb->input['enabled'], + "logging" => (int)$mybb->input['logging'] + ); + + $new_task['nextrun'] = fetch_next_run($new_task); + $tid = $db->insert_query("tasks", $new_task); + + $plugins->run_hooks("admin_tools_tasks_add_commit"); + + $cache->update_tasks(); + + // Log admin action + log_admin_action($tid, $mybb->input['title']); + + flash_message($lang->success_task_created, 'success'); + admin_redirect("index.php?module=tools-tasks"); + } + } + $page->add_breadcrumb_item($lang->add_new_task); + $page->output_header($lang->scheduled_tasks." - ".$lang->add_new_task); + + + $sub_tabs['scheduled_tasks'] = array( + 'title' => $lang->scheduled_tasks, + 'link' => "index.php?module=tools-tasks" + ); + + $sub_tabs['add_task'] = array( + 'title' => $lang->add_new_task, + 'link' => "index.php?module=tools-tasks&action=add", + 'description' => $lang->add_new_task_desc + ); + + $sub_tabs['task_logs'] = array( + 'title' => $lang->view_task_logs, + 'link' => "index.php?module=tools-tasks&action=logs" + ); + + $page->output_nav_tabs($sub_tabs, 'add_task'); + $form = new Form("index.php?module=tools-tasks&action=add", "post", "add"); + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['minute'] = '*'; + $mybb->input['hour'] = '*'; + $mybb->input['day'] = '*'; + $mybb->input['weekday'] = '*'; + $mybb->input['month'] = '*'; + } + $form_container = new FormContainer($lang->add_new_task); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->short_description." *", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + + $task_list = array(); + $task_files = scandir(MYBB_ROOT."inc/tasks/"); + foreach($task_files as $task_file) + { + if(is_file(MYBB_ROOT."inc/tasks/{$task_file}") && get_extension($task_file) == "php") + { + $file_id = preg_replace("#\.".get_extension($task_file)."$#i", "$1", $task_file); + $task_list[$file_id] = $task_file; + } + } + $form_container->output_row($lang->task_file." *", $lang->task_file_desc, $form->generate_select_box("file", $task_list, $mybb->input['file'], array('id' => 'file')), 'file'); + $form_container->output_row($lang->time_minutes, $lang->time_minutes_desc, $form->generate_text_box('minute', $mybb->input['minute'], array('id' => 'minute')), 'minute'); + $form_container->output_row($lang->time_hours, $lang->time_hours_desc, $form->generate_text_box('hour', $mybb->input['hour'], array('id' => 'hour')), 'hour'); + $form_container->output_row($lang->time_days_of_month, $lang->time_days_of_month_desc, $form->generate_text_box('day', $mybb->input['day'], array('id' => 'day')), 'day'); + + $options = array( + "*" => $lang->every_weekday, + "0" => $lang->sunday, + "1" => $lang->monday, + "2" => $lang->tuesday, + "3" => $lang->wednesday, + "4" => $lang->thursday, + "5" => $lang->friday, + "6" => $lang->saturday + ); + $form_container->output_row($lang->time_weekdays, $lang->time_weekdays_desc, $form->generate_select_box('weekday[]', $options, $mybb->input['weekday'], array('id' => 'weekday', 'multiple' => true, 'size' => 8)), 'weekday'); + + $options = array( + "*" => $lang->every_month, + "1" => $lang->january, + "2" => $lang->february, + "3" => $lang->march, + "4" => $lang->april, + "5" => $lang->may, + "6" => $lang->june, + "7" => $lang->july, + "8" => $lang->august, + "9" => $lang->september, + "10" => $lang->october, + "11" => $lang->november, + "12" => $lang->december + ); + $form_container->output_row($lang->time_months, $lang->time_months_desc, $form->generate_select_box('month[]', $options, $mybb->input['month'], array('id' => 'month', 'multiple' => true, 'size' => 13)), 'month'); + + $form_container->output_row($lang->enable_logging." *", "", $form->generate_yes_no_radio("logging", $mybb->input['logging'], true)); + + $form_container->output_row($lang->enabled." *", "", $form->generate_yes_no_radio("enabled", $mybb->input['enabled'], true)); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_task); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("tasks", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $task = $db->fetch_array($query); + + // Does the task not exist? + if(!$task['tid']) + { + flash_message($lang->error_invalid_task, 'error'); + admin_redirect("index.php?module=tools-tasks"); + } + + $plugins->run_hooks("admin_tools_tasks_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + if(!trim($mybb->input['description'])) + { + $errors[] = $lang->error_missing_description; + } + + if(!file_exists(MYBB_ROOT."inc/tasks/".$mybb->input['file'].".php")) + { + $errors[] = $lang->error_invalid_task_file; + } + + $mybb->input['minute'] = check_time_values($mybb->input['minute'], 0, 59, 'string'); + if($mybb->input['minute'] === false) + { + $errors[] = $lang->error_invalid_minute; + } + + $mybb->input['hour'] = check_time_values($mybb->input['hour'], 0, 59, 'string'); + if($mybb->input['hour'] === false) + { + $errors[] = $lang->error_invalid_hour; + } + + if($mybb->input['day'] != "*" && $mybb->input['day'] != '') + { + $mybb->input['day'] = check_time_values($mybb->input['day'], 1, 31, 'string'); + if($mybb->input['day'] === false) + { + $errors[] = $lang->error_invalid_day; + } + $mybb->input['weekday'] = array('*'); + } + else + { + $mybb->input['weekday'] = check_time_values($mybb->input['weekday'], 0, 6, 'array'); + if($mybb->input['weekday'] === false) + { + $errors[] = $lang->error_invalid_weekday; + } + $mybb->input['day'] = '*'; + } + + $mybb->input['month'] = check_time_values($mybb->input['month'], 1, 12, 'array'); + if($mybb->input['month'] === false) + { + $errors[] = $lang->error_invalid_month; + } + + if(!$errors) + { + $enable_confirmation = false; + // Check if we need to ask the user to confirm turning on the task + if(($task['file'] == "backupdb" || $task['file'] == "checktables") && $task['enabled'] == 0 && $mybb->input['enabled'] == 1) + { + $mybb->input['enabled'] = 0; + $enable_confirmation = true; + } + + $updated_task = array( + "title" => $db->escape_string($mybb->input['title']), + "description" => $db->escape_string($mybb->input['description']), + "file" => $db->escape_string($mybb->input['file']), + "minute" => $db->escape_string($mybb->input['minute']), + "hour" => $db->escape_string($mybb->input['hour']), + "day" => $db->escape_string($mybb->input['day']), + "month" => $db->escape_string(implode(',', $mybb->input['month'])), + "weekday" => $db->escape_string(implode(',', $mybb->input['weekday'])), + "enabled" => (int)$mybb->input['enabled'], + "logging" => (int)$mybb->input['logging'] + ); + + $updated_task['nextrun'] = fetch_next_run($updated_task); + + $plugins->run_hooks("admin_tools_tasks_edit_commit"); + + $db->update_query("tasks", $updated_task, "tid='{$task['tid']}'"); + + $cache->update_tasks(); + + // Log admin action + log_admin_action($task['tid'], $mybb->input['title']); + + flash_message($lang->success_task_updated, 'success'); + + if($enable_confirmation == true) + { + admin_redirect("index.php?module=tools-tasks&action=enable&tid={$task['tid']}&my_post_key={$mybb->post_code}"); + } + else + { + admin_redirect("index.php?module=tools-tasks"); + } + } + } + + $page->add_breadcrumb_item($lang->edit_task); + $page->output_header($lang->scheduled_tasks." - ".$lang->edit_task); + + $sub_tabs['edit_task'] = array( + 'title' => $lang->edit_task, + 'description' => $lang->edit_task_desc, + 'link' => "index.php?module=tools-tasks&action=edit&tid={$task['tid']}" + ); + + $page->output_nav_tabs($sub_tabs, 'edit_task'); + + $form = new Form("index.php?module=tools-tasks&action=edit", "post"); + + if($errors) + { + $page->output_inline_error($errors); + $task_data = $mybb->input; + } + else + { + $task_data = $task; + $task_data['weekday'] = explode(',', $task['weekday']); + $task_data['month'] = explode(',', $task['month']); + } + + $form_container = new FormContainer($lang->edit_task); + echo $form->generate_hidden_field("tid", $task['tid']); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $task_data['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->short_description." *", "", $form->generate_text_box('description', $task_data['description'], array('id' => 'description')), 'description'); + + $task_list = array(); + $task_files = scandir(MYBB_ROOT."inc/tasks/"); + foreach($task_files as $task_file) + { + if(is_file(MYBB_ROOT."inc/tasks/{$task_file}") && get_extension($task_file) == "php") + { + $file_id = preg_replace("#\.".get_extension($task_file)."$#i", "$1", $task_file); + $task_list[$file_id] = $task_file; + } + } + $form_container->output_row($lang->task." *", $lang->task_file_desc, $form->generate_select_box("file", $task_list, $task_data['file'], array('id' => 'file')), 'file'); + $form_container->output_row($lang->time_minutes, $lang->time_minutes_desc, $form->generate_text_box('minute', $task_data['minute'], array('id' => 'minute')), 'minute'); + $form_container->output_row($lang->time_hours, $lang->time_hours_desc, $form->generate_text_box('hour', $task_data['hour'], array('id' => 'hour')), 'hour'); + $form_container->output_row($lang->time_days_of_month, $lang->time_days_of_month_desc, $form->generate_text_box('day', $task_data['day'], array('id' => 'day')), 'day'); + + $options = array( + "*" => $lang->every_weekday, + "0" => $lang->sunday, + "1" => $lang->monday, + "2" => $lang->tuesday, + "3" => $lang->wednesday, + "4" => $lang->thursday, + "5" => $lang->friday, + "6" => $lang->saturday + ); + $form_container->output_row($lang->time_weekdays, $lang->time_weekdays_desc, $form->generate_select_box('weekday[]', $options, $task_data['weekday'], array('id' => 'weekday', 'multiple' => true)), 'weekday'); + + $options = array( + "*" => $lang->every_month, + "1" => $lang->january, + "2" => $lang->february, + "3" => $lang->march, + "4" => $lang->april, + "5" => $lang->may, + "6" => $lang->june, + "7" => $lang->july, + "8" => $lang->august, + "9" => $lang->september, + "10" => $lang->october, + "11" => $lang->november, + "12" => $lang->december + ); + $form_container->output_row($lang->time_months, $lang->time_months_desc, $form->generate_select_box('month[]', $options, $task_data['month'], array('id' => 'month', 'multiple' => true)), 'month'); + + $form_container->output_row($lang->enable_logging." *", "", $form->generate_yes_no_radio("logging", $task_data['logging'], true)); + + $form_container->output_row($lang->enabled." *", "", $form->generate_yes_no_radio("enabled", $task_data['enabled'], true)); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_task); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("tasks", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $task = $db->fetch_array($query); + + // Does the task not exist? + if(!$task['tid']) + { + flash_message($lang->error_invalid_task, 'error'); + admin_redirect("index.php?module=tools-tasks"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=tools-tasks"); + } + + $plugins->run_hooks("admin_tools_tasks_delete"); + + if($mybb->request_method == "post") + { + // Delete the task & any associated task log entries + $db->delete_query("tasks", "tid='{$task['tid']}'"); + $db->delete_query("tasklog", "tid='{$task['tid']}'"); + + // Fetch next task run + + $plugins->run_hooks("admin_tools_tasks_delete_commit"); + + $cache->update_tasks(); + + // Log admin action + log_admin_action($task['tid'], $task['title']); + + flash_message($lang->success_task_deleted, 'success'); + admin_redirect("index.php?module=tools-tasks"); + } + else + { + $page->output_confirm_action("index.php?module=tools-tasks&action=delete&tid={$task['tid']}", $lang->confirm_task_deletion); + } +} + +if($mybb->input['action'] == "enable" || $mybb->input['action'] == "disable") +{ + if(!verify_post_check($mybb->input['my_post_key'])) + { + flash_message($lang->invalid_post_verify_key2, 'error'); + admin_redirect("index.php?module=tools-tasks"); + } + + $query = $db->simple_select("tasks", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $task = $db->fetch_array($query); + + // Does the task not exist? + if(!$task['tid']) + { + flash_message($lang->error_invalid_task, 'error'); + admin_redirect("index.php?module=tools-tasks"); + } + + if($mybb->input['action'] == "enable") + { + $plugins->run_hooks("admin_tools_tasks_enable"); + } + else + { + $plugins->run_hooks("admin_tools_tasks_disable"); + } + + if($mybb->input['action'] == "enable") + { + if($task['file'] == "backupdb" || $task['file'] == "checktables") + { + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=tools-tasks"); + } + + if($mybb->request_method == "post") + { + $nextrun = fetch_next_run($task); + $db->update_query("tasks", array("nextrun" => $nextrun, "enabled" => 1), "tid='{$task['tid']}'"); + + $plugins->run_hooks("admin_tools_tasks_enable_commit"); + + $cache->update_tasks(); + + // Log admin action + log_admin_action($task['tid'], $task['title'], $mybb->input['action']); + + flash_message($lang->success_task_enabled, 'success'); + admin_redirect("index.php?module=tools-tasks"); + } + else + { + $page->output_confirm_action("index.php?module=tools-tasks&action=enable&tid={$task['tid']}", $lang->confirm_task_enable); + } + } + else + { + $nextrun = fetch_next_run($task); + $db->update_query("tasks", array("nextrun" => $nextrun, "enabled" => 1), "tid='{$task['tid']}'"); + + $plugins->run_hooks("admin_tools_tasks_enable_commit"); + + $cache->update_tasks(); + + // Log admin action + log_admin_action($task['tid'], $task['title'], $mybb->input['action']); + + flash_message($lang->success_task_enabled, 'success'); + admin_redirect("index.php?module=tools-tasks"); + } + } + else + { + $db->update_query("tasks", array("enabled" => 0), "tid='{$task['tid']}'"); + + $plugins->run_hooks("admin_tools_tasks_disable_commit"); + + $cache->update_tasks(); + + // Log admin action + log_admin_action($task['tid'], $task['title'], $mybb->input['action']); + + flash_message($lang->success_task_disabled, 'success'); + admin_redirect("index.php?module=tools-tasks"); + } +} + +if($mybb->input['action'] == "run") +{ + if(!verify_post_check($mybb->input['my_post_key'])) + { + flash_message($lang->invalid_post_verify_key2, 'error'); + admin_redirect("index.php?module=tools-tasks"); + } + + ignore_user_abort(true); + @set_time_limit(0); + + $plugins->run_hooks("admin_tools_tasks_run"); + + $query = $db->simple_select("tasks", "*", "tid='".$mybb->get_input('tid', 1)."'"); + $task = $db->fetch_array($query); + + // Does the task not exist? + if(!$task['tid']) + { + flash_message($lang->error_invalid_task, 'error'); + admin_redirect("index.php?module=tools-tasks"); + } + + run_task($task['tid']); + + $plugins->run_hooks("admin_tools_tasks_run_commit"); + + // Log admin action + log_admin_action($task['tid'], $task['title']); + + flash_message($lang->success_task_run, 'success'); + admin_redirect("index.php?module=tools-tasks"); +} + +if($mybb->input['action'] == "logs") +{ + $plugins->run_hooks("admin_tools_tasks_logs"); + + $page->output_header($lang->task_logs); + + $sub_tabs['scheduled_tasks'] = array( + 'title' => $lang->scheduled_tasks, + 'link' => "index.php?module=tools-tasks" + ); + + $sub_tabs['add_task'] = array( + 'title' => $lang->add_new_task, + 'link' => "index.php?module=tools-tasks&action=add" + ); + + $sub_tabs['task_logs'] = array( + 'title' => $lang->view_task_logs, + 'link' => "index.php?module=tools-tasks&action=logs", + 'description' => $lang->view_task_logs_desc + ); + + $page->output_nav_tabs($sub_tabs, 'task_logs'); + + $table = new Table; + $table->construct_header($lang->task); + $table->construct_header($lang->date, array("class" => "align_center", "width" => 200)); + $table->construct_header($lang->data, array("width" => "60%")); + + $query = $db->simple_select("tasklog", "COUNT(*) AS log_count"); + $log_count = $db->fetch_field($query, "log_count"); + + $start = 0; + $per_page = 50; + $current_page = 1; + + if($mybb->input['page'] > 0) + { + $current_page = $mybb->get_input('page', 1); + $start = ($current_page-1)*$per_page; + $pages = $log_count / $per_page; + $pages = ceil($pages); + if($current_page > $pages) + { + $start = 0; + $current_page = 1; + } + } + + $pagination = draw_admin_pagination($current_page, $per_page, $log_count, "index.php?module=tools-tasks&action=logs&page={page}"); + + $query = $db->query(" + SELECT l.*, t.title + FROM ".TABLE_PREFIX."tasklog l + LEFT JOIN ".TABLE_PREFIX."tasks t ON (t.tid=l.tid) + ORDER BY l.dateline DESC + LIMIT {$start}, {$per_page} + "); + while($log_entry = $db->fetch_array($query)) + { + $log_entry['title'] = htmlspecialchars_uni($log_entry['title']); + $log_entry['data'] = htmlspecialchars_uni($log_entry['data']); + + $date = my_date('relative', $log_entry['dateline']); + $table->construct_cell("{$log_entry['title']}"); + $table->construct_cell($date, array("class" => "align_center")); + $table->construct_cell($log_entry['data']); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_task_logs, array("colspan" => "3")); + $table->construct_row(); + } + + $table->output($lang->task_logs); + echo $pagination; + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $page->output_header($lang->task_manager); + + $sub_tabs['scheduled_tasks'] = array( + 'title' => $lang->scheduled_tasks, + 'link' => "index.php?module=tools-tasks", + 'description' => $lang->scheduled_tasks_desc + ); + + $sub_tabs['add_task'] = array( + 'title' => $lang->add_new_task, + 'link' => "index.php?module=tools-tasks&action=add" + ); + + $sub_tabs['task_logs'] = array( + 'title' => $lang->view_task_logs, + 'link' => "index.php?module=tools-tasks&action=logs" + ); + + $plugins->run_hooks("admin_tools_tasks_start"); + + $page->output_nav_tabs($sub_tabs, 'scheduled_tasks'); + + $table = new Table; + $table->construct_header($lang->task); + $table->construct_header($lang->next_run, array("class" => "align_center", "width" => 200)); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 150)); + + $query = $db->simple_select("tasks", "*", "", array("order_by" => "title", "order_dir" => "asc")); + while($task = $db->fetch_array($query)) + { + $task['title'] = htmlspecialchars_uni($task['title']); + $task['description'] = htmlspecialchars_uni($task['description']); + $next_run = date($mybb->settings['dateformat'], $task['nextrun']).", ".date($mybb->settings['timeformat'], $task['nextrun']); + if($task['enabled'] == 1) + { + $icon = "style}/images/icons/bullet_on.png\" alt=\"({$lang->alt_enabled})\" title=\"{$lang->alt_enabled}\" style=\"vertical-align: middle;\" /> "; + } + else + { + $icon = "style}/images/icons/bullet_off.png\" alt=\"({$lang->alt_disabled})\" title=\"{$lang->alt_disabled}\" style=\"vertical-align: middle;\" /> "; + } + $table->construct_cell("
{$icon}{$task['title']}
{$task['description']}
"); + $table->construct_cell($next_run, array("class" => "align_center")); + + $popup = new PopupMenu("task_{$task['tid']}", $lang->options); + $popup->add_item($lang->edit_task, "index.php?module=tools-tasks&action=edit&tid={$task['tid']}"); + if($task['enabled'] == 1) + { + $popup->add_item($lang->run_task, "index.php?module=tools-tasks&action=run&tid={$task['tid']}&my_post_key={$mybb->post_code}"); + $popup->add_item($lang->disable_task, "index.php?module=tools-tasks&action=disable&tid={$task['tid']}&my_post_key={$mybb->post_code}"); + } + else + { + $popup->add_item($lang->enable_task, "index.php?module=tools-tasks&action=enable&tid={$task['tid']}&my_post_key={$mybb->post_code}"); + } + $popup->add_item($lang->delete_task, "index.php?module=tools-tasks&action=delete&tid={$task['tid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_task_deletion}')"); + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_tasks, array('colspan' => 3)); + $table->construct_row(); + } + + $table->output($lang->scheduled_tasks); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/tools/warninglog.php b/Upload/admin/modules/tools/warninglog.php new file mode 100644 index 0000000..b56d5cf --- /dev/null +++ b/Upload/admin/modules/tools/warninglog.php @@ -0,0 +1,480 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->warning_logs, "index.php?module=tools-warninglog"); + +$plugins->run_hooks("admin_tools_warninglog_begin"); + +// Revoke a warning +if($mybb->input['action'] == "do_revoke" && $mybb->request_method == "post") +{ + $query = $db->simple_select("warnings", "*", "wid='".(int)$mybb->input['wid']."'"); + $warning = $db->fetch_array($query); + + if(!$warning['wid']) + { + flash_message($lang->error_invalid_warning, 'error'); + admin_redirect("index.php?module=tools-warninglog"); + } + else if($warning['daterevoked']) + { + flash_message($lang->error_already_revoked, 'error'); + admin_redirect("index.php?module=tools-warninglog&action=view&wid={$warning['wid']}"); + } + + $user = get_user($warning['uid']); + + $plugins->run_hooks("admin_tools_warninglog_do_revoke"); + + if(!trim($mybb->input['reason'])) + { + $warn_errors[] = $lang->error_no_revoke_reason; + $mybb->input['action'] = "view"; + } + else + { + // Warning is still active, lower users point count + if($warning['expired'] != 1) + { + $new_warning_points = $user['warningpoints']-$warning['points']; + if($new_warning_points < 0) + { + $new_warning_points = 0; + } + + // Update user + $updated_user = array( + "warningpoints" => $new_warning_points + ); + } + + // Update warning + $updated_warning = array( + "expired" => 1, + "daterevoked" => TIME_NOW, + "revokedby" => $mybb->user['uid'], + "revokereason" => $db->escape_string($mybb->input['reason']) + ); + + $plugins->run_hooks("admin_tools_warninglog_do_revoke_commit"); + + if($warning['expired'] != 1) + { + $db->update_query("users", $updated_user, "uid='{$warning['uid']}'"); + } + + $db->update_query("warnings", $updated_warning, "wid='{$warning['wid']}'"); + + flash_message($lang->redirect_warning_revoked, 'success'); + admin_redirect("index.php?module=tools-warninglog&action=view&wid={$warning['wid']}"); + } +} + +// Detailed view of a warning +if($mybb->input['action'] == "view") +{ + $query = $db->query(" + SELECT w.*, t.title AS type_title, u.username, p.subject AS post_subject + FROM ".TABLE_PREFIX."warnings w + LEFT JOIN ".TABLE_PREFIX."warningtypes t ON (t.tid=w.tid) + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=w.issuedby) + LEFT JOIN ".TABLE_PREFIX."posts p ON (p.pid=w.pid) + WHERE w.wid='".(int)$mybb->input['wid']."' + "); + $warning = $db->fetch_array($query); + + if(!$warning['wid']) + { + flash_message($lang->error_invalid_warning, 'error'); + admin_redirect("index.php?module=tools-warninglog"); + } + + $user = get_user((int)$warning['uid']); + + $plugins->run_hooks("admin_tools_warninglog_view"); + + $page->add_breadcrumb_item($lang->warning_details, "index.php?module=tools-warninglog&action=view&wid={$warning['wid']}"); + + $page->output_header($lang->warning_details); + + $user_link = build_profile_link($user['username'], $user['uid'], "_blank"); + + if(is_array($warn_errors)) + { + $page->output_inline_error($warn_errors); + $mybb->input['reason'] = htmlspecialchars_uni($mybb->input['reason']); + } + + $table = new Table; + + $post_link = ""; + if($warning['post_subject']) + { + if(!is_object($parser)) + { + require_once MYBB_ROOT."inc/class_parser.php"; + $parser = new postParser; + } + + $warning['post_subject'] = $parser->parse_badwords($warning['post_subject']); + $warning['post_subject'] = htmlspecialchars_uni($warning['post_subject']); + $post_link = get_post_link($warning['pid']); + $table->construct_cell("{$lang->warned_user}

{$user_link}"); + $table->construct_cell("{$lang->post}

settings['bburl']}/{$post_link}\" target=\"_blank\">{$warning['post_subject']}"); + $table->construct_row(); + } + else + { + $table->construct_cell("{$lang->warned_user}

{$user_link}", array('colspan' => 2)); + $table->construct_row(); + } + + $issuedby = build_profile_link($warning['username'], $warning['issuedby'], "_blank"); + $notes = nl2br(htmlspecialchars_uni($warning['notes'])); + + $date_issued = my_date('relative', $warning['dateline']); + if($warning['type_title']) + { + $warning_type = $warning['type_title']; + } + else + { + $warning_type = $warning['title']; + } + $warning_type = htmlspecialchars_uni($warning_type); + if($warning['points'] > 0) + { + $warning['points'] = "+{$warning['points']}"; + } + + $points = $lang->sprintf($lang->warning_points, $warning['points']); + if($warning['expired'] != 1) + { + if($warning['expires'] == 0) + { + $expires = $lang->never; + } + else + { + $expires = my_date('relative', $warning['expires']); + } + $status = $lang->warning_active; + } + else + { + if($warning['daterevoked']) + { + $expires = $status = $lang->warning_revoked; + } + else if($warning['expires']) + { + $expires = $status = $lang->already_expired; + } + } + + $table->construct_cell("{$lang->warning}

{$warning_type} {$points}", array('width' => '50%')); + $table->construct_cell("{$lang->date_issued}

{$date_issued}", array('width' => '50%')); + $table->construct_row(); + + $table->construct_cell("{$lang->issued_by}

{$issuedby}", array('width' => '50%')); + $table->construct_cell("{$lang->expires}

{$expires}", array('width' => '50%')); + $table->construct_row(); + + $table->construct_cell("{$lang->warning_note}

{$notes}", array('colspan' => 2)); + $table->construct_row(); + + $table->output("
{$status}
".$lang->warning_details); + + if(!$warning['daterevoked']) + { + $form = new Form("index.php?module=tools-warninglog", "post"); + $form_container = new FormContainer($lang->revoke_warning); + echo $form->generate_hidden_field('action', 'do_revoke'); + echo $form->generate_hidden_field('wid', $warning['wid']); + $form_container->output_row("", $lang->revoke_warning_desc, $form->generate_text_area('reason', $mybb->input['reason'], array('id' => 'reason')), 'reason'); + + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->revoke_warning); + $form->output_submit_wrapper($buttons); + $form->end(); + } + else + { + $date_revoked = my_date('relative', $warning['daterevoked']); + $revoked_user = get_user($warning['revokedby']); + $revoked_by = build_profile_link($revoked_user['username'], $revoked_user['uid'], "_blank"); + $revoke_reason = nl2br(htmlspecialchars_uni($warning['revokereason'])); + + $revoke_table = new Table; + $revoke_table->construct_cell("{$lang->revoked_by}

{$revoked_by}", array('width' => '50%')); + $revoke_table->construct_cell("{$lang->date_revoked}

{$date_revoked}", array('width' => '50%')); + $revoke_table->construct_row(); + + $revoke_table->construct_cell("{$lang->reason}

{$revoke_reason}", array('colspan' => 2)); + $revoke_table->construct_row(); + + $revoke_table->output($lang->warning_is_revoked); + } + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_tools_warninglog_start"); + + $page->output_header($lang->warning_logs); + + $sub_tabs['warning_logs'] = array( + 'title' => $lang->warning_logs, + 'link' => "index.php?module=tools-warninglog", + 'description' => $lang->warning_logs_desc + ); + + $page->output_nav_tabs($sub_tabs, 'warning_logs'); + + // Filter options + $where_sql = ''; + if(!empty($mybb->input['filter']['username'])) + { + $search_user = get_user_by_username($mybb->input['filter']['username']); + + $mybb->input['filter']['uid'] = (int)$search_user['uid']; + $mybb->input['filter']['uid'] = $db->fetch_field($query, "uid"); + } + if($mybb->input['filter']['uid']) + { + $search['uid'] = (int)$mybb->input['filter']['uid']; + $where_sql .= " AND w.uid='{$search['uid']}'"; + if(!isset($mybb->input['search']['username'])) + { + $user = get_user($mybb->input['search']['uid']); + $mybb->input['search']['username'] = $user['username']; + } + } + if(!empty($mybb->input['filter']['mod_username'])) + { + $mod_user = get_user_by_username($mybb->input['filter']['mod_username']); + + $mybb->input['filter']['mod_uid'] = (int)$mod_user['uid']; + } + if($mybb->input['filter']['mod_uid']) + { + $search['mod_uid'] = (int)$mybb->input['filter']['mod_uid']; + $where_sql .= " AND w.issuedby='{$search['mod_uid']}'"; + if(!isset($mybb->input['search']['mod_username'])) + { + $mod_user = get_user($mybb->input['search']['uid']); + $mybb->input['search']['mod_username'] = $mod_user['username']; + } + } + if($mybb->input['filter']['reason']) + { + $search['reason'] = $db->escape_string_like($mybb->input['filter']['reason']); + $where_sql .= " AND (w.notes LIKE '%{$search['reason']}%' OR t.title LIKE '%{$search['reason']}%' OR w.title LIKE '%{$search['reason']}%')"; + } + $sortbysel = array(); + switch($mybb->input['filter']['sortby']) + { + case "username": + $sortby = "u.username"; + $sortbysel['username'] = ' selected="selected"'; + break; + case "expires": + $sortby = "w.expires"; + $sortbysel['expires'] = ' selected="selected"'; + break; + case "issuedby": + $sortby = "i.username"; + $sortbysel['issuedby'] = ' selected="selected"'; + break; + default: // "dateline" + $sortby = "w.dateline"; + $sortbysel['dateline'] = ' selected="selected"'; + } + $order = $mybb->input['filter']['order']; + $ordersel = array(); + if($order != "asc") + { + $order = "desc"; + $ordersel['desc'] = ' selected="selected"'; + } + else + { + $ordersel['asc'] = ' selected="selected"'; + } + + // Expire any warnings past their expiration date + require_once MYBB_ROOT.'inc/datahandlers/warnings.php'; + $warningshandler = new WarningsHandler('update'); + + $warningshandler->expire_warnings(); + + // Pagination stuff + $sql = " + SELECT COUNT(wid) as count + FROM + ".TABLE_PREFIX."warnings w + LEFT JOIN ".TABLE_PREFIX."warningtypes t ON (w.tid=t.tid) + WHERE 1=1 + {$where_sql} + "; + $query = $db->query($sql); + $total_warnings = $db->fetch_field($query, 'count'); + $view_page = 1; + if(isset($mybb->input['page']) && $mybb->get_input('page', 1) > 0) + { + $view_page = $mybb->get_input('page', 1); + } + $per_page = 20; + if(isset($mybb->input['filter']['per_page']) && (int)$mybb->input['filter']['per_page'] > 0) + { + $per_page = (int)$mybb->input['filter']['per_page']; + } + $start = ($view_page-1) * $per_page; + // Build the base URL for pagination links + $url = 'index.php?module=tools-warninglog'; + if(is_array($mybb->input['filter']) && count($mybb->input['filter'])) + { + foreach($mybb->input['filter'] as $field => $value) + { + $value = urlencode($value); + $url .= "&filter[{$field}]={$value}"; + } + } + + // The actual query + $sql = " + SELECT + w.wid, w.title as custom_title, w.points, w.dateline, w.issuedby, w.expires, w.expired, w.daterevoked, w.revokedby, + t.title, + u.uid, u.username, u.usergroup, u.displaygroup, + i.uid as mod_uid, i.username as mod_username, i.usergroup as mod_usergroup, i.displaygroup as mod_displaygroup + FROM ".TABLE_PREFIX."warnings w + LEFT JOIN ".TABLE_PREFIX."users u on (w.uid=u.uid) + LEFT JOIN ".TABLE_PREFIX."warningtypes t ON (w.tid=t.tid) + LEFT JOIN ".TABLE_PREFIX."users i ON (i.uid=w.issuedby) + WHERE 1=1 + {$where_sql} + ORDER BY {$sortby} {$order} + LIMIT {$start}, {$per_page} + "; + $query = $db->query($sql); + + + $table = new Table; + $table->construct_header($lang->warned_user, array('width' => '15%')); + $table->construct_header($lang->warning, array("class" => "align_center", 'width' => '25%')); + $table->construct_header($lang->date_issued, array("class" => "align_center", 'width' => '20%')); + $table->construct_header($lang->expires, array("class" => "align_center", 'width' => '20%')); + $table->construct_header($lang->issued_by, array("class" => "align_center", 'width' => '15%')); + $table->construct_header($lang->options, array("class" => "align_center", 'width' => '5%')); + + while($row = $db->fetch_array($query)) + { + if(!$row['username']) + { + $row['username'] = $lang->guest; + } + + $trow = alt_trow(); + $username = format_name($row['username'], $row['usergroup'], $row['displaygroup']); + if(!$row['uid']) + { + $username_link = $username; + } + else + { + $username_link = build_profile_link($username, $row['uid'], "_blank"); + } + $mod_username = format_name($row['mod_username'], $row['mod_usergroup'], $row['mod_displaygroup']); + $mod_username_link = build_profile_link($mod_username, $row['mod_uid'], "_blank"); + $issued_date = my_date('relative', $row['dateline']); + $revoked_text = ''; + if($row['daterevoked'] > 0) + { + $revoked_date = my_date('relative', $row['daterevoked']); + $revoked_text = "
{$lang->revoked} {$revoked_date}"; + } + if($row['expires'] > 0) + { + $expire_date = my_date('relative', $row['expires']); + } + else + { + $expire_date = $lang->never; + } + $title = $row['title']; + if(empty($row['title'])) + { + $title = $row['custom_title']; + } + $title = htmlspecialchars_uni($title); + if($row['points'] > 0) + { + $points = '+'.$row['points']; + } + + $table->construct_cell($username_link); + $table->construct_cell("{$title} ({$points})"); + $table->construct_cell($issued_date, array("class" => "align_center")); + $table->construct_cell($expire_date.$revoked_text, array("class" => "align_center")); + $table->construct_cell($mod_username_link); + $table->construct_cell("{$lang->view}", array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_warning_logs, array("colspan" => "6")); + $table->construct_row(); + } + + $table->output($lang->warning_logs); + + // Do we need to construct the pagination? + if($total_warnings > $per_page) + { + echo draw_admin_pagination($view_page, $per_page, $total_warnings, $url)."
"; + } + + $sort_by = array( + 'expires' => $lang->expiry_date, + 'dateline' => $lang->issued_date, + 'username' => $lang->warned_user, + 'issuedby' => $lang->issued_by + ); + + $order_array = array( + 'asc' => $lang->asc, + 'desc' => $lang->desc + ); + + $form = new Form("index.php?module=tools-warninglog", "post"); + $form_container = new FormContainer($lang->filter_warning_logs); + $form_container->output_row($lang->filter_warned_user, "", $form->generate_text_box('filter[username]', $mybb->input['filter']['username'], array('id' => 'filter_username')), 'filter_username'); + $form_container->output_row($lang->filter_issued_by, "", $form->generate_text_box('filter[mod_username]', $mybb->input['filter']['mod_username'], array('id' => 'filter_mod_username')), 'filter_mod_username'); + $form_container->output_row($lang->filter_reason, "", $form->generate_text_box('filter[reason]', $mybb->input['filter']['reason'], array('id' => 'filter_reason')), 'filter_reason'); + $form_container->output_row($lang->sort_by, "", $form->generate_select_box('filter[sortby]', $sort_by, $mybb->input['filter']['sortby'], array('id' => 'filter_sortby'))." {$lang->in} ".$form->generate_select_box('filter[order]', $order_array, $order, array('id' => 'filter_order'))." {$lang->order}", 'filter_order'); + $form_container->output_row($lang->results_per_page, "", $form->generate_numeric_field('filter[per_page]', $per_page, array('id' => 'filter_per_page')), 'filter_per_page'); + + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->filter_warning_logs); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/user/admin_permissions.php b/Upload/admin/modules/user/admin_permissions.php new file mode 100644 index 0000000..75f0aba --- /dev/null +++ b/Upload/admin/modules/user/admin_permissions.php @@ -0,0 +1,530 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->admin_permissions, "index.php?module=user-admin_permissions"); + +if(($mybb->input['action'] == "edit" && $mybb->input['uid'] == 0) || $mybb->input['action'] == "group" || !$mybb->input['action']) +{ + $sub_tabs['user_permissions'] = array( + 'title' => $lang->user_permissions, + 'link' => "index.php?module=user-admin_permissions", + 'description' => $lang->user_permissions_desc + ); + + $sub_tabs['group_permissions'] = array( + 'title' => $lang->group_permissions, + 'link' => "index.php?module=user-admin_permissions&action=group", + 'description' => $lang->group_permissions_desc + ); + + $sub_tabs['default_permissions'] = array( + 'title' => $lang->default_permissions, + 'link' => "index.php?module=user-admin_permissions&action=edit&uid=0", + 'description' => $lang->default_permissions_desc + ); +} + +$uid = $mybb->get_input('uid', 1); + +$plugins->run_hooks("admin_user_admin_permissions_begin"); + +if($mybb->input['action'] == "delete") +{ + if(is_super_admin($uid)) + { + flash_message($lang->error_super_admin, 'error'); + admin_redirect("index.php?module=user-admin_permissions"); + } + + if($mybb->input['no']) + { + admin_redirect("index.php?module=user-admin_permissions"); + } + + if(!trim($mybb->input['uid'])) + { + flash_message($lang->error_delete_no_uid, 'error'); + admin_redirect("index.php?module=user-admin_permissions"); + } + + $query = $db->simple_select("adminoptions", "COUNT(uid) as adminoptions", "uid = '{$mybb->input['uid']}'"); + if($db->fetch_field($query, 'adminoptions') == 0) + { + flash_message($lang->error_delete_invalid_uid, 'error'); + admin_redirect("index.php?module=user-admin_permissions"); + } + + $plugins->run_hooks("admin_user_admin_permissions_delete"); + + if($mybb->request_method == "post") + { + $newperms = array( + "permissions" => '' + ); + + $plugins->run_hooks("admin_user_admin_permissions_delete_commit"); + + $db->update_query("adminoptions", $newperms, "uid = '{$uid}'"); + + // Log admin action + if($uid < 0) + { + $gid = abs($uid); + $query = $db->simple_select("usergroups", "title", "gid='{$gid}'"); + $group = $db->fetch_array($query); + log_admin_action($uid, $group['title']); + + } + elseif($uid == 0) + { + // Default + log_admin_action(0, $lang->default); + } + else + { + $user = get_user($uid); + log_admin_action($uid, $user['username']); + } + + flash_message($lang->success_perms_deleted, 'success'); + admin_redirect("index.php?module=user-admin_permissions"); + } + else + { + $page->output_confirm_action("index.php?module=user-admin_permissions&action=delete&uid={$mybb->input['uid']}", $lang->confirm_perms_deletion); + } +} + +if($mybb->input['action'] == "edit") +{ + if(is_super_admin($uid)) + { + flash_message($lang->error_super_admin, 'error'); + admin_redirect("index.php?module=user-admin_permissions"); + } + + $plugins->run_hooks("admin_user_admin_permissions_edit"); + + if($mybb->request_method == "post") + { + foreach($mybb->input['permissions'] as $module => $actions) + { + $no_access = 0; + foreach($actions as $action => $access) + { + if($access == 0) + { + ++$no_access; + } + } + // User can't access any actions in this module - just disallow it completely + if($no_access == count($actions)) + { + unset($mybb->input['permissions'][$module]); + } + } + + // Does an options row exist for this admin already? + $query = $db->simple_select("adminoptions", "COUNT(uid) AS existing_options", "uid='".$mybb->get_input('uid', 1)."'"); + $existing_options = $db->fetch_field($query, "existing_options"); + if($existing_options > 0) + { + $db->update_query("adminoptions", array('permissions' => $db->escape_string(serialize($mybb->input['permissions']))), "uid = '".$mybb->get_input('uid', 1)."'"); + } + else + { + $insert_array = array( + "uid" => $mybb->get_input('uid', 1), + "permissions" => $db->escape_string(serialize($mybb->input['permissions'])), + "notes" => '', + "defaultviews" => '' + ); + $db->insert_query("adminoptions", $insert_array); + } + + $plugins->run_hooks("admin_user_admin_permissions_edit_commit"); + + // Log admin action + if($uid > 0) + { + // Users + $user = get_user($uid); + log_admin_action($uid, $user['username']); + } + elseif($uid < 0) + { + // Groups + $gid = abs($uid); + $query = $db->simple_select("usergroups", "title", "gid='{$gid}'"); + $group = $db->fetch_array($query); + log_admin_action($uid, $group['title']); + } + else + { + // Default + log_admin_action(0); + } + + flash_message($lang->admin_permissions_updated, 'success'); + admin_redirect("index.php?module=user-admin_permissions"); + } + + if($uid > 0) + { + switch($db->type) + { + case "pgsql": + case "sqlite": + $query = $db->query(" + SELECT u.uid, u.username, g.cancp, g.gid + FROM ".TABLE_PREFIX."users u + LEFT JOIN ".TABLE_PREFIX."usergroups g ON (((','|| u.additionalgroups|| ',' LIKE '%,'|| g.gid|| ',%') OR u.usergroup = g.gid)) + WHERE u.uid='$uid' + AND g.cancp=1 + LIMIT 1 + "); + break; + default: + $query = $db->query(" + SELECT u.uid, u.username, g.cancp, g.gid + FROM ".TABLE_PREFIX."users u + LEFT JOIN ".TABLE_PREFIX."usergroups g ON (((CONCAT(',', u.additionalgroups, ',') LIKE CONCAT('%,', g.gid, ',%')) OR u.usergroup = g.gid)) + WHERE u.uid='$uid' + AND g.cancp=1 + LIMIT 1 + "); + } + + $admin = $db->fetch_array($query); + $permission_data = get_admin_permissions($uid, $admin['gid']); + $title = $admin['username']; + $page->add_breadcrumb_item($lang->user_permissions, "index.php?module=user-admin_permissions"); + } + elseif($uid < 0) + { + $gid = abs($uid); + $query = $db->simple_select("usergroups", "title", "gid='$gid'"); + $group = $db->fetch_array($query); + $permission_data = get_admin_permissions("", $gid); + $title = $group['title']; + $page->add_breadcrumb_item($lang->group_permissions, "index.php?module=user-admin_permissions&action=group"); + } + else + { + $query = $db->simple_select("adminoptions", "permissions", "uid='0'"); + $permission_data = my_unserialize($db->fetch_field($query, "permissions")); + $page->add_breadcrumb_item($lang->default_permissions); + $title = $lang->default; + } + + if($uid != 0) + { + $page->add_breadcrumb_item($lang->edit_permissions.": {$title}"); + } + + $page->output_header($lang->edit_permissions); + + if($uid != 0) + { + $sub_tabs['edit_permissions'] = array( + 'title' => $lang->edit_permissions, + 'link' => "index.php?module=user-admin_permissions&action=edit&uid={$uid}", + 'description' => $lang->edit_permissions_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_permissions'); + } + + $form = new Form("index.php?module=user-admin_permissions&action=edit", "post", "edit"); + + echo $form->generate_hidden_field("uid", $uid); + + // Fetch all of the modules we have + $modules_dir = MYBB_ADMIN_DIR."modules"; + $dir = opendir($modules_dir); + $modules = array(); + while(($module = readdir($dir)) !== false) + { + if(is_dir($modules_dir."/".$module) && !in_array($module, array(".", "..")) && file_exists($modules_dir."/".$module."/module_meta.php")) + { + require_once $modules_dir."/".$module."/module_meta.php"; + $meta_function = $module."_admin_permissions"; + + // Module has no permissions, skip it + if(function_exists($meta_function) && is_array($meta_function())) + { + $permission_modules[$module] = $meta_function(); + $modules[$permission_modules[$module]['disporder']][] = $module; + } + } + } + closedir($dir); + + ksort($modules); + foreach($modules as $disp_order => $mod) + { + if(!is_array($mod)) + { + continue; + } + + foreach($mod as $module) + { + $module_tabs[$module] = $permission_modules[$module]['name']; + } + } + $page->output_tab_control($module_tabs); + + foreach($permission_modules as $key => $module) + { + echo "
\n"; + $form_container = new FormContainer("{$module['name']}"); + foreach($module['permissions'] as $action => $title) + { + $form_container->output_row($title, "", $form->generate_yes_no_radio('permissions['.$key.']['.$action.']', (int)$permission_data[$key][$action], array('yes' => 1, 'no' => 0)), 'permissions['.$key.']['.$action.']'); + } + $form_container->end(); + echo "
\n"; + } + + $buttons[] = $form->generate_submit_button($lang->update_permissions); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "group") +{ + $plugins->run_hooks("admin_user_admin_permissions_group"); + + $page->add_breadcrumb_item($lang->group_permissions); + $page->output_header($lang->group_permissions); + + $page->output_nav_tabs($sub_tabs, 'group_permissions'); + + $table = new Table; + $table->construct_header($lang->group); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 150)); + + // Get usergroups with ACP access + $query = $db->query(" + SELECT g.title, g.cancp, a.permissions, g.gid + FROM ".TABLE_PREFIX."usergroups g + LEFT JOIN ".TABLE_PREFIX."adminoptions a ON (a.uid = -g.gid) + WHERE g.cancp = 1 + ORDER BY g.title ASC + "); + while($group = $db->fetch_array($query)) + { + if($group['permissions'] != "") + { + $perm_type = "group"; + } + else + { + $perm_type = "default"; + } + $uid = -$group['gid']; + $table->construct_cell("
style}/images/icons/{$perm_type}.png\" title=\"{$lang->permissions_type_group}\" alt=\"{$perm_type}\" />
"); + + if($group['permissions'] != "") + { + $popup = new PopupMenu("groupperm_{$uid}", $lang->options); + $popup->add_item($lang->edit_permissions, "index.php?module=user-admin_permissions&action=edit&uid={$uid}"); + + // Check permissions for Revoke + $popup->add_item($lang->revoke_permissions, "index.php?module=user-admin_permissions&action=delete&uid={$uid}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, 'Are you sure you wish to revoke this group\'s permissions?')"); + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + } + else + { + $table->construct_cell("{$lang->set_permissions}", array("class" => "align_center")); + } + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_group_perms, array("colspan" => "3")); + $table->construct_row(); + } + + $table->output($lang->group_permissions); + + echo << +
+{$lang->legend} +{$lang->using_custom_perms} {$lang->using_custom_perms}
+{$lang->using_default_perms} {$lang->using_default_perms}
+LEGEND; + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_user_admin_permissions_start"); + + $page->add_breadcrumb_item($lang->user_permissions); + $page->output_header($lang->user_permissions); + + $page->output_nav_tabs($sub_tabs, 'user_permissions'); + + $table = new Table; + $table->construct_header($lang->user); + $table->construct_header($lang->last_active, array("class" => "align_center", "width" => 200)); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 150)); + + // Get usergroups with ACP access + $usergroups = array(); + $query = $db->simple_select("usergroups", "*", "cancp = 1"); + while($usergroup = $db->fetch_array($query)) + { + $usergroups[$usergroup['gid']] = $usergroup; + } + + // Get users whose primary or secondary usergroup has ACP access + $comma = $primary_group_list = $secondary_group_list = ''; + foreach($usergroups as $gid => $group_info) + { + $primary_group_list .= $comma.$gid; + switch($db->type) + { + case "pgsql": + case "sqlite": + $secondary_group_list .= " OR ','|| u.additionalgroups||',' LIKE '%,{$gid},%'"; + break; + default: + $secondary_group_list .= " OR CONCAT(',', u.additionalgroups,',') LIKE '%,{$gid},%'"; + } + + $comma = ','; + } + + $group_list = implode(',', array_keys($usergroups)); + $secondary_groups = ','.$group_list.','; + + // Get usergroups with ACP access + $query = $db->query(" + SELECT g.title, g.cancp, a.permissions, g.gid + FROM ".TABLE_PREFIX."usergroups g + LEFT JOIN ".TABLE_PREFIX."adminoptions a ON (a.uid = -g.gid) + WHERE g.cancp = 1 + ORDER BY g.title ASC + "); + while($group = $db->fetch_array($query)) + { + $group_permissions[$group['gid']] = $group['permissions']; + } + + $query = $db->query(" + SELECT u.uid, u.username, u.lastactive, u.usergroup, u.additionalgroups, a.permissions + FROM ".TABLE_PREFIX."users u + LEFT JOIN ".TABLE_PREFIX."adminoptions a ON (a.uid=u.uid) + WHERE u.usergroup IN ({$primary_group_list}) {$secondary_group_list} + ORDER BY u.username ASC + "); + while($admin = $db->fetch_array($query)) + { + if($admin['permissions'] != "") + { + $perm_type = "user"; + } + else + { + $groups = explode(",", $admin['additionalgroups'].",".$admin['usergroup']); + foreach($groups as $group) + { + if($group == "") continue; + if($group_permissions[$group] != "") + { + $perm_type = "group"; + break; + } + } + + if(!$group_permissions) + { + $perm_type = "default"; + } + } + + $usergroup_list = array(); + + // Build a list of group memberships that have access to the Admin CP + // Primary usergroup? + if($usergroups[$admin['usergroup']]['cancp'] == 1) + { + $usergroup_list[] = "".$usergroups[$admin['usergroup']]['title'].""; + } + + // Secondary usergroups? + $additional_groups = explode(',', $admin['additionalgroups']); + if(is_array($additional_groups)) + { + foreach($additional_groups as $gid) + { + if($usergroups[$gid]['cancp'] == 1) + { + $usergroup_list[] = $usergroups[$gid]['title']; + } + } + } + $usergroup_list = implode(", ", $usergroup_list); + + $table->construct_cell("
style}/images/icons/{$perm_type}.png\" title=\"{$lang->perms_type_user}\" alt=\"{$perm_type}\" />
"); + + $table->construct_cell(my_date('relative', $admin['lastactive']), array("class" => "align_center")); + + $popup = new PopupMenu("adminperm_{$admin['uid']}", $lang->options); + if(!is_super_admin($admin['uid'])) + { + if($admin['permissions'] != "") + { + $popup->add_item($lang->edit_permissions, "index.php?module=user-admin_permissions&action=edit&uid={$admin['uid']}"); + $popup->add_item($lang->revoke_permissions, "index.php?module=user-admin_permissions&action=delete&uid={$admin['uid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_perms_deletion2}')"); + } + else + { + $popup->add_item($lang->set_permissions, "index.php?module=user-admin_permissions&action=edit&uid={$admin['uid']}"); + } + } + $popup->add_item($lang->view_log, "index.php?module=tools-adminlog&uid={$admin['uid']}"); + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_user_perms, array("colspan" => "3")); + $table->construct_row(); + } + + $table->output($lang->user_permissions); + + echo << +
+{$lang->legend} +{$lang->using_individual_perms} {$lang->using_individual_perms}
+{$lang->using_group_perms} {$lang->using_group_perms}
+{$lang->using_default_perms} {$lang->using_default_perms}
+LEGEND; + $page->output_footer(); +} + diff --git a/Upload/admin/modules/user/banning.php b/Upload/admin/modules/user/banning.php new file mode 100644 index 0000000..65b7a83 --- /dev/null +++ b/Upload/admin/modules/user/banning.php @@ -0,0 +1,605 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->banning, "index.php?module=user-banning"); + + +$sub_tabs['ips'] = array( + 'title' => $lang->banned_ips, + 'link' => "index.php?module=config-banning", +); + +$sub_tabs['bans'] = array( + 'title' => $lang->banned_accounts, + 'link' => "index.php?module=user-banning", + 'description' => $lang->banned_accounts_desc +); + +$sub_tabs['usernames'] = array( + 'title' => $lang->disallowed_usernames, + 'link' => "index.php?module=config-banning&type=usernames", +); + +$sub_tabs['emails'] = array( + 'title' => $lang->disallowed_email_addresses, + 'link' => "index.php?module=config-banning&type=emails", +); + +// Fetch banned groups +$query = $db->simple_select("usergroups", "gid,title", "isbannedgroup=1", array('order_by' => 'title')); +while($group = $db->fetch_array($query)) +{ + $banned_groups[$group['gid']] = $group['title']; +} + +// Fetch ban times +$ban_times = fetch_ban_times(); + +$plugins->run_hooks("admin_user_banning_begin"); + +if($mybb->input['action'] == "prune") +{ + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=user-banning"); + } + + $query = $db->simple_select("banned", "*", "uid='{$mybb->input['uid']}'"); + $ban = $db->fetch_array($query); + + if(!$ban['uid']) + { + flash_message($lang->error_invalid_ban, 'error'); + admin_redirect("index.php?module=user-banning"); + } + + $user = get_user($ban['uid']); + + if(is_super_admin($user['uid']) && ($mybb->user['uid'] != $user['uid'] && !is_super_admin($mybb->user['uid']))) + { + flash_message($lang->cannot_perform_action_super_admin_general, 'error'); + admin_redirect("index.php?module=user-banning"); + } + + $plugins->run_hooks("admin_user_banning_prune"); + + if($mybb->request_method == "post") + { + require_once MYBB_ROOT."inc/class_moderation.php"; + $moderation = new Moderation(); + + $query = $db->simple_select("threads", "tid", "uid='{$user['uid']}'"); + while($thread = $db->fetch_array($query)) + { + $moderation->delete_thread($thread['tid']); + } + + $query = $db->simple_select("posts", "pid", "uid='{$user['uid']}'"); + while($post = $db->fetch_array($query)) + { + $moderation->delete_post($post['pid']); + } + + $plugins->run_hooks("admin_user_banning_prune_commit"); + + $cache->update_reportedcontent(); + + // Log admin action + log_admin_action($mybb->input['uid'], $user['username']); + + flash_message($lang->success_pruned, 'success'); + admin_redirect("index.php?module=user-banning"); + } + else + { + $page->output_confirm_action("index.php?module=user-banning&action=prune&uid={$user['uid']}", $lang->confirm_prune); + } +} + +if($mybb->input['action'] == "lift") +{ + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=user-banning"); + } + + $query = $db->simple_select("banned", "*", "uid='{$mybb->input['uid']}'"); + $ban = $db->fetch_array($query); + + if(!$ban['uid']) + { + flash_message($lang->error_invalid_ban, 'error'); + admin_redirect("index.php?module=user-banning"); + } + + $user = get_user($ban['uid']); + + if(is_super_admin($user['uid']) && ($mybb->user['uid'] != $user['uid'] && !is_super_admin($mybb->user['uid']))) + { + flash_message($lang->cannot_perform_action_super_admin_general, 'error'); + admin_redirect("index.php?module=user-banning"); + } + + $plugins->run_hooks("admin_user_banning_lift"); + + if($mybb->request_method == "post") + { + $updated_group = array( + 'usergroup' => $ban['oldgroup'], + 'additionalgroups' => $ban['oldadditionalgroups'], + 'displaygroup' => $ban['olddisplaygroup'] + ); + $db->delete_query("banned", "uid='{$ban['uid']}'"); + + $plugins->run_hooks("admin_user_banning_lift_commit"); + + $db->update_query("users", $updated_group, "uid='{$ban['uid']}'"); + + $cache->update_banned(); + $cache->update_moderators(); + + // Log admin action + log_admin_action($mybb->input['uid'], $user['username']); + + flash_message($lang->success_ban_lifted, 'success'); + admin_redirect("index.php?module=user-banning"); + } + else + { + $page->output_confirm_action("index.php?module=user-banning&action=lift&uid={$ban['uid']}", $lang->confirm_lift_ban); + } +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("banned", "*", "uid='{$mybb->input['uid']}'"); + $ban = $db->fetch_array($query); + + $user = get_user($ban['uid']); + + if(!$ban['uid']) + { + flash_message($lang->error_invalid_ban, 'error'); + admin_redirect("index.php?module=user-banning"); + } + + $plugins->run_hooks("admin_user_banning_edit"); + + if($mybb->request_method == "post") + { + if(!$ban['uid']) + { + $errors[] = $lang->error_invalid_username; + } + // Is the user we're trying to ban a super admin and we're not? + else if(is_super_admin($ban['uid']) && !is_super_admin($ban['uid'])) + { + $errors[] = $lang->error_no_perm_to_ban; + } + + if($ban['uid'] == $mybb->user['uid']) + { + $errors[] = $lang->error_ban_self; + } + + // No errors? Update + if(!$errors) + { + // Ban the user + if($mybb->input['bantime'] == '---') + { + $lifted = 0; + } + else + { + $lifted = ban_date2timestamp($mybb->input['bantime'], $ban['dateline']); + } + + $reason = my_substr($mybb->input['reason'], 0, 255); + + if(count($banned_groups) == 1) + { + $group = array_keys($banned_groups); + $mybb->input['usergroup'] = $group[0]; + } + + $update_array = array( + 'gid' => (int)$mybb->input['usergroup'], + 'dateline' => TIME_NOW, + 'bantime' => $db->escape_string($mybb->input['bantime']), + 'lifted' => $db->escape_string($lifted), + 'reason' => $db->escape_string($reason) + ); + + $db->update_query('banned', $update_array, "uid='{$ban['uid']}'"); + + // Move the user to the banned group + $update_array = array( + 'usergroup' => (int)$mybb->input['usergroup'], + 'displaygroup' => 0, + 'additionalgroups' => '', + ); + $db->update_query('users', $update_array, "uid = {$ban['uid']}"); + + $plugins->run_hooks("admin_user_banning_edit_commit"); + + $cache->update_banned(); + + // Log admin action + log_admin_action($mybb->input['uid'], $user['username']); + + flash_message($lang->success_ban_updated, 'success'); + admin_redirect("index.php?module=user-banning"); + } + } + $page->add_breadcrumb_item($lang->edit_ban); + $page->output_header($lang->edit_ban); + + $sub_tabs = array(); + $sub_tabs['edit'] = array( + 'title' => $lang->edit_ban, + 'description' => $lang->edit_ban_desc + ); + $page->output_nav_tabs($sub_tabs, "edit"); + + $form = new Form("index.php?module=user-banning&action=edit&uid={$ban['uid']}", "post"); + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input = array_merge($mybb->input, $ban); + } + + $form_container = new FormContainer($lang->edit_ban); + $form_container->output_row($lang->ban_username, "", $user['username']); + $form_container->output_row($lang->ban_reason, "", $form->generate_text_area('reason', $mybb->input['reason'], array('id' => 'reason', 'maxlength' => '255')), 'reason'); + if(count($banned_groups) > 1) + { + $form_container->output_row($lang->ban_group, $lang->ban_group_desc, $form->generate_select_box('usergroup', $banned_groups, $mybb->input['usergroup'], array('id' => 'usergroup')), 'usergroup'); + } + + if($mybb->input['bantime'] == 'perm' || $mybb->input['bantime'] == '' || $mybb->input['lifted'] == 'perm' ||$mybb->input['lifted'] == '') + { + $mybb->input['bantime'] = '---'; + $mybb->input['lifted'] = '---'; + } + + foreach($ban_times as $time => $period) + { + if($time != '---') + { + $friendly_time = my_date("D, jS M Y @ g:ia", ban_date2timestamp($time)); + $period = "{$period} ({$friendly_time})"; + } + $length_list[$time] = $period; + } + $form_container->output_row($lang->ban_time, "", $form->generate_select_box('bantime', $length_list, $mybb->input['bantime'], array('id' => 'bantime')), 'bantime'); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->update_ban); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $where_sql_full = $where_sql = ''; + + $plugins->run_hooks("admin_user_banning_start"); + + if($mybb->request_method == "post") + { + $options = array( + 'fields' => array('username', 'usergroup', 'additionalgroups', 'displaygroup') + ); + + $user = get_user_by_username($mybb->input['username'], $options); + + // Are we searching a user? + if(isset($mybb->input['search']) && $mybb->get_input('search') != '') + { + $where_sql = 'uid=\''.(int)$user['uid'].'\''; + $where_sql_full = 'WHERE b.uid=\''.(int)$user['uid'].'\''; + } + else + { + if(!$user['uid']) + { + $errors[] = $lang->error_invalid_username; + } + // Is the user we're trying to ban a super admin and we're not? + else if(is_super_admin($user['uid']) && !is_super_admin($mybb->user['uid'])) + { + $errors[] = $lang->error_no_perm_to_ban; + } + else + { + $query = $db->simple_select("banned", "uid", "uid='{$user['uid']}'"); + if($db->fetch_field($query, "uid")) + { + $errors[] = $lang->error_already_banned; + } + + // Get PRIMARY usergroup information + $usergroups = $cache->read("usergroups"); + if(!empty($usergroups[$user['usergroup']]) && $usergroups[$user['usergroup']]['isbannedgroup'] == 1) + { + $errors[] = $lang->error_already_banned; + } + } + + if($user['uid'] == $mybb->user['uid']) + { + $errors[] = $lang->error_ban_self; + } + + // No errors? Insert + if(!$errors) + { + // Ban the user + if($mybb->input['bantime'] == '---') + { + $lifted = 0; + } + else + { + $lifted = ban_date2timestamp($mybb->input['bantime']); + } + + $reason = my_substr($mybb->input['reason'], 0, 255); + + if(count($banned_groups) == 1) + { + $group = array_keys($banned_groups); + $mybb->input['usergroup'] = $group[0]; + } + + $insert_array = array( + 'uid' => $user['uid'], + 'gid' => (int)$mybb->input['usergroup'], + 'oldgroup' => $user['usergroup'], + 'oldadditionalgroups' => $user['additionalgroups'], + 'olddisplaygroup' => $user['displaygroup'], + 'admin' => (int)$mybb->user['uid'], + 'dateline' => TIME_NOW, + 'bantime' => $db->escape_string($mybb->input['bantime']), + 'lifted' => $db->escape_string($lifted), + 'reason' => $db->escape_string($reason) + ); + $db->insert_query('banned', $insert_array); + + // Move the user to the banned group + $update_array = array( + 'usergroup' => (int)$mybb->input['usergroup'], + 'displaygroup' => 0, + 'additionalgroups' => '', + ); + + $db->delete_query("forumsubscriptions", "uid = '{$user['uid']}'"); + $db->delete_query("threadsubscriptions", "uid = '{$user['uid']}'"); + + $plugins->run_hooks("admin_user_banning_start_commit"); + + $db->update_query('users', $update_array, "uid = '{$user['uid']}'"); + + $cache->update_banned(); + + // Log admin action + log_admin_action($user['uid'], $user['username'], $lifted); + + flash_message($lang->success_banned, 'success'); + admin_redirect("index.php?module=user-banning"); + } + } + } + + $page->output_header($lang->banned_accounts); + + $page->output_nav_tabs($sub_tabs, "bans"); + + $query = $db->simple_select("banned", "COUNT(*) AS ban_count", $where_sql); + $ban_count = $db->fetch_field($query, "ban_count"); + + $per_page = 20; + + if($mybb->input['page'] > 0) + { + $current_page = $mybb->get_input('page', 1); + $start = ($current_page-1)*$per_page; + $pages = $ban_count / $per_page; + $pages = ceil($pages); + if($current_page > $pages) + { + $start = 0; + $current_page = 1; + } + } + else + { + $start = 0; + $current_page = 1; + } + + $pagination = draw_admin_pagination($current_page, $per_page, $ban_count, "index.php?module=user-banning&page={page}"); + + $table = new Table; + $table->construct_header($lang->user); + $table->construct_header($lang->ban_lifts_on, array("class" => "align_center", "width" => 150)); + $table->construct_header($lang->time_left, array("class" => "align_center", "width" => 150)); + $table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 2, "width" => 200)); + $table->construct_header($lang->moderation, array("class" => "align_center", "colspan" => 1, "width" => 200)); + + // Fetch bans + $query = $db->query(" + SELECT b.*, a.username AS adminuser, u.username + FROM ".TABLE_PREFIX."banned b + LEFT JOIN ".TABLE_PREFIX."users u ON (b.uid=u.uid) + LEFT JOIN ".TABLE_PREFIX."users a ON (b.admin=a.uid) + {$where_sql_full} + ORDER BY dateline DESC + LIMIT {$start}, {$per_page} + "); + + // Get the banned users + while($ban = $db->fetch_array($query)) + { + $profile_link = build_profile_link($ban['username'], $ban['uid'], "_blank"); + $ban_date = my_date($mybb->settings['dateformat'], $ban['dateline']); + if($ban['lifted'] == 'perm' || $ban['lifted'] == '' || $ban['bantime'] == 'perm' || $ban['bantime'] == '---') + { + $ban_period = $lang->permenantly; + $time_remaining = $lifts_on = $lang->na; + } + else + { + $ban_period = $lang->for." ".$ban_times[$ban['bantime']]; + + $remaining = $ban['lifted']-TIME_NOW; + $time_remaining = nice_time($remaining, array('short' => 1, 'seconds' => false)).""; + + if($remaining < 3600) + { + $time_remaining = "{$time_remaining}"; + } + else if($remaining < 86400) + { + $time_remaining = "{$time_remaining}"; + } + else if($remaining < 604800) + { + $time_remaining = "{$time_remaining}"; + } + else + { + $time_remaining = "{$time_remaining}"; + } + $lifts_on = my_date($mybb->settings['dateformat'], $ban['lifted']); + } + + if(!$ban['adminuser']) + { + if($ban['admin'] == 0) + { + $ban['adminuser'] = "MyBB System"; + } + else + { + $ban['adminuser'] = $ban['admin']; + } + } + + $table->construct_cell($lang->sprintf($lang->bannedby_x_on_x, $profile_link, htmlspecialchars_uni($ban['adminuser']), $ban_date, $ban_period)); + $table->construct_cell($lifts_on, array("class" => "align_center")); + $table->construct_cell($time_remaining, array("class" => "align_center")); + $table->construct_cell("{$lang->edit}", array("class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_lift_ban}');\">{$lang->lift}", array("class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_prune}');\">{$lang->prune_threads_and_posts}", array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_banned_users, array("colspan" => "6")); + $table->construct_row(); + } + $table->output($lang->banned_accounts); + echo $pagination; + + $form = new Form("index.php?module=user-banning", "post"); + if($errors) + { + $page->output_inline_error($errors); + } + + if($mybb->input['uid'] && !$mybb->input['username']) + { + $user = get_user($mybb->input['uid']); + $mybb->input['username'] = $user['username']; + } + + $form_container = new FormContainer($lang->ban_a_user); + $form_container->output_row($lang->ban_username, $lang->autocomplete_enabled, $form->generate_text_box('username', $mybb->input['username'], array('id' => 'username')), 'username'); + $form_container->output_row($lang->ban_reason, "", $form->generate_text_area('reason', $mybb->input['reason'], array('id' => 'reason', 'maxlength' => '255')), 'reason'); + if(count($banned_groups) > 1) + { + $form_container->output_row($lang->ban_group, $lang->add_ban_group_desc, $form->generate_select_box('usergroup', $banned_groups, $mybb->input['usergroup'], array('id' => 'usergroup')), 'usergroup'); + } + foreach($ban_times as $time => $period) + { + if($time != "---") + { + $friendly_time = my_date("D, jS M Y @ g:ia", ban_date2timestamp($time)); + $period = "{$period} ({$friendly_time})"; + } + $length_list[$time] = $period; + } + $form_container->output_row($lang->ban_time, "", $form->generate_select_box('bantime', $length_list, $mybb->input['bantime'], array('id' => 'bantime')), 'bantime'); + + $form_container->end(); + + // Autocompletion for usernames + echo ' + + + '; + + $buttons[] = $form->generate_submit_button($lang->ban_user); + $buttons[] = $form->generate_submit_button($lang->search_user, array('name' => 'search')); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/user/group_promotions.php b/Upload/admin/modules/user/group_promotions.php new file mode 100644 index 0000000..2252791 --- /dev/null +++ b/Upload/admin/modules/user/group_promotions.php @@ -0,0 +1,725 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->user_group_promotions, "index.php?module=user-group_promotions"); + +$sub_tabs['usergroup_promotions'] = array( + 'title' => $lang->user_group_promotions, + 'link' => "index.php?module=user-group_promotions", + 'description' => $lang->user_group_promotions_desc +); + +$sub_tabs['add_promotion'] = array( + 'title' => $lang->add_new_promotion, + 'link' => "index.php?module=user-group_promotions&action=add", + 'description' => $lang->add_new_promotion_desc +); + +$sub_tabs['promotion_logs'] = array( + 'title' => $lang->view_promotion_logs, + 'link' => "index.php?module=user-group_promotions&action=logs", + 'description' => $lang->view_promotion_logs_desc +); + +$plugins->run_hooks("admin_user_group_promotions_begin"); + +if($mybb->input['action'] == "disable") +{ + if($mybb->input['no']) + { + admin_redirect("index.php?module=user-group_promotions"); + } + + if(!trim($mybb->input['pid'])) + { + flash_message($lang->error_no_promo_id, 'error'); + admin_redirect("index.php?module=user-group_promotions"); + } + + $query = $db->simple_select("promotions", "*", "pid='".$mybb->get_input('pid', 1)."'"); + $promotion = $db->fetch_array($query); + + if(!$promotion['pid']) + { + flash_message($lang->error_invalid_promo_id, 'error'); + admin_redirect("index.php?module=user-group_promotions"); + } + + $plugins->run_hooks("admin_user_group_promotions_disable"); + + if($mybb->request_method == "post") + { + $update_promotion = array( + "enabled" => 0 + ); + + $plugins->run_hooks("admin_user_group_promotions_disable_commit"); + + $db->update_query("promotions", $update_promotion, "pid = '{$mybb->input['pid']}'"); + + // Log admin action + log_admin_action($promotion['pid'], $promotion['title']); + + flash_message($lang->success_promo_disabled, 'success'); + admin_redirect("index.php?module=user-group_promotions"); + } + else + { + $page->output_confirm_action("index.php?module=user-group_promotions&action=disable&pid={$promotion['pid']}", $lang->confirm_promo_disable); + } +} + +if($mybb->input['action'] == "delete") +{ + if($mybb->input['no']) + { + admin_redirect("index.php?module=user-group_promotions"); + } + + if(!trim($mybb->input['pid'])) + { + flash_message($lang->error_no_promo_id, 'error'); + admin_redirect("index.php?module=user-group_promotions"); + } + + $query = $db->simple_select("promotions", "*", "pid='".$mybb->get_input('pid', 1)."'"); + $promotion = $db->fetch_array($query); + + if(!$promotion['pid']) + { + flash_message($lang->error_invalid_promo_id, 'error'); + admin_redirect("index.php?module=user-group_promotions"); + } + + $plugins->run_hooks("admin_user_group_promotions_delete"); + + if($mybb->request_method == "post") + { + $db->delete_query("promotions", "pid = '{$mybb->input['pid']}'"); + + $plugins->run_hooks("admin_user_group_promotions_delete_commit"); + + // Log admin action + log_admin_action($promotion['pid'], $promotion['title']); + + flash_message($lang->success_promo_deleted, 'success'); + admin_redirect("index.php?module=user-group_promotions"); + } + else + { + $page->output_confirm_action("index.php?module=user-group_promotions&action=delete&pid={$mybb->input['pid']}", $lang->confirm_promo_deletion); + } +} + +if($mybb->input['action'] == "enable") +{ + if(!verify_post_check($mybb->input['my_post_key'])) + { + flash_message($lang->invalid_post_verify_key2, 'error'); + admin_redirect("index.php?module=user-group_promotions"); + } + + if(!trim($mybb->input['pid'])) + { + flash_message($lang->error_no_promo_id, 'error'); + admin_redirect("index.php?module=user-group_promotions"); + } + + $query = $db->simple_select("promotions", "*", "pid='".$mybb->get_input('pid', 1)."'"); + $promotion = $db->fetch_array($query); + + if(!$promotion['pid']) + { + flash_message($lang->error_invalid_promo_id, 'error'); + admin_redirect("index.php?module=user-group_promotions"); + } + + $plugins->run_hooks("admin_user_group_promotions_enable"); + + $update_promotion = array( + "enabled" => 1 + ); + + $plugins->run_hooks("admin_user_group_promotions_enable_commit"); + + $db->update_query("promotions", $update_promotion, "pid = '{$mybb->input['pid']}'"); + + // Log admin action + log_admin_action($promotion['pid'], $promotion['title']); + + flash_message($lang->success_promo_enabled, 'success'); + admin_redirect("index.php?module=user-group_promotions"); +} + +if($mybb->input['action'] == "edit") +{ + if(!trim($mybb->input['pid'])) + { + flash_message($lang->error_no_promo_id, 'error'); + admin_redirect("index.php?module=user-group_promotions"); + } + + $query = $db->simple_select("promotions", "*", "pid = '{$mybb->input['pid']}'"); + $promotion = $db->fetch_array($query); + + if(!$promotion) + { + flash_message($lang->error_invalid_promo_id, 'error'); + admin_redirect("index.php?module=user-group_promotions"); + } + + $plugins->run_hooks("admin_user_group_promotions_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_no_title; + } + + if(!trim($mybb->input['description'])) + { + $errors[] = $lang->error_no_desc; + } + + if(empty($mybb->input['requirements'])) + { + $errors[] = $lang->error_no_requirements; + } + + if(empty($mybb->input['originalusergroup'])) + { + $errors[] = $lang->error_no_orig_usergroup; + } + + if(!trim($mybb->input['newusergroup'])) + { + $errors[] = $lang->error_no_new_usergroup; + } + + if(!trim($mybb->input['usergroupchangetype'])) + { + $errors[] = $lang->error_no_usergroup_change_type; + } + + if(!$errors) + { + if(in_array('*', $mybb->input['originalusergroup'])) + { + $mybb->input['originalusergroup'] = '*'; + } + else + { + $mybb->input['originalusergroup'] = implode(',', array_map('intval', $mybb->input['originalusergroup'])); + } + + $update_promotion = array( + "title" => $db->escape_string($mybb->input['title']), + "description" => $db->escape_string($mybb->input['description']), + "posts" => (int)$mybb->input['postcount'], + "posttype" => $db->escape_string($mybb->input['posttype']), + "threads" => (int)$mybb->input['threadcount'], + "threadtype" => $db->escape_string($mybb->input['threadtype']), + "registered" => (int)$mybb->input['timeregistered'], + "registeredtype" => $db->escape_string($mybb->input['timeregisteredtype']), + "online" => $db->escape_string($mybb->input['timeonline']), + "onlinetype" => $db->escape_string($mybb->input['timeonlinetype']), + "reputations" => (int)$mybb->input['reputationcount'], + "reputationtype" => $db->escape_string($mybb->input['reputationtype']), + "referrals" => (int)$mybb->input['referrals'], + "referralstype" => $db->escape_string($mybb->input['referralstype']), + "warnings" => (int)$mybb->input['warnings'], + "warningstype" => $db->escape_string($mybb->input['warningstype']), + "requirements" => $db->escape_string(implode(",", $mybb->input['requirements'])), + "originalusergroup" => $db->escape_string($mybb->input['originalusergroup']), + "newusergroup" => (int)$mybb->input['newusergroup'], + "usergrouptype" => $db->escape_string($mybb->input['usergroupchangetype']), + "enabled" => (int)$mybb->input['enabled'], + "logging" => (int)$mybb->input['logging'] + ); + + $plugins->run_hooks("admin_user_group_promotions_edit_commit"); + + $db->update_query("promotions", $update_promotion, "pid = '".$mybb->get_input('pid', 1)."'"); + + // Log admin action + log_admin_action($promotion['pid'], $mybb->input['title']); + + flash_message($lang->success_promo_updated, 'success'); + admin_redirect("index.php?module=user-group_promotions"); + } + } + + $page->add_breadcrumb_item($lang->edit_promotion); + $page->output_header($lang->user_group_promotions." - ".$lang->edit_promotion); + + $sub_tabs = array(); + $sub_tabs['edit_promotion'] = array( + 'title' => $lang->edit_promotion, + 'link' => "index.php?module=user-group_promotions&action=edit", + 'description' => $lang->edit_promotion_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_promotion'); + $form = new Form("index.php?module=user-group_promotions&action=edit", "post", "edit"); + echo $form->generate_hidden_field("pid", $mybb->input['pid']); + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['title'] = $promotion['title']; + $mybb->input['description'] = $promotion['description']; + $mybb->input['requirements'] = explode(',', $promotion['requirements']); + $mybb->input['reputationcount'] = $promotion['reputations']; + $mybb->input['reputationtype'] = $promotion['reputationtype']; + $mybb->input['postcount'] = $promotion['posts']; + $mybb->input['posttype'] = $promotion['posttype']; + $mybb->input['threadcount'] = $promotion['threads']; + $mybb->input['threadtype'] = $promotion['threadtype']; + $mybb->input['referrals'] = $promotion['referrals']; + $mybb->input['referralstype'] = $promotion['referralstype']; + $mybb->input['warnings'] = $promotion['warnings']; + $mybb->input['warningstype'] = $promotion['warningstype']; + $mybb->input['timeregistered'] = $promotion['registered']; + $mybb->input['timeregisteredtype'] = $promotion['registeredtype']; + $mybb->input['timeonline'] = $promotion['online']; + $mybb->input['timeonlinetype'] = $promotion['onlinetype']; + $mybb->input['originalusergroup'] = explode(',', $promotion['originalusergroup']); + $mybb->input['usergroupchangetype'] = $promotion['usergrouptype']; + $mybb->input['newusergroup'] = $promotion['newusergroup']; + $mybb->input['enabled'] = $promotion['enabled']; + $mybb->input['logging'] = $promotion['logging']; + } + + $form_container = new FormContainer($lang->edit_promotion); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->short_desc." *", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + + $options = array( + "postcount" => $lang->post_count, + "threadcount" => $lang->thread_count, + "reputation" => $lang->reputation, + "referrals" => $lang->referrals, + "warnings" => $lang->warning_points, + "timeregistered" => $lang->time_registered, + "timeonline" => $lang->time_online + ); + + $form_container->output_row($lang->promo_requirements." *", $lang->promo_requirements_desc, $form->generate_select_box('requirements[]', $options, $mybb->input['requirements'], array('id' => 'requirements', 'multiple' => true, 'size' => 5)), 'requirements'); + + $options_type = array( + ">" => $lang->greater_than, + ">=" => $lang->greater_than_or_equal_to, + "=" => $lang->equal_to, + "<=" => $lang->less_than_or_equal_to, + "<" => $lang->less_than + ); + + $form_container->output_row($lang->post_count, $lang->post_count_desc, $form->generate_numeric_field('postcount', $mybb->input['postcount'], array('id' => 'postcount'))." ".$form->generate_select_box("posttype", $options_type, $mybb->input['posttype'], array('id' => 'posttype')), 'postcount'); + + $form_container->output_row($lang->thread_count, $lang->thread_count_desc, $form->generate_numeric_field('threadcount', $mybb->input['threadcount'], array('id' => 'threadcount'))." ".$form->generate_select_box("threadtype", $options_type, $mybb->input['threadtype'], array('id' => 'threadtype')), 'threadcount'); + + $form_container->output_row($lang->reputation_count, $lang->reputation_count_desc, $form->generate_numeric_field('reputationcount', $mybb->input['reputationcount'], array('id' => 'reputationcount'))." ".$form->generate_select_box("reputationtype", $options_type, $mybb->input['reputationtype'], array('id' => 'reputationtype')), 'reputationcount'); + + $options = array( + "hours" => $lang->hours, + "days" => $lang->days, + "weeks" => $lang->weeks, + "months" => $lang->months, + "years" => $lang->years + ); + + $form_container->output_row($lang->referral_count, $lang->referral_count_desc, $form->generate_numeric_field('referrals', $mybb->input['referrals'], array('id' => 'referrals'))." ".$form->generate_select_box("referralstype", $options_type, $mybb->input['referralstype'], array('id' => 'referralstype')), 'referrals'); + + $form_container->output_row($lang->warning_points, $lang->warning_points_desc, $form->generate_numeric_field('warnings', $mybb->input['warnings'], array('id' => 'warnings'))." ".$form->generate_select_box("warningstype", $options_type, $mybb->input['warningstype'], array('id' => 'warningstype')), 'warnings'); + + $form_container->output_row($lang->time_registered, $lang->time_registered_desc, $form->generate_numeric_field('timeregistered', $mybb->input['timeregistered'], array('id' => 'timeregistered'))." ".$form->generate_select_box("timeregisteredtype", $options, $mybb->input['timeregisteredtype'], array('id' => 'timeregisteredtype')), 'timeregistered'); + + $form_container->output_row($lang->time_online, $lang->time_online_desc, $form->generate_numeric_field('timeonline', $mybb->input['timeonline'], array('id' => 'timeonline'))." ".$form->generate_select_box("timeonlinetype", $options, $mybb->input['timeonlinetype'], array('id' => 'timeonlinetype')), 'timeonline'); + + $options = array(); + + $query = $db->simple_select("usergroups", "gid, title", "gid != '1'", array('order_by' => 'title')); + while($usergroup = $db->fetch_array($query)) + { + $options[(int)$usergroup['gid']] = $usergroup['title']; + } + + $form_container->output_row($lang->orig_user_group." *", $lang->orig_user_group_desc, $form->generate_select_box('originalusergroup[]', $options, $mybb->input['originalusergroup'], array('id' => 'originalusergroup', 'multiple' => true, 'size' => 5)), 'originalusergroup'); + + unset($options['*']); // Remove the all usergroups option + $form_container->output_row($lang->new_user_group." *", $lang->new_user_group_desc, $form->generate_select_box('newusergroup', $options, $mybb->input['newusergroup'], array('id' => 'newusergroup')), 'newusergroup'); + + $options = array( + 'primary' => $lang->primary_user_group, + 'secondary' => $lang->secondary_user_group + ); + + $form_container->output_row($lang->user_group_change_type." *", $lang->user_group_change_type_desc, $form->generate_select_box('usergroupchangetype', $options, $mybb->input['usergroupchangetype'], array('id' => 'usergroupchangetype')), 'usergroupchangetype'); + + $form_container->output_row($lang->enabled." *", "", $form->generate_yes_no_radio("enabled", $mybb->input['enabled'], true)); + + $form_container->output_row($lang->enable_logging." *", "", $form->generate_yes_no_radio("logging", $mybb->input['logging'], true)); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->update_promotion); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_user_group_promotions_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_no_title; + } + + if(!trim($mybb->input['description'])) + { + $errors[] = $lang->error_no_desc; + } + + if(empty($mybb->input['requirements'])) + { + $errors[] = $lang->error_no_requirements; + } + + if(empty($mybb->input['originalusergroup'])) + { + $errors[] = $lang->error_no_orig_usergroup; + } + + if(!trim($mybb->input['newusergroup'])) + { + $errors[] = $lang->error_no_new_usergroup; + } + + if(!trim($mybb->input['usergroupchangetype'])) + { + $errors[] = $lang->error_no_usergroup_change_type; + } + + if(!$errors) + { + if(in_array('*', $mybb->input['originalusergroup'])) + { + $mybb->input['originalusergroup'] = '*'; + } + else + { + $mybb->input['originalusergroup'] = implode(',', array_map('intval', $mybb->input['originalusergroup'])); + } + + $new_promotion = array( + "title" => $db->escape_string($mybb->input['title']), + "description" => $db->escape_string($mybb->input['description']), + "posts" => (int)$mybb->input['postcount'], + "posttype" => $db->escape_string($mybb->input['posttype']), + "threads" => (int)$mybb->input['threadcount'], + "threadtype" => $db->escape_string($mybb->input['threadtype']), + "registered" => (int)$mybb->input['timeregistered'], + "registeredtype" => $db->escape_string($mybb->input['timeregisteredtype']), + "online" => (int)$mybb->input['timeonline'], + "onlinetype" => $db->escape_string($mybb->input['timeonlinetype']), + "reputations" => (int)$mybb->input['reputationcount'], + "reputationtype" => $db->escape_string($mybb->input['reputationtype']), + "referrals" => (int)$mybb->input['referrals'], + "referralstype" => $db->escape_string($mybb->input['referralstype']), + "warnings" => (int)$mybb->input['warnings'], + "warningstype" => $db->escape_string($mybb->input['warningstype']), + "requirements" => $db->escape_string(implode(",", $mybb->input['requirements'])), + "originalusergroup" => $db->escape_string($mybb->input['originalusergroup']), + "usergrouptype" => $db->escape_string($mybb->input['usergroupchangetype']), + "newusergroup" => (int)$mybb->input['newusergroup'], + "enabled" => (int)$mybb->input['enabled'], + "logging" => (int)$mybb->input['logging'] + ); + + $pid = $db->insert_query("promotions", $new_promotion); + + $plugins->run_hooks("admin_user_group_promotions_add_commit"); + + // Log admin action + log_admin_action($pid, $mybb->input['title']); + + flash_message($lang->success_promo_added, 'success'); + admin_redirect("index.php?module=user-group_promotions"); + } + } + $page->add_breadcrumb_item($lang->add_new_promotion); + $page->output_header($lang->user_group_promotions." - ".$lang->add_new_promotion); + + $sub_tabs['usergroup_promotions'] = array( + 'title' => $lang->user_group_promotions, + 'link' => "index.php?module=user-group_promotions" + ); + + $sub_tabs['add_promotion'] = array( + 'title' => $lang->add_new_promotion, + 'link' => "index.php?module=user-group_promotions&action=add", + 'description' => $lang->add_new_promotion_desc + ); + + $sub_tabs['promotion_logs'] = array( + 'title' => $lang->view_promotion_logs, + 'link' => "index.php?module=user-group_promotions&action=logs" + ); + + $page->output_nav_tabs($sub_tabs, 'add_promotion'); + $form = new Form("index.php?module=user-group_promotions&action=add", "post", "add"); + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input['reputationcount'] = '0'; + $mybb->input['referrals'] = '0'; + $mybb->input['warnings'] = '0'; + $mybb->input['postcount'] = '0'; + $mybb->input['threadcount'] = '0'; + $mybb->input['timeregistered'] = '0'; + $mybb->input['timeregisteredtype'] = 'days'; + $mybb->input['timeonline'] = '0'; + $mybb->input['timeonlinetype'] = 'days'; + $mybb->input['originalusergroup'] = '*'; + $mybb->input['newusergroup'] = '2'; + $mybb->input['enabled'] = '1'; + $mybb->input['logging'] = '1'; + } + $form_container = new FormContainer($lang->add_new_promotion); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->short_desc." *", "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + + $options = array( + "postcount" => $lang->post_count, + "threadcount" => $lang->thread_count, + "reputation" => $lang->reputation, + "referrals" => $lang->referrals, + "warnings" => $lang->warning_points, + "timeregistered" => $lang->time_registered, + "timeonline" => $lang->time_online + ); + + $form_container->output_row($lang->promo_requirements." *", $lang->promo_requirements_desc, $form->generate_select_box('requirements[]', $options, $mybb->input['requirements'], array('id' => 'requirements', 'multiple' => true, 'size' => 5)), 'requirements'); + + $options_type = array( + ">" => $lang->greater_than, + ">=" => $lang->greater_than_or_equal_to, + "=" => $lang->equal_to, + "<=" => $lang->less_than_or_equal_to, + "<" => $lang->less_than + ); + + $form_container->output_row($lang->post_count, $lang->post_count_desc, $form->generate_numeric_field('postcount', $mybb->input['postcount'], array('id' => 'postcount'))." ".$form->generate_select_box("posttype", $options_type, $mybb->input['posttype'], array('id' => 'posttype')), 'postcount'); + + $form_container->output_row($lang->thread_count, $lang->thread_count_desc, $form->generate_numeric_field('threadcount', $mybb->input['threadcount'], array('id' => 'threadcount'))." ".$form->generate_select_box("threadtype", $options_type, $mybb->input['threadtype'], array('id' => 'threadtype')), 'threadcount'); + + $form_container->output_row($lang->reputation_count, $lang->reputation_count_desc, $form->generate_numeric_field('reputationcount', $mybb->input['reputationcount'], array('id' => 'reputationcount'))." ".$form->generate_select_box("reputationtype", $options_type, $mybb->input['reputationtype'], array('id' => 'reputationtype')), 'reputationcount'); + + $options = array( + "hours" => $lang->hours, + "days" => $lang->days, + "weeks" => $lang->weeks, + "months" => $lang->months, + "years" => $lang->years + ); + + $form_container->output_row($lang->referral_count, $lang->referral_count_desc, $form->generate_numeric_field('referrals', $mybb->input['referrals'], array('id' => 'referrals'))." ".$form->generate_select_box("referralstype", $options_type, $mybb->input['referralstype'], array('id' => 'referralstype')), 'referrals'); + + $form_container->output_row($lang->warning_points, $lang->warning_points_desc, $form->generate_numeric_field('warnings', $mybb->input['warnings'], array('id' => 'warnings'))." ".$form->generate_select_box("warningstype", $options_type, $mybb->input['warningstype'], array('id' => 'warningstype')), 'warnings'); + + $form_container->output_row($lang->time_registered, $lang->time_registered_desc, $form->generate_numeric_field('timeregistered', $mybb->input['timeregistered'], array('id' => 'timeregistered'))." ".$form->generate_select_box("timeregisteredtype", $options, $mybb->input['timeregisteredtype'], array('id' => 'timeregisteredtype')), 'timeregistered'); + + $form_container->output_row($lang->time_online, $lang->time_online_desc, $form->generate_numeric_field('timeonline', $mybb->input['timeonline'], array('id' => 'timeonline'))." ".$form->generate_select_box("timeonlinetype", $options, $mybb->input['timeonlinetype'], array('id' => 'timeonlinetype')), 'timeonline'); + $options = array(); + + $query = $db->simple_select("usergroups", "gid, title", "gid != '1'", array('order_by' => 'title')); + while($usergroup = $db->fetch_array($query)) + { + $options[(int)$usergroup['gid']] = $usergroup['title']; + } + + $form_container->output_row($lang->orig_user_group." *", $lang->orig_user_group_desc, $form->generate_select_box('originalusergroup[]', $options, $mybb->input['originalusergroup'], array('id' => 'originalusergroup', 'multiple' => true, 'size' => 5)), 'originalusergroup'); + + unset($options['*']); + $form_container->output_row($lang->new_user_group." *", $lang->new_user_group_desc, $form->generate_select_box('newusergroup', $options, $mybb->input['newusergroup'], array('id' => 'newusergroup')), 'newusergroup'); + + $options = array( + 'primary' => $lang->primary_user_group, + 'secondary' => $lang->secondary_user_group + ); + + $form_container->output_row($lang->user_group_change_type." *", $lang->user_group_change_type_desc, $form->generate_select_box('usergroupchangetype', $options, $mybb->input['usergroupchangetype'], array('id' => 'usergroupchangetype')), 'usergroupchangetype'); + + $form_container->output_row($lang->enabled." *", "", $form->generate_yes_no_radio("enabled", $mybb->input['enabled'], true)); + + $form_container->output_row($lang->enable_logging." *", "", $form->generate_yes_no_radio("logging", $mybb->input['logging'], true)); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->update_promotion); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "logs") +{ + $plugins->run_hooks("admin_user_group_promotions_logs"); + + if($mybb->get_input('page', 1) > 1) + { + $mybb->input['page'] = $mybb->get_input('page', 1); + $start = ($mybb->input['page']*20)-20; + } + else + { + $mybb->input['page'] = 1; + $start = 0; + } + + $page->add_breadcrumb_item($lang->promotion_logs); + $page->output_header($lang->user_group_promotions." - ".$lang->promotion_logs); + + $page->output_nav_tabs($sub_tabs, 'promotion_logs'); + + $table = new Table; + $table->construct_header($lang->promoted_user, array("class" => "align_center", "width" => '20%')); + $table->construct_header($lang->user_group_change_type, array("class" => "align_center", "width" => '20%')); + $table->construct_header($lang->orig_user_group, array("class" => "align_center", "width" => '20%')); + $table->construct_header($lang->new_user_group, array("class" => "align_center", "width" => '20%')); + $table->construct_header($lang->time_promoted, array("class" => "align_center", "width" => '20%')); + + $query = $db->query(" + SELECT pl.*,u.username + FROM ".TABLE_PREFIX."promotionlogs pl + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=pl.uid) + ORDER BY dateline DESC + LIMIT {$start}, 20 + "); + while($log = $db->fetch_array($query)) + { + $log['username'] = "".htmlspecialchars_uni($log['username']).""; + + if($log['type'] == "secondary" || (!empty($log['oldusergroup']) && strstr(",", $log['oldusergroup']))) + { + $log['oldusergroup'] = "".$lang->multiple_usergroups.""; + $log['newusergroup'] = htmlspecialchars_uni($groupscache[$log['newusergroup']]['title']); + } + else + { + $log['oldusergroup'] = htmlspecialchars_uni($groupscache[$log['oldusergroup']]['title']); + $log['newusergroup'] = htmlspecialchars_uni($groupscache[$log['newusergroup']]['title']); + } + + if($log['type'] == "secondary") + { + $log['type'] = $lang->secondary; + } + else + { + $log['type'] = $lang->primary; + } + + $log['dateline'] = date($mybb->settings['dateformat'], $log['dateline']).", ".date($mybb->settings['timeformat'], $log['dateline']); + $table->construct_cell($log['username']); + $table->construct_cell($log['type'], array('style' => 'text-align: center;')); + $table->construct_cell($log['oldusergroup'], array('style' => 'text-align: center;')); + $table->construct_cell($log['newusergroup'], array('style' => 'text-align: center;')); + $table->construct_cell($log['dateline'], array('style' => 'text-align: center;')); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_promotion_logs, array("colspan" => "5")); + $table->construct_row(); + } + + $table->output($lang->promotion_logs); + + $query = $db->simple_select("promotionlogs", "COUNT(plid) as promotionlogs"); + $total_rows = $db->fetch_field($query, "promotionlogs"); + + echo "
".draw_admin_pagination($mybb->input['page'], "20", $total_rows, "index.php?module=user-group_promotions&action=logs&page={page}"); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_user_group_promotions_start"); + + $page->output_header($lang->promotion_manager); + + $page->output_nav_tabs($sub_tabs, 'usergroup_promotions'); + + $table = new Table; + $table->construct_header($lang->promotion); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 150)); + + $query = $db->simple_select("promotions", "*", "", array("order_by" => "title", "order_dir" => "asc")); + while($promotion = $db->fetch_array($query)) + { + $promotion['title'] = htmlspecialchars_uni($promotion['title']); + $promotion['description'] = htmlspecialchars_uni($promotion['description']); + if($promotion['enabled'] == 1) + { + $icon = "style}/images/icons/bullet_on.png\" alt=\"({$lang->alt_enabled})\" title=\"{$lang->alt_enabled}\" style=\"vertical-align: middle;\" /> "; + } + else + { + $icon = "style}/images/icons/bullet_off.png\" alt=\"({$lang->alt_disabled})\" title=\"{$lang->alt_disabled}\" style=\"vertical-align: middle;\" /> "; + } + + $table->construct_cell("
{$icon}{$promotion['title']}
{$promotion['description']}
"); + + $popup = new PopupMenu("promotion_{$promotion['pid']}", $lang->options); + $popup->add_item($lang->edit_promotion, "index.php?module=user-group_promotions&action=edit&pid={$promotion['pid']}"); + if($promotion['enabled'] == 1) + { + $popup->add_item($lang->disable_promotion, "index.php?module=user-group_promotions&action=disable&pid={$promotion['pid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_promo_disable}')"); + } + else + { + $popup->add_item($lang->enable_promotion, "index.php?module=user-group_promotions&action=enable&pid={$promotion['pid']}&my_post_key={$mybb->post_code}"); + } + $popup->add_item($lang->delete_promotion, "index.php?module=user-group_promotions&action=delete&pid={$promotion['pid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_promo_deletion}')"); + $table->construct_cell($popup->fetch(), array("class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_promotions_set, array("colspan" => "2")); + $table->construct_row(); + } + + $table->output($lang->user_group_promotions); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/user/groups.php b/Upload/admin/modules/user/groups.php new file mode 100644 index 0000000..058cd00 --- /dev/null +++ b/Upload/admin/modules/user/groups.php @@ -0,0 +1,1473 @@ + 0, + "canview" => 1, + "canviewthreads" => 1, + "canviewprofiles" => 1, + "candlattachments" => 1, + "canviewboardclosed" => 1, + "canpostthreads" => 1, + "canpostreplys" => 1, + "canpostattachments" => 1, + "canratethreads" => 1, + "modposts" => 0, + "modthreads" => 0, + "modattachments" => 0, + "mod_edit_posts" => 0, + "caneditposts" => 1, + "candeleteposts" => 1, + "candeletethreads" => 1, + "caneditattachments" => 1, + "canpostpolls" => 1, + "canvotepolls" => 1, + "canundovotes" => 0, + "canusepms" => 1, + "cansendpms" => 1, + "cantrackpms" => 1, + "candenypmreceipts" => 1, + "pmquota" => 100, + "maxpmrecipients" => 5, + "cansendemail" => 1, + "cansendemailoverride" => 0, + "maxemails" => 4, + "emailfloodtime" => 5, + "canviewmemberlist" => 1, + "canviewcalendar" => 1, + "canaddevents" => 1, + "canbypasseventmod" => 0, + "canmoderateevents" => 0, + "canviewonline" => 1, + "canviewwolinvis" => 0, + "canviewonlineips" => 0, + "cancp" => 0, + "issupermod" => 0, + "cansearch" => 1, + "canusercp" => 1, + "canuploadavatars" => 1, + "canratemembers" => 1, + "canchangename" => 0, + "canbereported" => 0, + "canchangewebsite" => 1, + "showforumteam" => 0, + "usereputationsystem" => 1, + "cangivereputations" => 1, + "reputationpower" => 1, + "maxreputationsday" => 5, + "maxreputationsperuser" => 5, + "maxreputationsperthread" => 5, + "candisplaygroup" => 0, + "attachquota" => 5000, + "cancustomtitle" => 0, + "canwarnusers" => 0, + "canreceivewarnings" => 1, + "maxwarningsday" => 0, + "canmodcp" => 0, + "showinbirthdaylist" => 0, + "canoverridepm" => 0, + "canusesig" => 0, + "canusesigxposts" => 0, + "signofollow" => 0, + "edittimelimit" => 0, + "maxposts" => 0, + "showmemberlist" => 1, + "canmanageannounce" => 0, + "canmanagemodqueue" => 0, + "canmanagereportedcontent" => 0, + "canviewmodlogs" => 0, + "caneditprofiles" => 0, + "canbanusers" => 0, + "canviewwarnlogs" => 0, + "canuseipsearch" => 0 +); + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->user_groups, "index.php?module=user-groups"); + +if($mybb->input['action'] == "add" || !$mybb->input['action']) +{ + $sub_tabs['manage_groups'] = array( + 'title' => $lang->manage_user_groups, + 'link' => "index.php?module=user-groups", + 'description' => $lang->manage_user_groups_desc + ); + $sub_tabs['add_group'] = array( + 'title' => $lang->add_user_group, + 'link' => "index.php?module=user-groups&action=add", + 'description' => $lang->add_user_group_desc + ); +} + +$plugins->run_hooks("admin_user_groups_begin"); + +if($mybb->input['action'] == "approve_join_request") +{ + $query = $db->simple_select("joinrequests", "*", "rid='".$mybb->input['rid']."'"); + $request = $db->fetch_array($query); + + if(!$request['rid']) + { + flash_message($lang->error_invalid_join_request, 'error'); + admin_redirect("index.php?module=user-groups"); + } + + if(!verify_post_check($mybb->input['my_post_key'])) + { + flash_message($lang->invalid_post_verify_key2, 'error'); + admin_redirect("index.php?module=user-groups&action=join_requests&gid={$request['gid']}"); + } + + $plugins->run_hooks("admin_user_groups_approve_join_request"); + + // Add the user to the group + join_usergroup($request['uid'], $request['gid']); + + // Delete the join request + $db->delete_query("joinrequests", "rid='{$request['rid']}'"); + + $plugins->run_hooks("admin_user_groups_approve_join_request_commit"); + + flash_message($lang->success_join_request_approved, "success"); + admin_redirect("index.php?module=user-groups&action=join_requests&gid={$request['gid']}"); +} + +if($mybb->input['action'] == "deny_join_request") +{ + $query = $db->simple_select("joinrequests", "*", "rid='".$mybb->input['rid']."'"); + $request = $db->fetch_array($query); + + if(!$request['rid']) + { + flash_message($lang->error_invalid_join_request, 'error'); + admin_redirect("index.php?module=user-groups"); + } + + if(!verify_post_check($mybb->input['my_post_key'])) + { + flash_message($lang->invalid_post_verify_key2, 'error'); + admin_redirect("index.php?module=user-groups&action=join_requests&gid={$request['gid']}"); + } + + $plugins->run_hooks("admin_user_groups_deny_join_request"); + + // Delete the join request + $db->delete_query("joinrequests", "rid='{$request['rid']}'"); + + $plugins->run_hooks("admin_user_groups_deny_join_request_commit"); + + flash_message($lang->success_join_request_denied, "success"); + admin_redirect("index.php?module=user-groups&action=join_requests&gid={$request['gid']}"); +} + +if($mybb->input['action'] == "join_requests") +{ + $query = $db->simple_select("usergroups", "*", "gid='".(int)$mybb->input['gid']."'"); + $group = $db->fetch_array($query); + + if(!$group['gid'] || $group['type'] != 4) + { + flash_message($lang->error_invalid_user_group, 'error'); + admin_redirect("index.php?module=user-groups"); + } + + $plugins->run_hooks("admin_user_groups_join_requests_start"); + + if($mybb->request_method == "post" && is_array($mybb->input['users'])) + { + $uid_in = implode(",", array_map('intval', $mybb->input['users'])); + + if(isset($mybb->input['approve'])) + { + foreach($mybb->input['users'] as $uid) + { + $uid = (int)$uid; + join_usergroup($uid, $group['gid']); + } + // Log admin action + log_admin_action("approve", $group['title'], $group['gid']); + $message = $lang->success_selected_requests_approved; + } + else + { + // Log admin action + log_admin_action("deny", $group['title'], $group['gid']); + $message = $lang->success_selected_requests_denied; + } + + $plugins->run_hooks("admin_user_groups_join_requests_commit"); + + // Go through and delete the join requests from the database + $db->delete_query("joinrequests", "uid IN ({$uid_in}) AND gid='{$group['gid']}'"); + + $plugins->run_hooks("admin_user_groups_join_requests_commit_end"); + + flash_message($message, 'success'); + admin_redirect("index.php?module=user-groups&action=join_requests&gid={$group['gid']}"); + } + + $page->add_breadcrumb_item($lang->join_requests_for." {$group['title']}"); + $page->output_header($lang->join_requests_for." {$group['title']}"); + + $sub_tabs = array(); + $sub_tabs['join_requests'] = array( + 'title' => $lang->group_join_requests, + 'link' => "index.php?module=user-groups&action=join_requests&gid={$group['gid']}", + 'description' => $lang->group_join_requests_desc + ); + + $page->output_nav_tabs($sub_tabs, 'join_requests'); + + $query = $db->simple_select("joinrequests", "COUNT(*) AS num_requests", "gid='{$group['gid']}'"); + $num_requests = $db->fetch_field($query, "num_requests"); + + $per_page = 20; + + if($mybb->input['page'] > 0) + { + $current_page = $mybb->get_input('page', 1); + $start = ($current_page-1)*$per_page; + $pages = $num_requests / $per_page; + $pages = ceil($pages); + if($current_page > $pages) + { + $start = 0; + $current_page = 1; + } + } + else + { + $start = 0; + $current_page = 1; + } + + // Do we need to construct the pagination? + $pagination = ''; + if($num_requests > $per_page) + { + $pagination = draw_admin_pagination($page, $per_page, $num_requests, "index.php?module=user-groups&action=join_requests&gid={$group['gid']}"); + echo $pagination; + } + + $form = new Form("index.php?module=user-groups&action=join_requests&gid={$group['gid']}", "post"); + $table = new Table; + $table->construct_header($form->generate_check_box("checkall", 1, "", array('class' => 'checkall')), array('width' => 1)); + $table->construct_header($lang->users); + $table->construct_header($lang->reason); + $table->construct_header($lang->date_requested, array("class" => 'align_center', "width" => 200)); + $table->construct_header($lang->controls, array("class" => "align_center", "width" => 200)); + + $query = $db->query(" + SELECT j.*, u.username + FROM ".TABLE_PREFIX."joinrequests j + INNER JOIN ".TABLE_PREFIX."users u ON (u.uid=j.uid) + WHERE j.gid='{$group['gid']}' + ORDER BY dateline ASC + LIMIT {$start}, {$per_page} + "); + + while($request = $db->fetch_array($query)) + { + $table->construct_cell($form->generate_check_box("users[]", $request['uid'], "")); + $table->construct_cell("".build_profile_link($request['username'], $request['uid'], "_blank").""); + $table->construct_cell(htmlspecialchars_uni($request['reason'])); + $table->construct_cell(my_date('relative', $request['dateline']), array('class' => 'align_center')); + + $popup = new PopupMenu("join_{$request['rid']}", $lang->options); + $popup->add_item($lang->approve, "index.php?module=user-groups&action=approve_join_request&rid={$request['rid']}&my_post_key={$mybb->post_code}"); + $popup->add_item($lang->deny, "index.php?module=user-groups&action=deny_join_request&rid={$request['rid']}&my_post_key={$mybb->post_code}"); + + $table->construct_cell($popup->fetch(), array('class' => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_join_requests, array("colspan" => 6)); + $table->construct_row(); + } + + $table->output($lang->join_requests_for." {$group['title']}"); + echo $pagination; + + $buttons[] = $form->generate_submit_button($lang->approve_selected_requests, array('name' => 'approve')); + $buttons[] = $form->generate_submit_button($lang->deny_selected_requests, array('name' => 'deny')); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} +if($mybb->input['action'] == "add_leader" && $mybb->request_method == "post") +{ + $query = $db->simple_select("usergroups", "*", "gid='".(int)$mybb->input['gid']."'"); + $group = $db->fetch_array($query); + + if(!$group['gid']) + { + flash_message($lang->error_invalid_user_group, 'error'); + admin_redirect("index.php?module=user-group"); + } + + $plugins->run_hooks("admin_user_groups_add_leader"); + + $user = get_user_by_username($mybb->input['username'], array('fields' => 'username')); + if(!$user['uid']) + { + $errors[] = $lang->error_invalid_username; + } + else + { + // Is this user already a leader of this group? + $query = $db->simple_select("groupleaders", "uid", "uid='{$user['uid']}' AND gid='{$group['gid']}'"); + $existing_leader = $db->fetch_field($query, "uid"); + if($existing_leader) + { + $errors[] = $lang->error_already_leader; + } + } + + // No errors, insert + if(!$errors) + { + $new_leader = array( + "gid" => $group['gid'], + "uid" => $user['uid'], + "canmanagemembers" => (int)$mybb->input['canmanagemembers'], + "canmanagerequests" => (int)$mybb->input['canmanagerequests'], + "caninvitemembers" => (int)$mybb->input['caninvitemembers'] + ); + + $plugins->run_hooks("admin_user_groups_add_leader_commit"); + + $db->insert_query("groupleaders", $new_leader); + + $cache->update_groupleaders(); + + // Log admin action + log_admin_action($user['uid'], $mybb->input['username'], $group['gid'], $group['title']); + + flash_message("{$user['username']} ".$lang->success_user_made_leader, 'success'); + admin_redirect("index.php?module=user-groups&action=leaders&gid={$group['gid']}"); + } + else + { + // Errors, show leaders page + $mybb->input['action'] = "leaders"; + } +} + +// Show a listing of group leaders +if($mybb->input['action'] == "leaders") +{ + $query = $db->simple_select("usergroups", "*", "gid='".(int)$mybb->input['gid']."'"); + $group = $db->fetch_array($query); + + if(!$group['gid']) + { + flash_message($lang->error_invalid_user_group, 'error'); + admin_redirect("index.php?module=user-groups"); + } + + $plugins->run_hooks("admin_user_groups_leaders"); + + $page->add_breadcrumb_item($lang->group_leaders_for." {$group['title']}"); + $page->output_header($lang->group_leaders_for." {$group['title']}"); + + $sub_tabs = array(); + $sub_tabs['group_leaders'] = array( + 'title' => $lang->manage_group_leaders, + 'link' => "index.php?module=user-groups&action=leaders&gid={$group['gid']}", + 'description' => $lang->manage_group_leaders_desc + ); + + $page->output_nav_tabs($sub_tabs, 'group_leaders'); + + $table = new Table; + $table->construct_header($lang->user); + $table->construct_header($lang->can_manage_members, array("class" => 'align_center', "width" => 200)); + $table->construct_header($lang->can_manage_join_requests, array("class" => 'align_center', "width" => 200)); + $table->construct_header($lang->can_invite_members, array("class" => 'align_center', "width" => 200)); + $table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 2, "width" => 200)); + + $query = $db->query(" + SELECT g.*, u.username + FROM ".TABLE_PREFIX."groupleaders g + INNER JOIN ".TABLE_PREFIX."users u ON (u.uid=g.uid) + WHERE g.gid='{$group['gid']}' + ORDER BY u.username ASC + "); + while($leader = $db->fetch_array($query)) + { + $leader['username'] = htmlspecialchars_uni($leader['username']); + if($leader['canmanagemembers']) + { + $canmanagemembers = $lang->yes; + } + else + { + $canmanagemembers = $lang->no; + } + + if($leader['canmanagerequests']) + { + $canmanagerequests = $lang->yes; + } + else + { + $canmanagerequests = $lang->no; + } + + if($leader['caninvitemembers']) + { + $caninvitemembers = $lang->yes; + } + else + { + $caninvitemembers = $lang->no; + } + + $table->construct_cell("".build_profile_link($leader['username'], $leader['uid'], "_blank").""); + $table->construct_cell($canmanagemembers, array("class" => "align_center")); + $table->construct_cell($canmanagerequests, array("class" => "align_center")); + $table->construct_cell($caninvitemembers, array("class" => "align_center")); + $table->construct_cell("{$lang->edit}", array("width" => 100, "class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->confirm_group_leader_deletion}')\">{$lang->delete}", array("width" => 100, "class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_assigned_leaders, array("colspan" => 5)); + $table->construct_row(); + } + + $table->output($lang->group_leaders_for." {$group['title']}"); + + $form = new Form("index.php?module=user-groups&action=add_leader&gid={$group['gid']}", "post"); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input = array_merge($mybb->input, array( + "canmanagemembers" => 1, + "canmanagerequests" => 1, + "caninvitemembers" => 1 + ) + ); + } + + $form_container = new FormContainer($lang->add_group_leader." {$group['title']}"); + $form_container->output_row($lang->username." *", "", $form->generate_text_box('username', $mybb->input['username'], array('id' => 'username')), 'username'); + $form_container->output_row($lang->can_manage_group_members, $lang->can_manage_group_members_desc, $form->generate_yes_no_radio('canmanagemembers', $mybb->input['canmanagemembers'])); + $form_container->output_row($lang->can_manage_group_join_requests, $lang->can_manage_group_join_requests_desc, $form->generate_yes_no_radio('canmanagerequests', $mybb->input['canmanagerequests'])); + $form_container->output_row($lang->can_invite_group_members, $lang->can_invite_group_members_desc, $form->generate_yes_no_radio('caninvitemembers', $mybb->input['caninvitemembers'])); + $buttons[] = $form->generate_submit_button($lang->save_group_leader); + + $form_container->end(); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete_leader") +{ + $query = $db->query(" + SELECT l.*, u.username + FROM ".TABLE_PREFIX."groupleaders l + INNER JOIN ".TABLE_PREFIX."users u ON (u.uid=l.uid) + WHERE l.lid='".(int)$mybb->input['lid']."'"); + $leader = $db->fetch_array($query); + + if(!$leader['lid']) + { + flash_message($lang->error_invalid_group_leader, 'error'); + admin_redirect("index.php?module=user-groups"); + } + + $query = $db->simple_select("usergroups", "*", "gid='{$leader['gid']}'"); + $group = $db->fetch_array($query); + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=user-groups"); + } + + $plugins->run_hooks("admin_user_groups_delete_leader"); + + if($mybb->request_method == "post") + { + $plugins->run_hooks("admin_user_groups_delete_leader_commit"); + + // Delete the leader + $db->delete_query("groupleaders", "lid='{$leader['lid']}'"); + + $plugins->run_hooks("admin_user_groups_delete_leader_commit_end"); + + $cache->update_groupleaders(); + + // Log admin action + log_admin_action($leader['lid'], $leader['username'], $group['gid'], $group['title']); + + flash_message($lang->success_group_leader_deleted, 'success'); + admin_redirect("index.php?module=user-groups&action=leaders&gid={$group['gid']}"); + } + else + { + $page->output_confirm_action("index.php?module=user-groups&action=delete_leader&lid={$leader['lid']}", $lang->confirm_group_leader_deletion); + } +} + +if($mybb->input['action'] == "edit_leader") +{ + $query = $db->query(" + SELECT l.*, u.username + FROM ".TABLE_PREFIX."groupleaders l + INNER JOIN ".TABLE_PREFIX."users u ON (u.uid=l.uid) + WHERE l.lid='".(int)$mybb->input['lid']."' + "); + $leader = $db->fetch_array($query); + + if(!$leader['lid']) + { + flash_message($lang->error_invalid_group_leader, 'error'); + admin_redirect("index.php?module=user-groups"); + } + + $query = $db->simple_select("usergroups", "*", "gid='{$leader['gid']}'"); + $group = $db->fetch_array($query); + + $plugins->run_hooks("admin_user_groups_edit_leader"); + + if($mybb->request_method == "post") + { + $updated_leader = array( + "canmanagemembers" => (int)$mybb->input['canmanagemembers'], + "canmanagerequests" => (int)$mybb->input['canmanagerequests'], + "caninvitemembers" => (int)$mybb->input['caninvitemembers'] + ); + + $plugins->run_hooks("admin_user_groups_edit_leader_commit"); + + $db->update_query("groupleaders", $updated_leader, "lid={$leader['lid']}"); + + $cache->update_groupleaders(); + + // Log admin action + log_admin_action($leader['lid'], $leader['username'], $group['gid'], $group['title']); + + flash_message($lang->success_group_leader_updated, 'success'); + admin_redirect("index.php?module=user-groups&action=leaders&gid={$group['gid']}"); + } + + if(!$errors) + { + $mybb->input = array_merge($mybb->input, $leader); + } + + $page->add_breadcrumb_item($lang->group_leaders_for." {$group['title']}", "index.php?module=user-groups&action=leaders&gid={$group['gid']}"); + $page->add_breadcrumb_item($lang->edit_leader." {$leader['username']}"); + + $page->output_header($lang->edit_group_leader); + + $sub_tabs = array(); + $sub_tabs['group_leaders'] = array( + 'title' => $lang->edit_group_leader, + 'link' => "index.php?module=user-groups&action=edit_leader&lid={$leader['lid']}", + 'description' => $lang->edit_group_leader_desc + ); + + $page->output_nav_tabs($sub_tabs, 'group_leaders'); + + $form = new Form("index.php?module=user-groups&action=edit_leader&lid={$leader['lid']}", "post"); + + $form_container = new FormContainer($lang->edit_group_leader); + $form_container->output_row($lang->username." *", "", $leader['username']); + + $form_container->output_row($lang->can_manage_group_members, $lang->can_manage_group_members_desc, $form->generate_yes_no_radio('canmanagemembers', $mybb->input['canmanagemembers'])); + $form_container->output_row($lang->can_manage_group_join_requests, $lang->can_manage_group_join_requests_desc, $form->generate_yes_no_radio('canmanagerequests', $mybb->input['canmanagerequests'])); + $form_container->output_row($lang->can_invite_group_members, $lang->can_invite_group_members_desc, $form->generate_yes_no_radio('caninvitemembers', $mybb->input['caninvitemembers'])); + $buttons[] = $form->generate_submit_button($lang->save_group_leader); + + $form_container->end(); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_user_groups_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + if(my_strpos($mybb->input['namestyle'], "{username}") === false) + { + $errors[] = $lang->error_missing_namestyle_username; + } + + if(!$errors) + { + if($mybb->input['stars'] < 1) + { + $mybb->input['stars'] = 0; + } + + if(!$mybb->input['starimage']) + { + $mybb->input['starimage'] = "images/star.png"; + } + + $new_usergroup = array( + "type" => 2, + "title" => $db->escape_string($mybb->input['title']), + "description" => $db->escape_string($mybb->input['description']), + "namestyle" => $db->escape_string($mybb->input['namestyle']), + "usertitle" => $db->escape_string($mybb->input['usertitle']), + "stars" => (int)$mybb->input['stars'], + "starimage" => $db->escape_string($mybb->input['starimage']), + "disporder" => 0 + ); + + // Set default permissions + if($mybb->input['copyfrom'] == 0) + { + $new_usergroup = array_merge($new_usergroup, $usergroup_permissions); + } + // Copying permissions from another group + else + { + $query = $db->simple_select("usergroups", "*", "gid='".(int)$mybb->input['copyfrom']."'"); + $existing_usergroup = $db->fetch_array($query); + foreach(array_keys($usergroup_permissions) as $field) + { + $new_usergroup[$field] = $existing_usergroup[$field]; + } + } + + $plugins->run_hooks("admin_user_groups_add_commit"); + + $gid = $db->insert_query("usergroups", $new_usergroup); + + $plugins->run_hooks("admin_user_groups_add_commit_end"); + + // Are we copying permissions? If so, copy all forum permissions too + if($mybb->input['copyfrom'] > 0) + { + $query = $db->simple_select("forumpermissions", "*", "gid='".(int)$mybb->input['copyfrom']."'"); + while($forum_permission = $db->fetch_array($query)) + { + unset($forum_permission['pid']); + $forum_permission['gid'] = $gid; + $db->insert_query("forumpermissions", $forum_permission); + } + } + + // Update the caches + $cache->update_usergroups(); + $cache->update_forumpermissions(); + + // Log admin action + log_admin_action($gid, $mybb->input['title']); + + flash_message($lang->success_group_created, 'success'); + admin_redirect("index.php?module=user-groups&action=edit&gid={$gid}"); + } + } + + $page->add_breadcrumb_item($lang->add_user_group); + $page->output_header($lang->add_user_group); + + $page->output_nav_tabs($sub_tabs, 'add_group'); + $form = new Form("index.php?module=user-groups&action=add", "post"); + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input = array_merge($mybb->input, array( + "namestyle" => "{username}" + ) + ); + } + + $form_container = new FormContainer($lang->add_user_group); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->short_description, "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + $form_container->output_row($lang->username_style, $lang->username_style_desc, $form->generate_text_box('namestyle', $mybb->input['namestyle'], array('id' => 'namestyle')), 'namestyle'); + $form_container->output_row($lang->user_title, $lang->user_title_desc, $form->generate_text_box('usertitle', $mybb->input['usertitle'], array('id' => 'usertitle')), 'usertitle'); + + $options[0] = $lang->do_not_copy_permissions; + $query = $db->simple_select("usergroups", "gid, title", "gid != '1'", array('order_by' => 'title')); + while($usergroup = $db->fetch_array($query)) + { + $options[$usergroup['gid']] = $usergroup['title']; + } + $form_container->output_row($lang->copy_permissions_from, $lang->copy_permissions_from_desc, $form->generate_select_box('copyfrom', $options, $mybb->input['copyfrom'], array('id' => 'copyfrom')), 'copyfrom'); + + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->save_user_group); + $form->output_submit_wrapper($buttons); + + $form->end(); + $page->output_footer(); +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("usergroups", "*", "gid='".(int)$mybb->input['gid']."'"); + $usergroup = $db->fetch_array($query); + + if(!$usergroup['gid']) + { + flash_message($lang->error_invalid_user_group, 'error'); + admin_redirect("index.php?module=user-group"); + } + else + { + if(preg_match("#<((m[^a])|(b[^diloru>])|(s[^aemptu>]))(\s*[^>]*)>#si", $mybb->input['namestyle'])) + { + $errors[] = $lang->error_disallowed_namestyle_username; + $mybb->input['namestyle'] = $usergroup['namestyle']; + } + } + + $plugins->run_hooks("admin_user_groups_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + if(my_strpos($mybb->input['namestyle'], "{username}") === false) + { + $errors[] = $lang->error_missing_namestyle_username; + } + + if($mybb->input['moderate'] == 1 && $mybb->input['invite'] == 1) + { + $errors[] = $lang->error_cannot_have_both_types; + } + + if(!$errors) + { + if($mybb->input['joinable'] == 1) + { + if($mybb->input['moderate'] == 1) + { + $mybb->input['type'] = "4"; + } + elseif($mybb->input['invite'] == 1) + { + $mybb->input['type'] = "5"; + } + else + { + $mybb->input['type'] = "3"; + } + } + else + { + $mybb->input['type'] = "2"; + } + + if($usergroup['type'] == 1) + { + $mybb->input['type'] = 1; + } + + if($mybb->input['stars'] < 1) + { + $mybb->input['stars'] = 0; + } + + $updated_group = array( + "type" => $mybb->get_input('type', 1), + "title" => $db->escape_string($mybb->input['title']), + "description" => $db->escape_string($mybb->input['description']), + "namestyle" => $db->escape_string($mybb->input['namestyle']), + "usertitle" => $db->escape_string($mybb->input['usertitle']), + "stars" => (int)$mybb->input['stars'], + "starimage" => $db->escape_string($mybb->input['starimage']), + "image" => $db->escape_string($mybb->input['image']), + "isbannedgroup" => (int)$mybb->input['isbannedgroup'], + "canview" => (int)$mybb->input['canview'], + "canviewthreads" => (int)$mybb->input['canviewthreads'], + "canviewprofiles" => (int)$mybb->input['canviewprofiles'], + "candlattachments" => (int)$mybb->input['candlattachments'], + "canviewboardclosed" => (int)$mybb->input['canviewboardclosed'], + "canpostthreads" => (int)$mybb->input['canpostthreads'], + "canpostreplys" => (int)$mybb->input['canpostreplys'], + "canpostattachments" => (int)$mybb->input['canpostattachments'], + "canratethreads" => (int)$mybb->input['canratethreads'], + "modposts" => (int)$mybb->input['modposts'], + "modthreads" => (int)$mybb->input['modthreads'], + "mod_edit_posts" => (int)$mybb->input['mod_edit_posts'], + "modattachments" => (int)$mybb->input['modattachments'], + "caneditposts" => (int)$mybb->input['caneditposts'], + "candeleteposts" => (int)$mybb->input['candeleteposts'], + "candeletethreads" => (int)$mybb->input['candeletethreads'], + "caneditattachments" => (int)$mybb->input['caneditattachments'], + "canpostpolls" => (int)$mybb->input['canpostpolls'], + "canvotepolls" => (int)$mybb->input['canvotepolls'], + "canundovotes" => (int)$mybb->input['canundovotes'], + "canusepms" => (int)$mybb->input['canusepms'], + "cansendpms" => (int)$mybb->input['cansendpms'], + "cantrackpms" => (int)$mybb->input['cantrackpms'], + "candenypmreceipts" => (int)$mybb->input['candenypmreceipts'], + "pmquota" => (int)$mybb->input['pmquota'], + "maxpmrecipients" => (int)$mybb->input['maxpmrecipients'], + "cansendemail" => (int)$mybb->input['cansendemail'], + "cansendemailoverride" => (int)$mybb->input['cansendemailoverride'], + "maxemails" => (int)$mybb->input['maxemails'], + "emailfloodtime" => (int)$mybb->input['emailfloodtime'], + "canviewmemberlist" => (int)$mybb->input['canviewmemberlist'], + "canviewcalendar" => (int)$mybb->input['canviewcalendar'], + "canaddevents" => (int)$mybb->input['canaddevents'], + "canbypasseventmod" => (int)$mybb->input['canbypasseventmod'], + "canmoderateevents" => (int)$mybb->input['canmoderateevents'], + "canviewonline" => (int)$mybb->input['canviewonline'], + "canviewwolinvis" => (int)$mybb->input['canviewwolinvis'], + "canviewonlineips" => (int)$mybb->input['canviewonlineips'], + "cancp" => (int)$mybb->input['cancp'], + "issupermod" => (int)$mybb->input['issupermod'], + "cansearch" => (int)$mybb->input['cansearch'], + "canusercp" => (int)$mybb->input['canusercp'], + "canuploadavatars" => (int)$mybb->input['canuploadavatars'], + "canchangename" => (int)$mybb->input['canchangename'], + "canbereported" => (int)$mybb->input['canbereported'], + "canchangewebsite" => (int)$mybb->input['canchangewebsite'], + "showforumteam" => (int)$mybb->input['showforumteam'], + "usereputationsystem" => (int)$mybb->input['usereputationsystem'], + "cangivereputations" => (int)$mybb->input['cangivereputations'], + "reputationpower" => (int)$mybb->input['reputationpower'], + "maxreputationsday" => (int)$mybb->input['maxreputationsday'], + "maxreputationsperuser" => (int)$mybb->input['maxreputationsperuser'], + "maxreputationsperthread" => (int)$mybb->input['maxreputationsperthread'], + "attachquota" => (int)$mybb->input['attachquota'], + "cancustomtitle" => (int)$mybb->input['cancustomtitle'], + "canwarnusers" => (int)$mybb->input['canwarnusers'], + "canreceivewarnings" =>(int)$mybb->input['canreceivewarnings'], + "maxwarningsday" => (int)$mybb->input['maxwarningsday'], + "canmodcp" => (int)$mybb->input['canmodcp'], + "showinbirthdaylist" => (int)$mybb->input['showinbirthdaylist'], + "canoverridepm" => (int)$mybb->input['canoverridepm'], + "canusesig" => (int)$mybb->input['canusesig'], + "canusesigxposts" => (int)$mybb->input['canusesigxposts'], + "signofollow" => (int)$mybb->input['signofollow'], + "edittimelimit" => (int)$mybb->input['edittimelimit'], + "maxposts" => (int)$mybb->input['maxposts'], + "showmemberlist" => (int)$mybb->input['showmemberlist'], + "canmanageannounce" => (int)$mybb->input['canmanageannounce'], + "canmanagemodqueue" => (int)$mybb->input['canmanagemodqueue'], + "canmanagereportedcontent" => (int)$mybb->input['canmanagereportedcontent'], + "canviewmodlogs" => (int)$mybb->input['canviewmodlogs'], + "caneditprofiles" => (int)$mybb->input['caneditprofiles'], + "canbanusers" => (int)$mybb->input['canbanusers'], + "canviewwarnlogs" => (int)$mybb->input['canviewwarnlogs'], + "canuseipsearch" => (int)$mybb->input['canuseipsearch'] + ); + + // Only update the candisplaygroup setting if not a default user group + if($usergroup['type'] != 1) + { + $updated_group['candisplaygroup'] = (int)$mybb->input['candisplaygroup']; + } + + $plugins->run_hooks("admin_user_groups_edit_commit"); + + $db->update_query("usergroups", $updated_group, "gid='{$usergroup['gid']}'"); + + // Update the caches + $cache->update_usergroups(); + $cache->update_forumpermissions(); + + // Log admin action + log_admin_action($usergroup['gid'], $mybb->input['title']); + + flash_message($lang->success_group_updated, 'success'); + admin_redirect("index.php?module=user-groups"); + } + } + + $page->add_breadcrumb_item($lang->edit_user_group); + $page->output_header($lang->edit_user_group); + + $sub_tabs = array(); + $sub_tabs['edit_group'] = array( + 'title' => $lang->edit_user_group, + 'description' => $lang->edit_user_group_desc + ); + + $form = new Form("index.php?module=user-groups&action=edit&gid={$usergroup['gid']}", "post"); + + $page->output_nav_tabs($sub_tabs, 'edit_group'); + + // If we have any error messages, show them + if($errors) + { + $page->output_inline_error($errors); + } + else + { + if($usergroup['type'] == "3") + { + $usergroup['joinable'] = 1; + $usergroup['moderate'] = 0; + $usergroup['invite'] = 0; + } + elseif($usergroup['type'] == "4") + { + $usergroup['joinable'] = 1; + $usergroup['moderate'] = 1; + $usergroup['invite'] = 0; + } + elseif($usergroup['type'] == "5") + { + $usergroup['joinable'] = 1; + $usergroup['moderate'] = 0; + $usergroup['invite'] = 1; + } + else + { + $usergroup['joinable'] = 0; + $usergroup['moderate'] = 0; + $usergroup['invite'] = 0; + } + $mybb->input = array_merge($mybb->input, $usergroup); + } + $tabs = array( + "general" => $lang->general, + "forums_posts" => $lang->forums_posts, + "users_permissions" => $lang->users_permissions, + "misc" => $lang->misc, + "modcp" => $lang->mod_cp + ); + $tabs = $plugins->run_hooks("admin_user_groups_edit_graph_tabs", $tabs); + $page->output_tab_control($tabs); + + echo "
"; + $form_container = new FormContainer($lang->general); + $form_container->output_row($lang->title." *", "", $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->short_description, "", $form->generate_text_box('description', $mybb->input['description'], array('id' => 'description')), 'description'); + $form_container->output_row($lang->username_style, $lang->username_style_desc, $form->generate_text_box('namestyle', $mybb->input['namestyle'], array('id' => 'namestyle')), 'namestyle'); + $form_container->output_row($lang->user_title, $lang->user_title_desc, $form->generate_text_box('usertitle', $mybb->input['usertitle'], array('id' => 'usertitle')), 'usertitle'); + + $stars = ""; + $stars .= "
".$form->generate_numeric_field('stars', $mybb->input['stars'], array('class' => 'field50', 'id' => 'stars'))."".$form->generate_text_box('starimage', $mybb->input['starimage'], array('id' => 'starimage'))."
{$lang->stars}{$lang->star_image}
"; + $form_container->output_row($lang->user_stars, $lang->user_stars_desc, $stars, "stars"); + + $form_container->output_row($lang->group_image, $lang->group_image_desc, $form->generate_text_box('image', $mybb->input['image'], array('id' => 'image')), 'image'); + + $general_options = array(); + $general_options[] = $form->generate_check_box("showmemberlist", 1, $lang->member_list, array("checked" => $mybb->input['showmemberlist'])); + if($usergroup['gid'] != "1" && $usergroup['gid'] != "5") + { + $general_options[] = $form->generate_check_box("showforumteam", 1, $lang->forum_team, array("checked" => $mybb->input['showforumteam'])); + } + $general_options[] = $form->generate_check_box("isbannedgroup", 1, $lang->is_banned_group, array("checked" => $mybb->input['isbannedgroup'])); + + $form_container->output_row($lang->general_options, "", "
".implode("
", $general_options)."
"); + + if($usergroup['type'] != 1) + { + $public_options = array( + $form->generate_check_box("joinable", 1, $lang->user_joinable, array("checked" => $mybb->input['joinable'])), + $form->generate_check_box("moderate", 1, $lang->moderate_join_requests, array("checked" => $mybb->input['moderate'])), + $form->generate_check_box("invite", 1, $lang->invite_only, array("checked" => $mybb->input['invite'])), + $form->generate_check_box("candisplaygroup", 1, $lang->can_set_as_display_group, array("checked" => $mybb->input['candisplaygroup'])), + ); + $form_container->output_row($lang->publicly_joinable_options, "", "
".implode("
", $public_options)."
"); + } + + $admin_options = array( + $form->generate_check_box("issupermod", 1, $lang->is_super_mod, array("checked" => $mybb->input['issupermod'])), + $form->generate_check_box("canmodcp", 1, $lang->can_access_mod_cp, array("checked" => $mybb->input['canmodcp'])), + $form->generate_check_box("cancp", 1, $lang->can_access_admin_cp, array("checked" => $mybb->input['cancp'])) + ); + $form_container->output_row($lang->moderation_administration_options, "", "
".implode("
", $admin_options)."
"); + + $form_container->end(); + echo "
"; + + // + // FORUMS AND POSTS + // + echo "
"; + $form_container = new FormContainer($lang->forums_posts); + + $viewing_options = array( + $form->generate_check_box("canview", 1, $lang->can_view_board, array("checked" => $mybb->input['canview'])), + $form->generate_check_box("canviewthreads", 1, $lang->can_view_threads, array("checked" => $mybb->input['canviewthreads'])), + $form->generate_check_box("cansearch", 1, $lang->can_search_forums, array("checked" => $mybb->input['cansearch'])), + $form->generate_check_box("canviewprofiles", 1, $lang->can_view_profiles, array("checked" => $mybb->input['canviewprofiles'])), + $form->generate_check_box("candlattachments", 1, $lang->can_download_attachments, array("checked" => $mybb->input['candlattachments'])), + $form->generate_check_box("canviewboardclosed", 1, $lang->can_view_board_closed, array("checked" => $mybb->input['canviewboardclosed'])) + ); + $form_container->output_row($lang->viewing_options, "", "
".implode("
", $viewing_options)."
"); + + $posting_options = array( + $form->generate_check_box("canpostthreads", 1, $lang->can_post_threads, array("checked" => $mybb->input['canpostthreads'])), + $form->generate_check_box("canpostreplys", 1, $lang->can_post_replies, array("checked" => $mybb->input['canpostreplys'])), + $form->generate_check_box("canratethreads", 1, $lang->can_rate_threads, array("checked" => $mybb->input['canratethreads'])), + "{$lang->max_posts_per_day}
{$lang->max_posts_per_day_desc}
".$form->generate_numeric_field('maxposts', $mybb->input['maxposts'], array('id' => 'maxposts', 'class' => 'field50')) + ); + $form_container->output_row($lang->posting_rating_options, "", "
".implode("
", $posting_options)."
"); + + $moderator_options = array( + $form->generate_check_box("modposts", 1, $lang->mod_new_posts, array("checked" => $mybb->input['modposts'])), + $form->generate_check_box("modthreads", 1, $lang->mod_new_threads, array("checked" => $mybb->input['modthreads'])), + $form->generate_check_box("modattachments", 1, $lang->mod_new_attachments, array("checked" => $mybb->input['modattachments'])), + $form->generate_check_box("mod_edit_posts", 1, $lang->mod_after_edit, array("checked" => $mybb->input['mod_edit_posts'])) + ); + $form_container->output_row($lang->moderation_options, "", "
".implode("
", $moderator_options)."
"); + + $poll_options = array( + $form->generate_check_box("canpostpolls", 1, $lang->can_post_polls, array("checked" => $mybb->input['canpostpolls'])), + $form->generate_check_box("canvotepolls", 1, $lang->can_vote_polls, array("checked" => $mybb->input['canvotepolls'])), + $form->generate_check_box("canundovotes", 1, $lang->can_undo_votes, array("checked" => $mybb->input['canundovotes'])) + ); + $form_container->output_row($lang->poll_options, "", "
".implode("
", $poll_options)."
"); + + $attachment_options = array( + $form->generate_check_box("canpostattachments", 1, $lang->can_post_attachments, array("checked" => $mybb->input['canpostattachments'])), + "{$lang->attach_quota}
{$lang->attach_quota_desc}
".$form->generate_numeric_field('attachquota', $mybb->input['attachquota'], array('id' => 'attachquota', 'class' => 'field50')). "KB" + ); + $form_container->output_row($lang->attachment_options, "", "
".implode("
", $attachment_options)."
"); + + $editing_options = array( + $form->generate_check_box("caneditposts", 1, $lang->can_edit_posts, array("checked" => $mybb->input['caneditposts'])), + $form->generate_check_box("candeleteposts", 1, $lang->can_delete_posts, array("checked" => $mybb->input['candeleteposts'])), + $form->generate_check_box("candeletethreads", 1, $lang->can_delete_threads, array("checked" => $mybb->input['candeletethreads'])), + $form->generate_check_box("caneditattachments", 1, $lang->can_edit_attachments, array("checked" => $mybb->input['caneditattachments'])), + "{$lang->edit_time_limit}
{$lang->edit_time_limit_desc}
".$form->generate_numeric_field('edittimelimit', $mybb->input['edittimelimit'], array('id' => 'edittimelimit', 'class' => 'field50')) + ); + $form_container->output_row($lang->editing_deleting_options, "", "
".implode("
", $editing_options)."
"); + + $form_container->end(); + echo "
"; + + // + // USERS AND PERMISSIONS + // + echo "
"; + $form_container = new FormContainer($lang->users_permissions); + + $account_options = array( + $form->generate_check_box("canbereported", 1, $lang->can_be_reported, array("checked" => $mybb->input['canbereported'])), + $form->generate_check_box("canusercp", 1, $lang->can_access_usercp, array("checked" => $mybb->input['canusercp'])), + $form->generate_check_box("canchangename", 1, $lang->can_change_username, array("checked" => $mybb->input['canchangename'])), + $form->generate_check_box("cancustomtitle", 1, $lang->can_use_usertitles, array("checked" => $mybb->input['cancustomtitle'])), + $form->generate_check_box("canuploadavatars", 1, $lang->can_upload_avatars, array("checked" => $mybb->input['canuploadavatars'])), + $form->generate_check_box("canusesig", 1, $lang->can_use_signature, array("checked" => $mybb->input['canusesig'])), + $form->generate_check_box("signofollow", 1, $lang->uses_no_follow, array("checked" => $mybb->input['signofollow'])), + $form->generate_check_box("canchangewebsite", 1, $lang->can_change_website, array("checked" => $mybb->input['canchangewebsite'])), + "{$lang->required_posts}
{$lang->required_posts_desc}
".$form->generate_numeric_field('canusesigxposts', $mybb->input['canusesigxposts'], array('id' => 'canusesigxposts', 'class' => 'field50')) + ); + $form_container->output_row($lang->account_management, "", "
".implode("
", $account_options)."
"); + + $reputation_options = array( + $form->generate_check_box("usereputationsystem", 1, $lang->show_reputations, array("checked" => $mybb->input['usereputationsystem'])), + $form->generate_check_box("cangivereputations", 1, $lang->can_give_reputation, array("checked" => $mybb->input['cangivereputations'])), + "{$lang->points_to_award_take}
{$lang->points_to_award_take_desc}
".$form->generate_numeric_field('reputationpower', $mybb->input['reputationpower'], array('id' => 'reputationpower', 'class' => 'field50')), + "{$lang->max_reputations_perthread}
{$lang->max_reputations_perthread_desc}
".$form->generate_numeric_field('maxreputationsperthread', $mybb->input['maxreputationsperthread'], array('id' => 'maxreputationsperthread', 'class' => 'field50')), + "{$lang->max_reputations_daily}
{$lang->max_reputations_daily_desc}
".$form->generate_numeric_field('maxreputationsday', $mybb->input['maxreputationsday'], array('id' => 'maxreputationsday', 'class' => 'field50')) + ); + $form_container->output_row($lang->reputation_system, "", "
".implode("
", $reputation_options)."
"); + + $warning_options = array( + $form->generate_check_box("canwarnusers", 1, $lang->can_send_warnings, array("checked" => $mybb->input['canwarnusers'])), + $form->generate_check_box("canreceivewarnings", 1, $lang->can_receive_warnings, array("checked" => $mybb->input['canreceivewarnings'])), + "{$lang->warnings_per_day}
".$form->generate_numeric_field('maxwarningsday', $mybb->input['maxwarningsday'], array('id' => 'maxwarningsday', 'class' => 'field50')) + ); + $form_container->output_row($lang->warning_system, "", "
".implode("
", $warning_options)."
"); + + $pm_options = array( + $form->generate_check_box("canusepms", 1, $lang->can_use_pms, array("checked" => $mybb->input['canusepms'])), + $form->generate_check_box("cansendpms", 1, $lang->can_send_pms, array("checked" => $mybb->input['cansendpms'])), + $form->generate_check_box("canoverridepm", 1, $lang->can_override_pms, array("checked" => $mybb->input['canoverridepm'])), + $form->generate_check_box("cantrackpms", 1, $lang->can_track_pms, array("checked" => $mybb->input['cantrackpms'])), + $form->generate_check_box("candenypmreceipts", 1, $lang->can_deny_reciept, array("checked" => $mybb->input['candenypmreceipts'])), + "{$lang->message_quota}
{$lang->message_quota_desc}
".$form->generate_numeric_field('pmquota', $mybb->input['pmquota'], array('id' => 'pmquota', 'class' => 'field50')), + "{$lang->max_recipients}
{$lang->max_recipients_desc}
".$form->generate_numeric_field('maxpmrecipients', $mybb->input['maxpmrecipients'], array('id' => 'maxpmrecipients', 'class' => 'field50')) + ); + $form_container->output_row($lang->private_messaging, "", "
".implode("
", $pm_options)."
"); + + $form_container->end(); + echo "
"; + + // + // MISC + // + echo "
"; + $form_container = new FormContainer($lang->misc); + + $calendar_options = array( + $form->generate_check_box("canviewcalendar", 1, $lang->can_view_calendar, array("checked" => $mybb->input['canviewcalendar'])), + $form->generate_check_box("canaddevents", 1, $lang->can_post_events, array("checked" => $mybb->input['canaddevents'])), + $form->generate_check_box("canbypasseventmod", 1, $lang->can_bypass_event_moderation, array("checked" => $mybb->input['canbypasseventmod'])), + $form->generate_check_box("canmoderateevents", 1, $lang->can_moderate_events, array("checked" => $mybb->input['canmoderateevents'])) + ); + $form_container->output_row($lang->calendar, "", "
".implode("
", $calendar_options)."
"); + + $wol_options = array( + $form->generate_check_box("canviewonline", 1, $lang->can_view_whos_online, array("checked" => $mybb->input['canviewonline'])), + $form->generate_check_box("canviewwolinvis", 1, $lang->can_view_invisible, array("checked" => $mybb->input['canviewwolinvis'])), + $form->generate_check_box("canviewonlineips", 1, $lang->can_view_ips, array("checked" => $mybb->input['canviewonlineips'])) + ); + $form_container->output_row($lang->whos_online, "", "
".implode("
", $wol_options)."
"); + + $misc_options = array( + $form->generate_check_box("canviewmemberlist", 1, $lang->can_view_member_list, array("checked" => $mybb->input['canviewmemberlist'])), + $form->generate_check_box("showinbirthdaylist", 1, $lang->show_in_birthday_list, array("checked" => $mybb->input['showinbirthdaylist'])), + $form->generate_check_box("cansendemail", 1, $lang->can_email_users, array("checked" => $mybb->input['cansendemail'])), + $form->generate_check_box("cansendemailoverride", 1, $lang->can_email_users_override, array("checked" => $mybb->input['cansendemailoverride'])), + "{$lang->max_emails_per_day}
{$lang->max_emails_per_day_desc}
".$form->generate_numeric_field('maxemails', $mybb->input['maxemails'], array('id' => 'maxemails', 'class' => 'field50')), + "{$lang->email_flood_time}
{$lang->email_flood_time_desc}
".$form->generate_numeric_field('emailfloodtime', $mybb->input['emailfloodtime'], array('id' => 'emailfloodtime', 'class' => 'field50')) + ); + $form_container->output_row($lang->misc, "", "
".implode("
", $misc_options)."
"); + + $form_container->end(); + echo "
"; + + // + // MODERATOR CP + // + echo "
"; + $form_container = new FormContainer($lang->mod_cp); + + $forum_post_options = array( + $form->generate_check_box("canmanageannounce", 1, $lang->can_manage_announce, array("checked" => $mybb->input['canmanageannounce'])), + $form->generate_check_box("canmanagemodqueue", 1, $lang->can_manage_mod_queue, array("checked" => $mybb->input['canmanagemodqueue'])), + $form->generate_check_box("canmanagereportedcontent", 1, $lang->can_manage_reported_content, array("checked" => $mybb->input['canmanagereportedcontent'])), + $form->generate_check_box("canviewmodlogs", 1, $lang->can_view_mod_logs, array("checked" => $mybb->input['canviewmodlogs'])) + ); + $form_container->output_row($lang->forum_post_options, "", "
".implode("
", $forum_post_options)."
"); + + $user_options = array( + $form->generate_check_box("caneditprofiles", 1, $lang->can_edit_profiles, array("checked" => $mybb->input['caneditprofiles'])), + $form->generate_check_box("canbanusers", 1, $lang->can_ban_users, array("checked" => $mybb->input['canbanusers'])), + $form->generate_check_box("canviewwarnlogs", 1, $lang->can_view_warnlogs, array("checked" => $mybb->input['canviewwarnlogs'])), + $form->generate_check_box("canuseipsearch", 1, $lang->can_use_ipsearch, array("checked" => $mybb->input['canuseipsearch'])) + ); + $form_container->output_row($lang->user_options, "", "
".implode("
", $user_options)."
"); + + $form_container->end(); + echo "
"; + + $plugins->run_hooks("admin_user_groups_edit_graph"); + + $buttons[] = $form->generate_submit_button($lang->save_user_group); + $form->output_submit_wrapper($buttons); + + $form->end(); + $page->output_footer(); +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("usergroups", "*", "gid='".(int)$mybb->input['gid']."'"); + $usergroup = $db->fetch_array($query); + + if(!$usergroup['gid']) + { + flash_message($lang->error_invalid_user_group, 'error'); + admin_redirect("index.php?module=user-groups"); + } + if($usergroup['type'] == 1) + { + flash_message($lang->error_default_group_delete, 'error'); + admin_redirect("index.php?module=user-groups"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=user-groups"); + } + + $plugins->run_hooks("admin_user_groups_delete"); + + if($mybb->request_method == "post") + { + // Move any users back to the registered group + $updated_users = array("usergroup" => 2); + $db->update_query("users", $updated_users, "usergroup='{$usergroup['gid']}'"); + + $updated_users = array("displaygroup" => "usergroup"); + $plugins->run_hooks("admin_user_groups_delete_commit"); + + $db->update_query("users", $updated_users, "displaygroup='{$usergroup['gid']}'", "", true); // No quotes = displaygroup=usergroup + + switch($db->type) + { + case "pgsql": + case "sqlite": + $query = $db->simple_select("users", "uid", "','||additionalgroups||',' LIKE '%,{$usergroup['gid']},%'"); + break; + default: + $query = $db->simple_select("users", "uid", "CONCAT(',',additionalgroups,',') LIKE '%,{$usergroup['gid']},%'"); + } + while($user = $db->fetch_array($query)) + { + leave_usergroup($user['uid'], $usergroup['gid']); + } + + $db->delete_query("groupleaders", "gid='{$usergroup['gid']}'"); + $db->delete_query("usergroups", "gid='{$usergroup['gid']}'"); + + $plugins->run_hooks("admin_user_groups_delete_commit_end"); + + $cache->update_groupleaders(); + $cache->update_moderators(); + $cache->update_usergroups(); + $cache->update_forumpermissions(); + + // Log admin action + log_admin_action($usergroup['gid'], $usergroup['title']); + + flash_message($lang->success_group_deleted, 'success'); + admin_redirect("index.php?module=user-groups"); + } + else + { + $page->output_confirm_action("index.php?module=user-groups&action=delete&gid={$usergroup['gid']}", $lang->confirm_group_deletion); + } +} + +if($mybb->input['action'] == "disporder" && $mybb->request_method == "post") +{ + $plugins->run_hooks("admin_user_groups_disporder"); + + foreach($mybb->input['disporder'] as $gid=>$order) + { + $gid = (int)$gid; + $order = (int)$order; + if($gid != 0 && $order != 0) + { + $sql_array = array( + 'disporder' => $order, + ); + $db->update_query('usergroups', $sql_array, "gid = '{$gid}'"); + } + } + + // Log admin action + log_admin_action(); + + $plugins->run_hooks("admin_user_groups_disporder_commit"); + + flash_message($lang->success_group_disporders_updated, 'success'); + admin_redirect("index.php?module=user-groups"); +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_user_groups_start"); + + if($mybb->request_method == "post") + { + if(!empty($mybb->input['disporder'])) + { + foreach($mybb->input['disporder'] as $gid => $order) + { + $db->update_query("usergroups", array('disporder' => (int)$order), "gid='".(int)$gid."'"); + } + + $plugins->run_hooks("admin_user_groups_start_commit"); + + $cache->update_usergroups(); + + flash_message($lang->success_groups_disporder_updated, 'success'); + admin_redirect("index.php?module=user-groups"); + } + } + + $page->output_header($lang->manage_user_groups); + $page->output_nav_tabs($sub_tabs, 'manage_groups'); + + $form = new Form("index.php?module=user-groups", "post", "groups"); + + $query = $db->query(" + SELECT g.gid, COUNT(u.uid) AS users + FROM ".TABLE_PREFIX."users u + LEFT JOIN ".TABLE_PREFIX."usergroups g ON (g.gid=u.usergroup) + GROUP BY g.gid + "); + while($groupcount = $db->fetch_array($query)) + { + $primaryusers[$groupcount['gid']] = $groupcount['users']; + } + + switch($db->type) + { + case "pgsql": + case "sqlite": + $query = $db->query(" + SELECT g.gid, COUNT(u.uid) AS users + FROM ".TABLE_PREFIX."users u + LEFT JOIN ".TABLE_PREFIX."usergroups g ON (','|| u.additionalgroups|| ',' LIKE '%,'|| g.gid|| ',%') + WHERE g.gid != '0' AND g.gid is not NULL GROUP BY g.gid + "); + break; + default: + $query = $db->query(" + SELECT g.gid, COUNT(u.uid) AS users + FROM ".TABLE_PREFIX."users u + LEFT JOIN ".TABLE_PREFIX."usergroups g ON (CONCAT(',', u.additionalgroups, ',') LIKE CONCAT('%,', g.gid, ',%')) + WHERE g.gid != '0' AND g.gid is not NULL GROUP BY g.gid + "); + } + while($groupcount = $db->fetch_array($query)) + { + $secondaryusers[$groupcount['gid']] = $groupcount['users']; + } + + $query = $db->query(" + SELECT g.gid, COUNT(r.uid) AS users + FROM ".TABLE_PREFIX."joinrequests r + LEFT JOIN ".TABLE_PREFIX."usergroups g ON (g.gid=r.gid) + GROUP BY g.gid + "); + + $joinrequests = array(); + while($joinrequest = $db->fetch_array($query)) + { + $joinrequests[$joinrequest['gid']] = $joinrequest['users']; + } + + // Fetch group leaders + $leaders = array(); + $query = $db->query(" + SELECT u.username, u.uid, l.gid + FROM ".TABLE_PREFIX."groupleaders l + INNER JOIN ".TABLE_PREFIX."users u ON (u.uid=l.uid) + ORDER BY u.username ASC + "); + while($leader = $db->fetch_array($query)) + { + $leaders[$leader['gid']][] = build_profile_link($leader['username'], $leader['uid'], "_blank"); + } + + $form_container = new FormContainer($lang->user_groups); + $form_container->output_row_header($lang->group); + $form_container->output_row_header($lang->number_of_users, array("class" => "align_center", 'width' => '75')); + $form_container->output_row_header($lang->order, array("class" => "align_center", 'width' => '5%')); + $form_container->output_row_header($lang->controls, array("class" => "align_center")); + + $query = $db->simple_select("usergroups", "*", "", array('order_by' => 'disporder')); + while($usergroup = $db->fetch_array($query)) + { + if($usergroup['type'] > 1) + { + $icon = "\"{$lang-custom_user_group}\" style=\"vertical-align: middle;\" />"; + } + else + { + $icon = "\"{$lang-default_user_group}\" style=\"vertical-align: middle;\" />"; + } + + $leaders_list = ''; + if(isset($leaders[$usergroup['gid']])) + { + $leaders_list = "
{$lang->group_leaders}: ".implode(", ", $leaders[$usergroup['gid']]); + } + + $join_requests = ''; + if($joinrequests[$usergroup['gid']] > 1 && $usergroup['type'] == 4) + { + $join_requests = " ({$joinrequests[$usergroup['gid']]} {$lang->outstanding_join_request})"; + } + else if($joinrequests[$usergroup['gid']] == 1 && $usergroup['type'] == 4) + { + $join_requests = " ({$joinrequests[$usergroup['gid']]} {$lang->outstanding_join_request})"; + } + + $form_container->output_cell("
{$icon}
{$usergroup['title']}{$join_requests}
{$usergroup['description']}{$leaders_list}
"); + + if(!$primaryusers[$usergroup['gid']]) + { + $primaryusers[$usergroup['gid']] = 0; + } + $numusers = $primaryusers[$usergroup['gid']]; + $numusers += $secondaryusers[$usergroup['gid']]; + + $form_container->output_cell(my_number_format($numusers), array("class" => "align_center")); + + if($usergroup['showforumteam'] == 1) + { + $form_container->output_cell("", array("class" => "align_center")); + } + else + { + $form_container->output_cell(" ", array("class" => "align_center")); + } + + $popup = new PopupMenu("usergroup_{$usergroup['gid']}", $lang->options); + $popup->add_item($lang->edit_group, "index.php?module=user-groups&action=edit&gid={$usergroup['gid']}"); + $popup->add_item($lang->list_users, "index.php?module=user-users&action=search&results=1&conditions[usergroup]={$usergroup['gid']}"); + if($joinrequests[$usergroup['gid']] > 0 && $usergroup['type'] == 4) + { + $popup->add_item($lang->join_requests, "index.php?module=user-groups&action=join_requests&gid={$usergroup['gid']}"); + } + $popup->add_item($lang->group_leaders, "index.php?module=user-groups&action=leaders&gid={$usergroup['gid']}"); + if($usergroup['type'] > 1) + { + $popup->add_item($lang->delete_group, "index.php?module=user-groups&action=delete&gid={$usergroup['gid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_group_deletion}')"); + } + $form_container->output_cell($popup->fetch(), array("class" => "align_center")); + $form_container->construct_row(); + } + + if($form_container->num_rows() == 0) + { + $form_container->output_cell($lang->no_groups, array('colspan' => 4)); + $form_container->construct_row(); + } + + $form_container->end(); + + $buttons = array(); + $buttons[] = $form->generate_submit_button($lang->update_groups_order); + $form->output_submit_wrapper($buttons); + + $form->end(); + + echo << +
+{$lang->legend} +{$lang->custom_user_group} {$lang->custom_user_group}
+{$lang->default_user_group} {$lang->default_user_group} +
+LEGEND; + + $page->output_footer(); +} diff --git a/Upload/admin/modules/user/index.html b/Upload/admin/modules/user/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/modules/user/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/modules/user/mass_mail.php b/Upload/admin/modules/user/mass_mail.php new file mode 100644 index 0000000..a6ba2af --- /dev/null +++ b/Upload/admin/modules/user/mass_mail.php @@ -0,0 +1,1704 @@ +
Please make sure IN_MYBB is defined."); +} + +require_once MYBB_ROOT."/inc/functions_massmail.php"; + +$page->add_breadcrumb_item($lang->mass_mail, "index.php?module=user-mass_mail"); + +if($mybb->input['action'] == "send" || $mybb->input['action'] == "archive" || !$mybb->input['action']) +{ + $sub_tabs['mail_queue'] = array( + 'title' => $lang->mass_mail_queue, + 'link' => 'index.php?module=user-mass_mail', + 'description' => $lang->mass_mail_queue_desc + ); + + $sub_tabs['send_mass_mail'] = array( + 'title' => $lang->create_mass_mail, + 'link' => 'index.php?module=user-mass_mail&action=send', + 'description' => $lang->create_mass_mail_desc + ); + + $sub_tabs['archive'] = array( + 'title' => $lang->mass_mail_archive, + 'link' => 'index.php?module=user-mass_mail&action=archive', + 'description' => $lang->mass_mail_archive_desc + ); +} + +$plugins->run_hooks("admin_user_mass_email"); + +if($mybb->input['action'] == "edit") +{ + $page->add_breadcrumb_item($lang->edit_mass_mail); + + $query = $db->simple_select("massemails", "*", "mid='".$mybb->get_input('mid', 1)."'"); + $email = $db->fetch_array($query); + if(!$email['mid']) + { + flash_message($lang->error_invalid_mid, 'error'); + admin_redirect("index.php?module=user-mass_mail"); + } + + $plugins->run_hooks("admin_user_mass_email_edit_start"); + + if($email['conditions'] != '') + { + $email['conditions'] = my_unserialize($email['conditions']); + } + + $sub_tabs['edit_mass_mail'] = array( + 'title' => $lang->edit_mass_mail, + 'link' => 'index.php?module=user-mass_mail&action=edit&mid='.$email['mid'], + 'description' => $lang->edit_mass_mail_desc + ); + + $replacement_fields = array( + "{username}" => $lang->username, + "{email}" => $lang->email_addr, + "{bbname}" => $lang->board_name, + "{bburl}" => $lang->board_url + ); + + $html_personalisation = $text_personalisation = "\n"; + $text_personalisation = substr($text_personalisation, 0, -2)."');\n// -->\n"; + + // All done here + if($mybb->request_method == "post") + { + // Sending this message now + if($mybb->input['delivery_type'] == "now") + { + $delivery_date = TIME_NOW; + } + // Delivering in the future + else + { + if(strstr($mybb->input['deliverytime_time'], "pm")) + { + $mybb->input['deliveryhour'] += 12; + } + + $exploded = explode(':', $mybb->input['endtime_time']); + $mybb->input['deliveryhour'] = (int)$exploded[0]; + + $exploded = explode(' ', $exploded[1]); + $mybb->input['deliveryminute'] = (int)$exploded[0]; + + $delivery_date = gmmktime($mybb->input['deliveryhour'], $mybb->input['deliveryminute'], 0, $mybb->input['endtime_month'], $mybb->input['endtime_day'], $mybb->input['endtime_year']) + $mybb->user['timezone']*3600; + if($delivery_date <= TIME_NOW) + { + $errors[] = $lang->error_only_in_future; + } + } + + // Need to perform the search to fetch the number of users we're emailing + $member_query = build_mass_mail_query($mybb->input['conditions']); + $query = $db->simple_select("users u", "COUNT(uid) AS num", $member_query); + $num = $db->fetch_field($query, "num"); + + if($num == 0) + { + $errors[] = $lang->error_no_users; + } + + if(!trim($mybb->input['subject'])) + { + $errors[] = $lang->error_missing_subject; + } + + if($mybb->input['type'] == 1) + { + if(!$mybb->input['message']) + { + $errors[] = $lang->error_missing_message; + } + } + else + { + if($mybb->input['format'] == 2 && $mybb->input['automatic_text'] == 0 && !$mybb->input['message']) + { + $errors[] = $lang->error_missing_plain_text; + } + + if(($mybb->input['format'] == 1 || $mybb->input['format'] == 2) && !$mybb->input['htmlmessage']) + { + $errors[] = $lang->error_missing_html; + } + else if($mybb->input['format'] == 0 && !$mybb->input['message']) + { + $errors[] = $lang->error_missing_plain_text; + } + } + + if(!$errors) + { + // Sending via a PM + if($mybb->input['type'] == 1) + { + $mybb->input['format'] = 0; + $mybb->input['htmlmessage'] = ''; + } + // Sending via email + else + { + // Do we need to generate a text based version? + if($mybb->input['format'] == 2 && $mybb->input['automatic_text']) + { + $mybb->input['message'] = create_text_message($mybb->input['htmlmessage']); + } + else if($mybb->input['format'] == 1) + { + $mybb->input['message'] = ''; + } + else if($mybb->input['format'] == 0) + { + $mybb->input['htmlmessage'] = ''; + } + } + + // Mark as queued for delivery + $updated_email = array( + "status" => 1, + "senddate" => $delivery_date, + "totalcount" => $num, + "conditions" => $db->escape_string(serialize($mybb->input['conditions'])), + "message" => $db->escape_string($mybb->input['message']), + "subject" => $db->escape_string($mybb->input['subject']), + "htmlmessage" => $db->escape_string($mybb->input['htmlmessage']), + "format" => (int)$mybb->input['format'], + "type" => $mybb->get_input('type', 1), + "perpage" => $mybb->get_input('perpage', 1) + ); + + $plugins->run_hooks("admin_user_mass_email_edit_commit"); + + $db->update_query("massemails", $updated_email, "mid='{$email['mid']}'"); + + flash_message($lang->success_mass_mail_saved, 'success'); + admin_redirect("index.php?module=user-mass_mail"); + } + } + + $page->output_header($lang->edit_mass_mail); + + $page->output_nav_tabs($sub_tabs, 'edit_mass_mail'); + + // If we have any error messages, show them + if($errors) + { + $page->output_inline_error($errors); + $input = $mybb->input; + } + else + { + $input = $email; + + if($email['senddate'] != 0) + { + if($email['senddate'] <= TIME_NOW) + { + $input['delivery_type'] = "now"; + $delivery_type_checked['now'] = " checked=\"checked\""; + } + else + { + $input['delivery_type'] = "future"; + $time = date("d-n-Y-h-i-a", $email['senddate']); + $time = explode('-', $time); + $input['deliveryhour'] = (int)$time[3]; + $input['deliveryminute'] = (int)$time[4]; + $input['deliverymonth'] = (int)$time[1]; + $input['deliveryday'] = (int)$time[0]; + $input['deliveryyear'] = (int)$time[2]; + $input['deliverymeridiem'] = $time[5]; + $delivery_type_checked['future'] = " checked=\"checked\""; + } + } + else + { + $input['delivery_type'] = "now"; + $delivery_type_checked['now'] = " checked=\"checked\""; + } + } + + if($input['deliveryhour']) + { + $input['endtime_time'] = (int)$input['deliveryhour'].":"; + } + else + { + $input['endtime_time'] = "12:"; + } + + if($input['deliveryminute']) + { + $input['endtime_time'] .= (int)$input['deliveryminute']." "; + } + else + { + $input['endtime_time'] .= "00 "; + } + + if($input['deliverymeridiem']) + { + $input['endtime_time'] .= $input['deliverymeridiem']; + } + else + { + $input['endtime_time'] .= "am"; + } + + if(!$input['deliveryyear']) + { + $enddateyear = gmdate('Y', TIME_NOW); + } + else + { + $enddateyear = (int)$input['deliveryyear']; + } + + if(!$input['deliverymonth']) + { + $input['enddatemonth'] = gmdate('n', TIME_NOW); + } + else + { + $input['enddatemonth'] = (int)$input['deliverymonth']; + } + + if(!$input['deliveryday']) + { + $input['enddateday'] = gmdate('j', TIME_NOW); + } + else + { + $input['enddateday'] = (int)$input['deliveryday']; + } + + $form = new Form("index.php?module=user-mass_mail&action=edit", "post"); + echo $form->generate_hidden_field("mid", $email['mid']); + + $mid_add = ''; + if($email['mid']) + { + $mid_add = "&mid={$email['mid']}"; + } + + $form_container = new FormContainer("{$lang->edit_mass_mail}: {$lang->message_settings}"); + + $form_container->output_row("{$lang->subject}: *", $lang->subject_desc, $form->generate_text_box('subject', $input['subject'], array('id' => 'subject')), 'subject'); + + if($input['type'] == 0) + { + $type_email_checked = true; + $type_pm_checked = false; + } + else if($input['type'] == 1) + { + $type_email_checked = false; + $type_pm_checked = true; + } + + $type_options = array( + $form->generate_radio_button("type", 0, $lang->send_via_email, array("id" => "type_email", "checked" => $type_email_checked)), + $form->generate_radio_button("type", 1, $lang->send_via_pm, array("id" => "type_pm", "checked" => $type_pm_checked)) + ); + $form_container->output_row("{$lang->message_type}: *", "", implode("
", $type_options)); + + $monthnames = array( + "offset", + $lang->january, + $lang->february, + $lang->march, + $lang->april, + $lang->may, + $lang->june, + $lang->july, + $lang->august, + $lang->september, + $lang->october, + $lang->november, + $lang->december, + ); + + $enddatemonth = ""; + foreach($monthnames as $key => $month) + { + if($month == "offset") + { + continue; + } + + if($key == $input['enddatemonth']) + { + $enddatemonth .= "\n"; + } + else + { + $enddatemonth .= "\n"; + } + } + + $enddateday = ""; + + // Construct option list for days + for($i = 1; $i <= 31; ++$i) + { + if($i == $input['enddateday']) + { + $enddateday .= "\n"; + } + else + { + $enddateday .= "\n"; + } + } + + $actions = " +
+
+ +
+
+ + + + +
\n   \n\n   \n\n - {$lang->time} ".$form->generate_text_box('endtime_time', $input['endtime_time'], array('id' => 'endtime_time', 'style' => 'width: 60px;'))."
+
+
+ "; + $form_container->output_row("{$lang->delivery_date}: *", $lang->delivery_date_desc, $actions); + + $form_container->output_row("{$lang->per_page}: *", $lang->per_page_desc, $form->generate_numeric_field('perpage', $input['perpage'], array('id' => 'perpage')), 'perpage'); + + $format_options = array( + 0 => $lang->plain_text_only, + 1 => $lang->html_only, + 2 => $lang->html_and_plain_text + ); + + $form_container->output_row("{$lang->message_format}: *", "", $form->generate_select_box('format', $format_options, $input['format'], array('id' => 'format')), 'format', null, array("id" => "format_container")); + + $form_container->end(); + + if($input['format'] == 2) + { + if($input['automatic_text'] && !$email['mid']) + { + $automatic_text_check = true; + $text_display = 'display: none'; + $automatic_display = 'display: none;'; + } + } + else if($input['format'] == 1 && $input['type'] != 1) + { + $text_display = 'display: none;'; + } + else if($input['format'] == 0 || $input['type'] == 1) + { + $html_display = 'display: none'; + } + + echo "
"; + $form_container = new FormContainer("{$lang->edit_mass_mail}: {$lang->define_html_message}"); + $form_container->output_row("{$lang->define_html_message_desc}:", $html_personalisation, $form->generate_text_area('htmlmessage', $input['htmlmessage'], array('id' => 'htmlmessage', 'rows' => 15, 'cols '=> 70, 'style' => 'width: 95%'))."
".$form->generate_check_box('automatic_text', 1, $lang->auto_gen_plain_text, array('checked' => $automatic_text_check, "id" => "automatic_text"))."
"); + $form_container->end(); + echo "
"; + + echo "
"; + $form_container = new FormContainer("{$lang->edit_mass_mail}: {$lang->define_text_version}"); + $form_container->output_row("{$lang->define_text_version_desc}:", $text_personalisation, $form->generate_text_area('message', $input['message'], array('id' => 'message', 'rows' => 15, 'cols '=> 70, 'style' => 'width: 95%'))); + $form_container->end(); + echo "
"; + + echo " + "; + + $form_container = new FormContainer("{$lang->edit_mass_mail}: {$lang->define_the_recipients}"); + + $form_container->output_row($lang->username_contains, "", $form->generate_text_box('conditions[username]', $input['conditions']['username'], array('id' => 'username')), 'username'); + $form_container->output_row($lang->email_addr_contains, "", $form->generate_text_box('conditions[email]', $input['conditions']['email'], array('id' => 'email')), 'email'); + + $query = $db->simple_select("usergroups", "gid, title", "gid != '1'", array('order_by' => 'title')); + + $options = array(); + while($usergroup = $db->fetch_array($query)) + { + $options[$usergroup['gid']] = $usergroup['title']; + } + + $form_container->output_row($lang->members_of, $lang->additional_user_groups_desc, $form->generate_select_box('conditions[usergroup][]', $options, $input['conditions']['usergroup'], array('id' => 'usergroups', 'multiple' => true, 'size' => 5)), 'usergroups'); + + $greater_options = array( + "greater_than" => $lang->greater_than, + "is_exactly" => $lang->is_exactly, + "less_than" => $lang->less_than + ); + $form_container->output_row($lang->post_count_is, "", $form->generate_select_box('conditions[postnum_dir]', $greater_options, $input['conditions']['postnum_dir'], array('id' => 'postnum_dir'))." ".$form->generate_numeric_field('conditions[postnum]', $input['conditions']['postnum'], array('id' => 'postnum')), 'postnum'); + + $more_options = array( + "more_than" => $lang->more_than, + "less_than" => $lang->less_than + ); + + $date_options = array( + "hours" => $lang->hours, + "days" => $lang->days, + "weeks" => $lang->weeks, + "months" => $lang->months, + "years" => $lang->years + ); + $form_container->output_row($lang->user_registered, "", $form->generate_select_box('conditions[regdate_dir]', $more_options, $input['conditions']['regdate_dir'], array('id' => 'regdate_dir'))." ".$form->generate_numeric_field('conditions[regdate]', $input['conditions']['regdate'], array('id' => 'regdate'))." ".$form->generate_select_box('conditions[regdate_date]', $date_options, $input['conditions']['regdate_date'], array('id' => 'regdate_date'))." {$lang->ago}", 'regdate'); + + $form_container->output_row($lang->user_last_active, "", $form->generate_select_box('conditions[lastactive_dir]', $more_options, $input['conditions']['lastactive_dir'], array('id' => 'lastactive_dir'))." ".$form->generate_numeric_field('conditions[lastactive]', $input['conditions']['lastactive'], array('id' => 'lastactive'))." ".$form->generate_select_box('conditions[lastactive_date]', $date_options, $input['conditions']['lastactive_date'], array('id' => 'lastactive_date'))." {$lang->ago}", 'lastactive'); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_mass_mail); + $form->output_submit_wrapper($buttons); + + $form->end(); + $page->output_footer(); +} + +if($mybb->input['action'] == "send") +{ + $page->add_breadcrumb_item($lang->send_mass_mail); + + if($mybb->input['step']) + { + $query = $db->simple_select("massemails", "*", "status=0 and mid='".$mybb->get_input('mid', 1)."'"); + $email = $db->fetch_array($query); + if(!$email['mid'] && $mybb->input['step'] != 1) + { + flash_message($lang->error_invalid_mid, 'error'); + admin_redirect("index.php?module=user-mass_mail"); + } + } + + $replacement_fields = array( + "{username}" => $lang->username, + "{email}" => $lang->email_addr, + "{bbname}" => $lang->board_name, + "{bburl}" => $lang->board_url + ); + + $html_personalisation = $text_personalisation = "\n"; + $text_personalisation = substr($text_personalisation, 0, -2)."');\n// -->\n"; + + $plugins->run_hooks("admin_user_mass_email_send_start"); + + if($mybb->input['step'] == 4) + { + // All done here + if($mybb->request_method == "post") + { + // Sending this message now + if($mybb->input['delivery_type'] == "now") + { + $delivery_date = TIME_NOW; + } + // Delivering in the future + else + { + if(strstr($mybb->input['deliverytime_time'], "pm")) + { + $mybb->input['deliveryhour'] += 12; + } + + $exploded = explode(':', $mybb->input['endtime_time']); + $mybb->input['deliveryhour'] = (int)$exploded[0]; + + $exploded = explode(' ', $exploded[1]); + $mybb->input['deliveryminute'] = (int)$exploded[0]; + + $delivery_date = gmmktime($mybb->input['deliveryhour'], $mybb->input['deliveryminute'], 0, $mybb->input['endtime_month'], $mybb->input['endtime_day'], $mybb->input['endtime_year']) + $mybb->user['timezone']*3600; + if($delivery_date <= TIME_NOW) + { + $errors[] = $lang->error_only_in_future; + } + } + + if(!$errors) + { + // Mark as queued for delivery + $updated_email = array( + "status" => 1, + "senddate" => $delivery_date + ); + + $plugins->run_hooks("admin_user_mass_email_send_finalize_commit"); + + $db->update_query("massemails", $updated_email, "mid='{$email['mid']}'"); + + flash_message($lang->success_mass_mail_saved, 'success'); + admin_redirect("index.php?module=user-mass_mail"); + } + } + + // Show summary of the mass email we've just been creating and allow the user to specify the delivery date + $page->output_header("{$lang->send_mass_mail}: {$lang->step_four}"); + + $page->output_nav_tabs($sub_tabs, 'send_mass_mail'); + + // If we have any error messages, show them + if($errors) + { + $page->output_inline_error($errors); + $input = $mybb->input; + } + else + { + $input = array(); + if($email['senddate'] != 0) + { + if($email['senddate'] <= TIME_NOW) + { + $input['delivery_type'] = "now"; + $delivery_type_checked['now'] = " checked=\"checked\""; + } + else + { + $input['delivery_type'] = "future"; + $time = date("d-n-Y-h-i-a", $email['senddate']); + $time = explode('-', $time); + $input['deliveryhour'] = (int)$time[3]; + $input['deliveryminute'] = (int)$time[4]; + $input['deliverymonth'] = (int)$time[1]; + $input['deliveryday'] = (int)$time[0]; + $input['deliveryyear'] = (int)$time[2]; + $input['deliverymeridiem'] = $time[5]; + $delivery_type_checked['future'] = " checked=\"checked\""; + } + } + else + { + $input['delivery_type'] = "now"; + $delivery_type_checked['now'] = " checked=\"checked\""; + } + } + + $table = new Table; + $table->construct_cell("{$lang->delivery_method}:", array('width' => '25%')); + if($email['type'] == 1) + { + $delivery_type = $lang->private_message; + } + else if($email['type'] == 0) + { + $delivery_type = $lang->email; + } + $table->construct_cell($delivery_type); + $table->construct_row(); + + $table->construct_cell("{$lang->subject}:"); + $table->construct_cell(htmlspecialchars_uni($email['subject'])); + $table->construct_row(); + + $table->construct_cell("{$lang->message}:"); + $format_preview = ''; + if($email['format'] == 0 || $email['format'] == 2) + { + $format_preview .= "{$lang->text_based} - {$lang->preview}"; + } + if($email['format'] == 2) + { + $format_preview .= " {$lang->and}
"; + } + if($email['format'] == 1 || $email['format'] == 2) + { + $format_preview.= "{$lang->html_based} - {$lang->preview}"; + } + $table->construct_cell($format_preview); + $table->construct_row(); + + // Recipient counts & details + $table->construct_cell("{$lang->total_recipients}:"); + $table->construct_cell(my_number_format($email['totalcount'])." - {$lang->change_recipient_conds}"); + $table->construct_row(); + + $table->output("{$lang->send_mass_mail}: {$lang->step_four} - {$lang->review_message}"); + + if($input['deliveryhour']) + { + $input['endtime_time'] = (int)$input['deliveryhour'].":"; + } + else + { + $input['endtime_time'] = "12:"; + } + + if($input['deliveryminute']) + { + $input['endtime_time'] .= (int)$input['deliveryminute']." "; + } + else + { + $input['endtime_time'] .= "00 "; + } + + if($input['deliverymeridiem']) + { + $input['endtime_time'] .= $input['deliverymeridiem']; + } + else + { + $input['endtime_time'] .= "am"; + } + + if(!$input['deliveryyear']) + { + $enddateyear = gmdate('Y', TIME_NOW); + } + else + { + $enddateyear = (int)$input['deliveryyear']; + } + + if(!$input['deliverymonth']) + { + $input['enddatemonth'] = gmdate('n', TIME_NOW); + } + else + { + $input['enddatemonth'] = (int)$input['deliverymonth']; + } + + if(!$input['deliveryday']) + { + $input['enddateday'] = gmdate('j', TIME_NOW); + } + else + { + $input['enddateday'] = (int)$input['deliveryday']; + } + + $monthnames = array( + "offset", + $lang->january, + $lang->february, + $lang->march, + $lang->april, + $lang->may, + $lang->june, + $lang->july, + $lang->august, + $lang->september, + $lang->october, + $lang->november, + $lang->december, + ); + + $enddatemonth = ""; + foreach($monthnames as $key => $month) + { + if($month == "offset") + { + continue; + } + + if($key == $input['enddatemonth']) + { + $enddatemonth .= "\n"; + } + else + { + $enddatemonth .= "\n"; + } + } + + $enddateday = ""; + + // Construct option list for days + for($i = 1; $i <= 31; ++$i) + { + if($i == $input['enddateday']) + { + $enddateday .= "\n"; + } + else + { + $enddateday .= "\n"; + } + } + + $form = new Form("index.php?module=user-mass_mail&action=send&step=4&mid={$email['mid']}", "post"); + $form_container = new FormContainer("{$lang->send_mass_mail}: {$lang->step_four} - {$lang->define_delivery_date}"); + + $actions = " +
+
+ +
+
+ + + + +
\n   \n\n   \n\n - {$lang->time} ".$form->generate_text_box('endtime_time', $input['endtime_time'], array('id' => 'endtime_time', 'style' => 'width: 60px;'))."
+
+
+ "; + $form_container->output_row("{$lang->delivery_date}: *", $lang->delivery_date_desc, $actions); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->schedule_for_delivery); + $form->output_submit_wrapper($buttons); + + $form->end(); + $page->output_footer(); + } + elseif($mybb->input['step'] == 3) + { + // Define the recipients/conditions + if($mybb->request_method == "post") + { + // Need to perform the search to fetch the number of users we're emailing + $member_query = build_mass_mail_query($mybb->input['conditions']); + $query = $db->simple_select("users u", "COUNT(uid) AS num", $member_query); + $num = $db->fetch_field($query, "num"); + + if($num == 0) + { + $errors[] = $lang->error_no_users; + } + // Got one or more results + else + { + $updated_email = array( + "totalcount" => $num, + "conditions" => $db->escape_string(serialize($mybb->input['conditions'])) + ); + + $plugins->run_hooks("admin_user_mass_email_send_define_commit"); + + $db->update_query("massemails", $updated_email, "mid='{$email['mid']}'"); + + // Take the user to the next step + admin_redirect("index.php?module=user-mass_mail&action=send&step=4&mid={$email['mid']}"); + } + } + + $page->output_header("{$lang->send_mass_mail}: {$lang->step_three}"); + + $form = new Form("index.php?module=user-mass_mail&action=send&step=3&mid={$email['mid']}", "post"); + $page->output_nav_tabs($sub_tabs, 'send_mass_mail'); + + // If we have any error messages, show them + if($errors) + { + $page->output_inline_error($errors); + $input = $mybb->input; + } + else + { + if($email['conditions'] != '') + { + $input = array( + "conditions" => my_unserialize($email['conditions']) + ); + } + else + { + $input = array(); + } + } + + $options = array( + 'username', 'email', 'postnum_dir', 'postnum', 'regdate', 'regdate_date', 'regdate_dir', 'lastactive', 'lastactive_date', 'lastactive_dir' + ); + + foreach($options as $option) + { + if(!isset($input['conditions'][$option])) + { + $input['conditions'][$option] = ''; + } + } + if(!isset($input['conditions']['usergroup']) || !is_array($input['conditions']['usergroup'])) + { + $input['conditions']['usergroup'] = array(); + } + + $form_container = new FormContainer("{$lang->send_mass_mail}: {$lang->step_three} - {$lang->define_the_recipients}"); + + $form_container->output_row($lang->username_contains, "", $form->generate_text_box('conditions[username]', $input['conditions']['username'], array('id' => 'username')), 'username'); + $form_container->output_row($lang->email_addr_contains, "", $form->generate_text_box('conditions[email]', $input['conditions']['email'], array('id' => 'email')), 'email'); + + $options = array(); + $query = $db->simple_select("usergroups", "gid, title", "gid != '1'", array('order_by' => 'title')); + while($usergroup = $db->fetch_array($query)) + { + $options[$usergroup['gid']] = $usergroup['title']; + } + + $form_container->output_row($lang->members_of, $lang->additional_user_groups_desc, $form->generate_select_box('conditions[usergroup][]', $options, $input['conditions']['usergroup'], array('id' => 'usergroups', 'multiple' => true, 'size' => 5)), 'usergroups'); + + $greater_options = array( + "greater_than" => $lang->greater_than, + "is_exactly" => $lang->is_exactly, + "less_than" => $lang->less_than + ); + $form_container->output_row($lang->post_count_is, "", $form->generate_select_box('conditions[postnum_dir]', $greater_options, $input['conditions']['postnum_dir'], array('id' => 'postnum_dir'))." ".$form->generate_numeric_field('conditions[postnum]', $input['conditions']['postnum'], array('id' => 'postnum')), 'postnum'); + + $more_options = array( + "more_than" => $lang->more_than, + "less_than" => $lang->less_than + ); + + $date_options = array( + "hours" => $lang->hours, + "days" => $lang->days, + "weeks" => $lang->weeks, + "months" => $lang->months, + "years" => $lang->years + ); + $form_container->output_row($lang->user_registered, "", $form->generate_select_box('conditions[regdate_dir]', $more_options, $input['conditions']['regdate_dir'], array('id' => 'regdate_dir'))." ".$form->generate_numeric_field('conditions[regdate]', $input['conditions']['regdate'], array('id' => 'regdate'))." ".$form->generate_select_box('conditions[regdate_date]', $date_options, $input['conditions']['regdate_date'], array('id' => 'regdate_date'))." {$lang->ago}", 'regdate'); + + $form_container->output_row($lang->user_last_active, "", $form->generate_select_box('conditions[lastactive_dir]', $more_options, $input['conditions']['lastactive_dir'], array('id' => 'lastactive_dir'))." ".$form->generate_numeric_field('conditions[lastactive]', $input['conditions']['lastactive'], array('id' => 'lastactive'))." ".$form->generate_select_box('conditions[lastactive_date]', $date_options, $input['conditions']['lastactive_date'], array('id' => 'lastactive_date'))." {$lang->ago}", 'lastactive'); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->next_step); + $form->output_submit_wrapper($buttons); + + $form->end(); + $page->output_footer(); + } + // Reviewing the automatic text based version of the message. + elseif($mybb->input['step'] == 2) + { + // Update text based version + if($mybb->request_method == "post") + { + if(!trim($mybb->input['message'])) + { + $errors[] = $lang->error_missing_plain_text; + } + else + { + $updated_email = array( + "message" => $db->escape_string($mybb->input['message']) + ); + + $plugins->run_hooks("admin_user_mass_email_send_review_commit"); + + $db->update_query("massemails", $updated_email, "mid='{$email['mid']}'"); + + // Take the user to the next step + admin_redirect("index.php?module=user-mass_mail&action=send&step=3&mid={$email['mid']}"); + } + } + + $page->output_header("{$lang->send_mass_mail}: {$lang->step_two}"); + + $form = new Form("index.php?module=user-mass_mail&action=send&step=2&mid={$email['mid']}", "post"); + $page->output_nav_tabs($sub_tabs, 'send_mass_mail'); + + // If we have any error messages, show them + if($errors) + { + $page->output_inline_error($errors); + } + + $form_container = new FormContainer("{$lang->send_mass_mail}: {$lang->step_two} - {$lang->review_text_version}"); + $form_container->output_row("{$lang->review_text_version_desc}:", $text_personalisation, $form->generate_text_area('message', $email['message'], array('id' => 'message', 'rows' => 15, 'cols '=> 70, 'style' => 'width: 95%'))); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->next_step); + $form->output_submit_wrapper($buttons); + + $form->end(); + $page->output_footer(); + } + elseif(!$mybb->input['step'] || $mybb->input['step'] == 1) + { + if($mybb->request_method == "post") + { + if(!trim($mybb->input['subject'])) + { + $errors[] = $lang->error_missing_subject; + } + + if($mybb->input['type'] == 1) + { + if(!$mybb->input['message']) + { + $errors[] = $lang->error_missing_message; + } + } + else + { + if($mybb->input['format'] == 2 && $mybb->input['automatic_text'] == 0 && !$mybb->input['message']) + { + $errors[] = $lang->error_missing_plain_text; + } + + if(($mybb->input['format'] == 1 || $mybb->input['format'] == 2) && !$mybb->input['htmlmessage']) + { + $errors[] = $lang->error_missing_html; + } + else if($mybb->input['format'] == 0 && !$mybb->input['message']) + { + $errors[] = $lang->error_missing_plain_text; + } + } + + // No errors, insert away + if(!$errors) + { + if(!$new_email['mid']) + { + // Sending via a PM + if($mybb->input['type'] == 1) + { + $mybb->input['format'] = 0; + $mybb->input['htmlmessage'] = ''; + } + // Sending via email + else + { + // Do we need to generate a text based version? + if($mybb->input['format'] == 2 && $mybb->input['automatic_text']) + { + $mybb->input['message'] = create_text_message($mybb->input['htmlmessage']); + } + else if($mybb->input['format'] == 1) + { + $mybb->input['message'] = ''; + } + else if($mybb->input['format'] == 0) + { + $mybb->input['htmlmessage'] = ''; + } + } + + $new_email = array( + "uid" => $mybb->user['uid'], + "subject" => $db->escape_string($mybb->input['subject']), + "message" => $db->escape_string($mybb->input['message']), + "htmlmessage" => $db->escape_string($mybb->input['htmlmessage']), + "format" => (int)$mybb->input['format'], + "type" => $mybb->get_input('type', 1), + "dateline" => TIME_NOW, + "senddate" => 0, + "status" => 0, + "sentcount" => 0, + "totalcount" => 0, + "conditions" => "", + "perpage" => $mybb->get_input('perpage', 1) + ); + + $mid = $db->insert_query("massemails", $new_email); + + $plugins->run_hooks("admin_user_mass_email_send_insert_commit"); + } + // Updating an existing one + else + { + $updated_email = array( + "subject" => $db->escape_string($mybb->input['subject']), + "message" => $db->escape_string($mybb->input['message']), + "htmlmessage" => $db->escape_string($mybb->input['htmlmessage']), + "format" => (int)$mybb->input['format'], + "type" => $mybb->get_input('type', 1), + "perpage" => $mybb->get_input('perpage', 1) + ); + + $plugins->run_hooks("admin_user_mass_email_send_update_commit"); + + $db->update_query("massemails", $updated_email, "mid='{$email['mid']}'"); + $mid = $email['mid']; + } + + if($mybb->input['format'] == 2 && $mybb->input['automatic_text'] == 1) + { + $next = 2; + } + else + { + $next = 3; + } + admin_redirect("index.php?module=user-mass_mail&action=send&step={$next}&mid={$mid}"); + } + } + + $page->output_header("{$lang->send_mass_mail}: {$lang->step_one}"); + + $mid_add = ''; + if($email['mid']) + { + $mid_add = "&mid={$email['mid']}"; + } + + $form = new Form("index.php?module=user-mass_mail&action=send{$mid_add}", "post"); + $page->output_nav_tabs($sub_tabs, 'send_mass_mail'); + + // If we have any error messages, show them + if($errors) + { + $page->output_inline_error($errors); + $input = $mybb->input; + } + else if(!$email) + { + $input = array( + "type" => 0, + "format" => 2, + "automatic_text" => 1, + "perpage" => 50, + ); + } + else + { + $input = $email; + } + + $form_container = new FormContainer("{$lang->send_mass_mail}: {$lang->step_one} - {$lang->message_settings}"); + + $form_container->output_row("{$lang->subject}: *", $lang->subject_desc, $form->generate_text_box('subject', $input['subject'], array('id' => 'subject')), 'subject'); + + if($mybb->input['type'] == 0) + { + $type_email_checked = true; + $type_pm_checked = false; + } + else if($mybb->input['type'] == 1) + { + $type_email_checked = false; + $type_pm_checked = true; + } + + $type_options = array( + $form->generate_radio_button("type", 0, $lang->send_via_email, array("id" => "type_email", "checked" => $type_email_checked)), + $form->generate_radio_button("type", 1, $lang->send_via_pm, array("id" => "type_pm", "checked" => $type_pm_checked)) + ); + $form_container->output_row("{$lang->message_type}:", "", implode("
", $type_options)); + + $format_options = array( + 0 => $lang->plain_text_only, + 1 => $lang->html_only, + 2 => $lang->html_and_plain_text + ); + + $form_container->output_row("{$lang->message_format}:", "", $form->generate_select_box('format', $format_options, $input['format'], array('id' => 'format')), 'format', null, array("id" => "format_container")); + + $form_container->output_row("{$lang->per_page}: *", $lang->per_page_desc, $form->generate_numeric_field('perpage', $input['perpage'], array('id' => 'perpage')), 'perpage'); + + $form_container->end(); + + if($mybb->input['format'] == 2) + { + if($mybb->input['automatic_text'] && !$email['mid']) + { + $automatic_text_check = true; + $text_display = 'display: none'; + $automatic_display = 'display: none;'; + } + } + else if($mybb->input['format'] == 1 && $mybb->input['type'] != 1) + { + $text_display = 'display: none;'; + } + else if($mybb->input['format'] == 0 || $mybb->input['type'] == 1) + { + $html_display = 'display: none'; + } + + echo "
"; + $form_container = new FormContainer("{$lang->send_mass_mail}: {$lang->step_one} - {$lang->define_html_message}"); + $form_container->output_row("{$lang->define_html_message_desc}:", $html_personalisation, $form->generate_text_area('htmlmessage', $input['htmlmessage'], array('id' => 'htmlmessage', 'rows' => 15, 'cols '=> 70, 'style' => 'width: 95%'))."
".$form->generate_check_box('automatic_text', 1, $lang->auto_gen_plain_text, array('checked' => $automatic_text_check, "id" => "automatic_text"))."
"); + $form_container->end(); + echo "
"; + + echo "
"; + $form_container = new FormContainer("{$lang->send_mass_mail}: {$lang->step_one} - {$lang->define_text_version}"); + $form_container->output_row("{$lang->define_text_version_desc}:", $text_personalisation, $form->generate_text_area('message', $input['message'], array('id' => 'message', 'rows' => 15, 'cols '=> 70, 'style' => 'width: 95%'))); + $form_container->end(); + echo "
"; + + echo " + "; + + $buttons[] = $form->generate_submit_button($lang->next_step); + $form->output_submit_wrapper($buttons); + + $form->end(); + $page->output_footer(); + } + + $plugins->run_hooks("admin_user_mass_email_preview_end"); +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("massemails", "*", "mid='".$mybb->get_input('mid', 1)."'"); + $mass_email = $db->fetch_array($query); + + if(!$mass_email['mid']) + { + flash_message($lang->error_delete_invalid_mid, 'error'); + admin_redirect("index.php?module=user-mass_mail"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=user-mass_mail"); + } + + $plugins->run_hooks("admin_user_mass_email_delete_start"); + + if($mybb->request_method == "post") + { + $db->delete_query("massemails", "mid='{$mass_email['mid']}'"); + + $plugins->run_hooks("admin_user_mass_email_delete_commit"); + + // Log admin action + log_admin_action($mass_email['mid'], $mass_email['subject']); + + if($mybb->input['archive'] == 1) + { + flash_message($lang->success_mass_mail_deleted, 'success'); + admin_redirect("index.php?module=user-mass_mail&action=archive"); + } + else + { + flash_message($lang->success_mass_mail_deleted, 'success'); + admin_redirect("index.php?module=user-mass_mail"); + } + } + else + { + if($mybb->input['archive'] == 1) + { + $page->output_confirm_action("index.php?module=user-mass_mail&action=delete&mid={$mass_email['mid']}&archive=1", $lang->mass_mail_deletion_confirmation); + } + else + { + $page->output_confirm_action("index.php?module=user-mass_mail&action=delete&mid={$mass_email['mid']}", $lang->mass_mail_deletion_confirmation); + } + } +} + +if($mybb->input['action'] == "preview") +{ + $query = $db->simple_select("massemails", "*", "mid='".$mybb->get_input('mid', 1)."'"); + $mass_email = $db->fetch_array($query); + + if(!$mass_email['mid']) + { + flash_message($lang->error_invalid_mid, 'error'); + admin_redirect("index.php?module=user-mass_mail"); + } + + $plugins->run_hooks("admin_user_mass_email_preview_start"); + + echo ''; + exit; +} + +if($mybb->input['action'] == "resend") +{ + // Copy and resend an email + $query = $db->simple_select("massemails", "*", "mid='".$mybb->get_input('mid', 1)."'"); + $mass_email = $db->fetch_array($query); + + if(!$mass_email['mid']) + { + flash_message($lang->error_invalid_mid, 'error'); + admin_redirect("index.php?module=user-mass_mail"); + } + + $plugins->run_hooks("admin_user_mass_email_resend_start"); + + // Need to perform the search to fetch the number of users we're emailing + $member_query = build_mass_mail_query(my_unserialize($mass_email['conditions'])); + $query = $db->simple_select("users u", "COUNT(uid) AS num", $member_query); + $total_recipients = $db->fetch_field($query, "num"); + + // Create the new email based off the old one. + $new_email = array( + "uid" => $mass_email['uid'], + "subject" => $db->escape_string($mass_email['subject']), + "message" => $db->escape_string($mass_email['message']), + "htmlmessage" => $db->escape_string($mass_email['htmlmessage']), + "type" => $db->escape_string($mass_email['type']), + "format" => $db->escape_string($mass_email['format']), + "dateline" => TIME_NOW, + "senddate" => '0', + "status" => 0, + "sentcount" => 0, + "totalcount" => $total_recipients, + "conditions" => $db->escape_string($mass_email['conditions']), + "perpage" => $mass_email['perpage'] + ); + + $mid = $db->insert_query("massemails", $new_email); + + $plugins->run_hooks("admin_user_mass_email_resend_end"); + + // Redirect the user to the summary page so they can select when to deliver this message + flash_message($lang->success_mass_mail_resent, 'success'); + admin_redirect("index.php?module=user-mass_mail&action=send&step=4&mid={$mid}"); + exit; +} + +if($mybb->input['action'] == "cancel") +{ + // Cancel the delivery of a mass-email. + $query = $db->simple_select("massemails", "*", "mid='".$mybb->get_input('mid', 1)."'"); + $mass_email = $db->fetch_array($query); + + if(!$mass_email['mid']) + { + flash_message($lang->error_invalid_mid, 'error'); + admin_redirect("index.php?module=user-mass_mail"); + } + + $updated_email = array( + 'status' => 4 + ); + + $plugins->run_hooks("admin_user_mass_email_cancel"); + + $db->update_query("massemails", $updated_email, "mid='{$mass_email['mid']}'"); + + flash_message($lang->success_mass_mail_canceled, 'success'); + admin_redirect("index.php?module=user-mass_mail"); + exit; +} + +if($mybb->input['action'] == "archive") +{ + // View a list of archived email messages + $page->output_header($lang->mass_mail_archive); + + $plugins->run_hooks("admin_user_mass_email_archive_start"); + + $page->output_nav_tabs($sub_tabs, 'archive'); + + $table = new Table; + $table->construct_header($lang->subject); + $table->construct_header($lang->status, array('width' => '130', 'class' => 'align_center')); + $table->construct_header($lang->delivery_date, array('width' => '130', 'class' => 'align_center')); + $table->construct_header($lang->recipients, array('width' => '130', 'class' => 'align_center')); + $table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 2, "width" => 200)); + + $query = $db->simple_select("massemails", "*", "status NOT IN (0, 1, 2)", array('order_by' => 'senddate')); + while($email = $db->fetch_array($query)) + { + $email['subject'] = htmlspecialchars_uni($email['subject']); + if($email['senddate'] < TIME_NOW) + { + $table->construct_cell("{$email['subject']}"); + } + if($email['status'] == 3) + { + $status = $lang->delivered; + } + else if($email['status'] == 4) + { + $status = $lang->canceled; + } + $table->construct_cell($status, array("class" => "align_center")); + + $delivery_date = my_date($mybb->settings['dateformat'], $email['senddate']); + + $table->construct_cell($delivery_date, array("class" => "align_center")); + $table->construct_cell(my_number_format($email['totalcount']), array("class" => "align_center")); + + $table->construct_cell("{$lang->resend}", array("width" => 100, "class" => "align_center")); + $table->construct_cell("post_code}&archive=1\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->mass_mail_deletion_confirmation}')\">{$lang->delete}", array("width" => 100, "class" => "align_center")); + + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_archived_messages, array('colspan' => 6)); + $table->construct_row(); + $no_results = true; + } + + $plugins->run_hooks("admin_user_mass_email_archive_end"); + + $table->output($lang->mass_mail_archive); + + $page->output_footer(); +} + +if(!$mybb->input['action']) +{ + $page->output_header($lang->mass_mail_queue); + + $plugins->run_hooks("admin_user_mass_email_start"); + + $page->output_nav_tabs($sub_tabs, 'mail_queue'); + + $table = new Table; + $table->construct_header($lang->subject); + $table->construct_header($lang->status, array('width' => '130', 'class' => 'align_center')); + $table->construct_header($lang->delivery_date, array('width' => '130', 'class' => 'align_center')); + $table->construct_header($lang->recipients, array('width' => '130', 'class' => 'align_center')); + $table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 2, "width" => 200)); + + $query = $db->simple_select("massemails", "*", "status IN (0, 1, 2)", array('order_by' => 'senddate')); + while($email = $db->fetch_array($query)) + { + $email['subject'] = htmlspecialchars_uni($email['subject']); + if(TIME_NOW >= $email['senddate'] && $email['status'] > 1) + { + $table->construct_cell("{$email['subject']}"); + } + else + { + $table->construct_cell("{$email['subject']}"); + } + if($email['status'] == 0) + { + $status = $lang->draft; + } + else if($email['status'] == 1) + { + $status = $lang->queued; + } + else if($email['status'] == 2) + { + $progress = ceil($email['sentcount']/$email['totalcount']*100); + if($progress > 100) + { + $progress = 100; + } + $status = "{$lang->delivering} ({$progress}%)"; + } + $table->construct_cell($status, array("class" => "align_center")); + + if($email['status'] != 0) + { + $delivery_date = my_date($mybb->settings['dateformat'], $email['senddate']); + } + else + { + $delivery_date = $lang->na; + } + + $table->construct_cell($delivery_date, array("class" => "align_center")); + $table->construct_cell(my_number_format($email['totalcount']), array("class" => "align_center")); + if(TIME_NOW >= $email['senddate'] && $email['status'] > 1) + { + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->mass_mail_cancel_confirmation}')\">{$lang->cancel}", array("width" => 100, "colspan" => 2, "class" => "align_center")); + } + else + { + $table->construct_cell("{$lang->edit}", array("width" => 100, "class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->mass_mail_deletion_confirmation}')\">{$lang->delete}", array("width" => 100, "class" => "align_center")); + } + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_unsent_messages, array('colspan' => 6)); + $table->construct_row(); + $no_results = true; + } + + $plugins->run_hooks("admin_user_mass_email_end"); + + $table->output($lang->mass_mail_queue); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/user/module_meta.php b/Upload/admin/modules/user/module_meta.php new file mode 100644 index 0000000..615003f --- /dev/null +++ b/Upload/admin/modules/user/module_meta.php @@ -0,0 +1,83 @@ +
Please make sure IN_MYBB is defined."); +} + +function user_meta() +{ + global $page, $lang, $plugins; + + $sub_menu = array(); + $sub_menu['10'] = array("id" => "users", "title" => $lang->users, "link" => "index.php?module=user-users"); + $sub_menu['20'] = array("id" => "groups", "title" => $lang->groups, "link" => "index.php?module=user-groups"); + $sub_menu['30'] = array("id" => "titles", "title" => $lang->user_titles, "link" => "index.php?module=user-titles"); + $sub_menu['40'] = array("id" => "banning", "title" => $lang->banning, "link" => "index.php?module=user-banning"); + $sub_menu['50'] = array("id" => "admin_permissions", "title" => $lang->admin_permissions, "link" => "index.php?module=user-admin_permissions"); + $sub_menu['60'] = array("id" => "mass_mail", "title" => $lang->mass_mail, "link" => "index.php?module=user-mass_mail"); + $sub_menu['70'] = array("id" => "group_promotions", "title" => $lang->group_promotions, "link" => "index.php?module=user-group_promotions"); + + $sub_menu = $plugins->run_hooks("admin_user_menu", $sub_menu); + + $page->add_menu_item($lang->users_and_groups, "user", "index.php?module=user", 30, $sub_menu); + return true; +} + +function user_action_handler($action) +{ + global $page, $lang, $plugins; + + $page->active_module = "user"; + + $actions = array( + 'group_promotions' => array('active' => 'group_promotions', 'file' => 'group_promotions.php'), + 'admin_permissions' => array('active' => 'admin_permissions', 'file' => 'admin_permissions.php'), + 'titles' => array('active' => 'titles', 'file' => 'titles.php'), + 'banning' => array('active' => 'banning', 'file' => 'banning.php'), + 'groups' => array('active' => 'groups', 'file' => 'groups.php'), + 'mass_mail' => array('active' => 'mass_mail', 'file' => 'mass_mail.php'), + 'users' => array('active' => 'users', 'file' => 'users.php') + ); + + $actions = $plugins->run_hooks("admin_user_action_handler", $actions); + + if(isset($actions[$action])) + { + $page->active_action = $actions[$action]['active']; + return $actions[$action]['file']; + } + else + { + $page->active_action = "users"; + return "users.php"; + } +} + +function user_admin_permissions() +{ + global $lang, $plugins; + + $admin_permissions = array( + "users" => $lang->can_manage_users, + "groups" => $lang->can_manage_user_groups, + "titles" => $lang->can_manage_user_titles, + "banning" => $lang->can_manage_user_bans, + "admin_permissions" => $lang->can_manage_admin_permissions, + "mass_mail" => $lang->can_send_mass_mail, + "group_promotions" => $lang->can_manage_group_promotions + ); + + $admin_permissions = $plugins->run_hooks("admin_user_permissions", $admin_permissions); + + return array("name" => $lang->users_and_groups, "permissions" => $admin_permissions, "disporder" => 30); +} diff --git a/Upload/admin/modules/user/titles.php b/Upload/admin/modules/user/titles.php new file mode 100644 index 0000000..cbae349 --- /dev/null +++ b/Upload/admin/modules/user/titles.php @@ -0,0 +1,280 @@ +
Please make sure IN_MYBB is defined."); +} + +$page->add_breadcrumb_item($lang->user_titles, "index.php?module=user-titles"); + +if($mybb->input['action'] == "add" || !$mybb->input['action']) +{ + $sub_tabs['manage_titles'] = array( + 'title' => $lang->user_titles, + 'link' => "index.php?module=user-titles", + 'description' => $lang->user_titles_desc + ); + $sub_tabs['add_title'] = array( + 'title' => $lang->add_new_user_title, + 'link' => "index.php?module=user-titles&action=add", + 'description' => $lang->add_new_user_title_desc + ); +} + +$plugins->run_hooks("admin_user_titles_begin"); + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_user_titles_add"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + if(!isset($mybb->input['posts'])) + { + $errors[] = $lang->error_missing_posts; + } + + $query = $db->simple_select("usertitles", "utid", "posts= '".(int)$mybb->input['posts']."'"); + if($db->num_rows($query)) + { + $errors[] = $lang->error_cannot_have_same_posts; + } + + if(!$errors) + { + $new_title = array( + "title" => $db->escape_string($mybb->input['title']), + "posts" => (int)$mybb->input['posts'], + "stars" => (int)$mybb->input['stars'], + "starimage" => $db->escape_string($mybb->input['starimage']) + ); + + $utid = $db->insert_query("usertitles", $new_title); + + $plugins->run_hooks("admin_user_titles_add_commit"); + + $cache->update_usertitles(); + + // Log admin action + log_admin_action($utid, $mybb->input['title'], $mybb->input['posts']); + + flash_message($lang->success_user_title_created, 'success'); + admin_redirect("index.php?module=user-titles"); + } + } + else + { + $mybb->input = array_merge($mybb->input, array( + 'stars' => '1', + 'starimage' => '{theme}/star.png', + ) + ); + } + + $page->add_breadcrumb_item($lang->add_new_user_title); + $page->output_header($lang->user_titles." - ".$lang->add_new_user_title); + + $page->output_nav_tabs($sub_tabs, 'add_title'); + $form = new Form("index.php?module=user-titles&action=add", "post"); + + + if($errors) + { + $page->output_inline_error($errors); + } + + $form_container = new FormContainer($lang->add_new_user_title); + $form_container->output_row($lang->title_to_assign."*", $lang->title_to_assign_desc, $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->minimum_posts, $lang->minimum_posts_desc, $form->generate_numeric_field('posts', $mybb->input['posts'], array('id' => 'posts')), 'posts'); + $form_container->output_row($lang->number_of_stars, $lang->number_of_stars_desc, $form->generate_numeric_field('stars', $mybb->input['stars'], array('id' => 'stars')), 'stars'); + $form_container->output_row($lang->star_image, $lang->star_image_desc, $form->generate_text_box('starimage', $mybb->input['starimage'], array('id' => 'starimage')), 'starimage'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_user_title); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "edit") +{ + $query = $db->simple_select("usertitles", "*", "utid='".(int)$mybb->input['utid']."'"); + $usertitle = $db->fetch_array($query); + + if(!$usertitle['utid']) + { + flash_message($lang->error_invalid_user_title, 'error'); + admin_redirect("index.php?module=user-titles"); + } + + $plugins->run_hooks("admin_user_titles_edit"); + + if($mybb->request_method == "post") + { + if(!trim($mybb->input['title'])) + { + $errors[] = $lang->error_missing_title; + } + + if(!isset($mybb->input['posts'])) + { + $errors[] = $lang->error_missing_posts; + } + + $query = $db->simple_select("usertitles", "utid", "posts= '".(int)$mybb->input['posts']."' AND utid!= '".(int)$mybb->input['utid']."'"); + if($db->num_rows($query)) + { + $errors[] = $lang->error_cannot_have_same_posts; + } + + if(!$errors) + { + $updated_title = array( + "title" => $db->escape_string($mybb->input['title']), + "posts" => (int)$mybb->input['posts'], + "stars" => (int)$mybb->input['stars'], + "starimage" => $db->escape_string($mybb->input['starimage']) + ); + + $plugins->run_hooks("admin_user_titles_edit_commit"); + + $db->update_query("usertitles", $updated_title, "utid='{$usertitle['utid']}'"); + + $cache->update_usertitles(); + + // Log admin action + log_admin_action($usertitle['utid'], $mybb->input['title'], $mybb->input['posts']); + + flash_message($lang->success_user_title_updated, 'success'); + admin_redirect("index.php?module=user-titles"); + } + } + + $page->add_breadcrumb_item($lang->edit_user_title); + $page->output_header($lang->user_titles." - ".$lang->edit_user_title); + + $sub_tabs['edit_title'] = array( + 'title' => $lang->edit_user_title, + 'link' => "index.php?module=user-titles&action=edit&utid=".$mybb->input['utid'], + 'description' => $lang->edit_user_title_desc + ); + + $page->output_nav_tabs($sub_tabs, 'edit_title'); + $form = new Form("index.php?module=user-titles&action=edit&utid={$usertitle['utid']}", "post"); + + + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input = array_merge($mybb->input, $usertitle); + } + + $form_container = new FormContainer($lang->edit_user_title); + $form_container->output_row($lang->title_to_assign."*", $lang->title_to_assign_desc, $form->generate_text_box('title', $mybb->input['title'], array('id' => 'title')), 'title'); + $form_container->output_row($lang->minimum_posts, $lang->minimum_posts_desc, $form->generate_numeric_field('posts', $mybb->input['posts'], array('id' => 'posts')), 'posts'); + $form_container->output_row($lang->number_of_stars, $lang->number_of_stars_desc, $form->generate_numeric_field('stars', $mybb->input['stars'], array('id' => 'stars')), 'stars'); + $form_container->output_row($lang->star_image, $lang->star_image_desc, $form->generate_text_box('starimage', $mybb->input['starimage'], array('id' => 'starimage')), 'starimage'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->save_user_title); + + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); + +} + +if($mybb->input['action'] == "delete") +{ + $query = $db->simple_select("usertitles", "*", "utid='".(int)$mybb->input['utid']."'"); + $usertitle = $db->fetch_array($query); + + if(!$usertitle['utid']) + { + flash_message($lang->error_invalid_user_title, 'error'); + admin_redirect("index.php?module=user-titles"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=user-titles"); + } + + $plugins->run_hooks("admin_user_titles_delete"); + + if($mybb->request_method == "post") + { + $db->delete_query("usertitles", "utid='{$usertitle['utid']}'"); + + $plugins->run_hooks("admin_user_titles_delete_commit"); + + $cache->update_usertitles(); + + // Log admin action + log_admin_action($usertitle['utid'], $usertitle['title'], $usertitle['posts']); + + flash_message($lang->success_user_title_deleted, 'success'); + admin_redirect("index.php?module=user-titles"); + } + else + { + $page->output_confirm_action("index.php?module=user-titles&action=delete&utid={$usertitle['utid']}", $lang->user_title_deletion_confirmation); + } +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_user_titles_start"); + + $page->output_header($lang->manage_user_titles); + + $page->output_nav_tabs($sub_tabs, 'manage_titles'); + + $table = new Table; + $table->construct_header($lang->user_title); + $table->construct_header($lang->minimum_posts, array('width' => '130', 'class' => 'align_center')); + $table->construct_header($lang->controls, array("class" => "align_center", "colspan" => 2, "width" => 200)); + + $query = $db->simple_select("usertitles", "*", "", array('order_by' => 'posts')); + while($usertitle = $db->fetch_array($query)) + { + $usertitle['title'] = htmlspecialchars_uni($usertitle['title']); + $table->construct_cell("{$usertitle['title']}"); + $table->construct_cell($usertitle['posts'], array("class" => "align_center")); + $table->construct_cell("{$lang->edit}", array("width" => 100, "class" => "align_center")); + $table->construct_cell("post_code}\" onclick=\"return AdminCP.deleteConfirmation(this, '{$lang->user_title_deletion_confirmation}')\">{$lang->delete}", array("width" => 100, "class" => "align_center")); + $table->construct_row(); + } + + if($table->num_rows() == 0) + { + $table->construct_cell($lang->no_user_titles, array('colspan' => 4)); + $table->construct_row(); + $no_results = true; + } + + $table->output($lang->manage_user_titles); + + $page->output_footer(); +} diff --git a/Upload/admin/modules/user/users.php b/Upload/admin/modules/user/users.php new file mode 100644 index 0000000..1acc84f --- /dev/null +++ b/Upload/admin/modules/user/users.php @@ -0,0 +1,4114 @@ +
Please make sure IN_MYBB is defined."); +} + +require_once MYBB_ROOT."inc/functions_upload.php"; + +$page->add_breadcrumb_item($lang->users, "index.php?module=user-users"); + +if($mybb->input['action'] == "add" || $mybb->input['action'] == "merge" || $mybb->input['action'] == "search" || !$mybb->input['action']) +{ + $sub_tabs['browse_users'] = array( + 'title' => $lang->browse_users, + 'link' => "index.php?module=user-users", + 'description' => $lang->browse_users_desc + ); + + $sub_tabs['find_users'] = array( + 'title' => $lang->find_users, + 'link' => "index.php?module=user-users&action=search", + 'description' => $lang->find_users_desc + ); + + $sub_tabs['create_user'] = array( + 'title' => $lang->create_user, + 'link' => "index.php?module=user-users&action=add", + 'description' => $lang->create_user_desc + ); + + $sub_tabs['merge_users'] = array( + 'title' => $lang->merge_users, + 'link' => "index.php?module=user-users&action=merge", + 'description' => $lang->merge_users_desc + ); +} + +$user_view_fields = array( + "avatar" => array( + "title" => $lang->avatar, + "width" => "24", + "align" => "" + ), + + "username" => array( + "title" => $lang->username, + "width" => "", + "align" => "" + ), + + "email" => array( + "title" => $lang->email, + "width" => "", + "align" => "center" + ), + + "usergroup" => array( + "title" => $lang->primary_group, + "width" => "", + "align" => "center" + ), + + "additionalgroups" => array( + "title" => $lang->additional_groups, + "width" => "", + "align" => "center" + ), + + "regdate" => array( + "title" => $lang->registered, + "width" => "", + "align" => "center" + ), + + "lastactive" => array( + "title" => $lang->last_active, + "width" => "", + "align" => "center" + ), + + "postnum" => array( + "title" => $lang->post_count, + "width" => "", + "align" => "center" + ), + + "threadnum" => array( + "title" => $lang->thread_count, + "width" => "", + "align" => "center" + ), + + "reputation" => array( + "title" => $lang->reputation, + "width" => "", + "align" => "center" + ), + + "warninglevel" => array( + "title" => $lang->warning_level, + "width" => "", + "align" => "center" + ), + + "regip" => array( + "title" => $lang->registration_ip, + "width" => "", + "align" => "center" + ), + + "lastip" => array( + "title" => $lang->last_known_ip, + "width" => "", + "align" => "center" + ), + + "controls" => array( + "title" => $lang->controls, + "width" => "", + "align" => "center" + ) +); + +$sort_options = array( + "username" => $lang->username, + "regdate" => $lang->registration_date, + "lastactive" => $lang->last_active, + "numposts" => $lang->post_count, + "reputation" => $lang->reputation, + "warninglevel" => $lang->warning_level +); + +$plugins->run_hooks("admin_user_users_begin"); + +// Initialise the views manager for user based views +require MYBB_ADMIN_DIR."inc/functions_view_manager.php"; +if($mybb->input['action'] == "views") +{ + view_manager("index.php?module=user-users", "user", $user_view_fields, $sort_options, "user_search_conditions"); +} + +if($mybb->input['action'] == 'iplookup') +{ + $mybb->input['ipaddress'] = $mybb->get_input('ipaddress'); + $lang->ipaddress_misc_info = $lang->sprintf($lang->ipaddress_misc_info, htmlspecialchars_uni($mybb->input['ipaddress'])); + $ipaddress_location = $lang->na; + $ipaddress_host_name = $lang->na; + $modcp_ipsearch_misc_info = ''; + if(!strstr($mybb->input['ipaddress'], "*")) + { + // Return GeoIP information if it is available to us + if(function_exists('geoip_record_by_name')) + { + $ip_record = @geoip_record_by_name($mybb->input['ipaddress']); + if($ip_record) + { + $ipaddress_location = htmlspecialchars_uni(utf8_encode($ip_record['country_name'])); + if($ip_record['city']) + { + $ipaddress_location .= $lang->comma.htmlspecialchars_uni(utf8_encode($ip_record['city'])); + } + } + } + + $ipaddress_host_name = htmlspecialchars_uni(@gethostbyaddr($mybb->input['ipaddress'])); + + // gethostbyaddr returns the same ip on failure + if($ipaddress_host_name == $mybb->input['ipaddress']) + { + $ipaddress_host_name = $lang->na; + } + } + + ?> + +input['action'] == "activate_user") +{ + if(!verify_post_check($mybb->input['my_post_key'])) + { + flash_message($lang->invalid_post_verify_key2, 'error'); + admin_redirect("index.php?module=user-users"); + } + + $user = get_user($mybb->input['uid']); + + // Does the user not exist? + if(!$user['uid'] || $user['usergroup'] != 5) + { + flash_message($lang->error_invalid_user, 'error'); + admin_redirect("index.php?module=user-users"); + } + + $plugins->run_hooks("admin_user_users_coppa_activate"); + + $updated_user['usergroup'] = $user['usergroup']; + + // Update + if($user['coppauser']) + { + $updated_user = array( + "coppauser" => 0 + ); + } + else + { + $db->delete_query("awaitingactivation", "uid='{$user['uid']}'"); + } + + // Move out of awaiting activation if they're in it. + if($user['usergroup'] == 5) + { + $updated_user['usergroup'] = 2; + } + + $plugins->run_hooks("admin_user_users_coppa_activate_commit"); + + $db->update_query("users", $updated_user, "uid='{$user['uid']}'"); + + $cache->update_awaitingactivation(); + + $message = $lang->sprintf($lang->email_adminactivateaccount, $user['username'], $mybb->settings['bbname'], $mybb->settings['bburl']); + my_mail($user['email'], $lang->sprintf($lang->emailsubject_activateaccount, $mybb->settings['bbname']), $message); + + // Log admin action + log_admin_action($user['uid'], $user['username']); + + if($mybb->input['from'] == "home") + { + if($user['coppauser']) + { + $message = $lang->success_coppa_activated; + } + else + { + $message = $lang->success_activated; + } + + update_admin_session('flash_message2', array('message' => $message, 'type' => 'success')); + } + else + { + if($user['coppauser']) + { + flash_message($lang->success_coppa_activated, 'success'); + } + else + { + flash_message($lang->success_activated, 'success'); + } + } + + if($admin_session['data']['last_users_url']) + { + $url = $admin_session['data']['last_users_url']; + update_admin_session('last_users_url', ''); + + if($mybb->input['from'] == "home") + { + update_admin_session('from', 'home'); + } + } + else + { + $url = "index.php?module=user-users&action=edit&uid={$user['uid']}"; + } + + $plugins->run_hooks("admin_user_users_coppa_end"); + + admin_redirect($url); +} + +if($mybb->input['action'] == "add") +{ + $plugins->run_hooks("admin_user_users_add"); + + if($mybb->request_method == "post") + { + // Determine the usergroup stuff + if(is_array($mybb->input['additionalgroups'])) + { + foreach($mybb->input['additionalgroups'] as $key => $gid) + { + if($gid == $mybb->input['usergroup']) + { + unset($mybb->input['additionalgroups'][$key]); + } + } + $additionalgroups = implode(",", $mybb->input['additionalgroups']); + } + else + { + $additionalgroups = ''; + } + + // Set up user handler. + require_once MYBB_ROOT."inc/datahandlers/user.php"; + $userhandler = new UserDataHandler('insert'); + + // Set the data for the new user. + $new_user = array( + "uid" => $mybb->input['uid'], + "username" => $mybb->input['username'], + "password" => $mybb->input['password'], + "password2" => $mybb->input['confirm_password'], + "email" => $mybb->input['email'], + "email2" => $mybb->input['email'], + "usergroup" => $mybb->input['usergroup'], + "additionalgroups" => $additionalgroups, + "displaygroup" => $mybb->input['displaygroup'], + "profile_fields" => $mybb->input['profile_fields'], + "profile_fields_editable" => true, + ); + + // Set the data of the user in the datahandler. + $userhandler->set_data($new_user); + $errors = ''; + + // Validate the user and get any errors that might have occurred. + if(!$userhandler->validate_user()) + { + $errors = $userhandler->get_friendly_errors(); + } + else + { + $user_info = $userhandler->insert_user(); + + $plugins->run_hooks("admin_user_users_add_commit"); + + // Log admin action + log_admin_action($user_info['uid'], $user_info['username']); + + flash_message($lang->success_user_created, 'success'); + admin_redirect("index.php?module=user-users&action=edit&uid={$user_info['uid']}"); + } + } + + // Fetch custom profile fields - only need required profile fields here + $query = $db->simple_select("profilefields", "*", "required=1", array('order_by' => 'disporder')); + + $profile_fields = array(); + while($profile_field = $db->fetch_array($query)) + { + $profile_fields['required'][] = $profile_field; + } + + $page->add_breadcrumb_item($lang->create_user); + $page->output_header($lang->create_user); + + $form = new Form("index.php?module=user-users&action=add", "post"); + + $page->output_nav_tabs($sub_tabs, 'create_user'); + + // If we have any error messages, show them + if($errors) + { + $page->output_inline_error($errors); + } + else + { + $mybb->input = array_merge($mybb->input, array('usergroup' => 2)); + } + + $form_container = new FormContainer($lang->required_profile_info); + $form_container->output_row($lang->username." *", "", $form->generate_text_box('username', $mybb->input['username'], array('id' => 'username')), 'username'); + $form_container->output_row($lang->password." *", "", $form->generate_password_box('password', $mybb->input['password'], array('id' => 'password', 'autocomplete' => 'off')), 'password'); + $form_container->output_row($lang->confirm_password." *", "", $form->generate_password_box('confirm_password', $mybb->input['confirm_password'], array('id' => 'confirm_new_password')), 'confirm_new_password'); + $form_container->output_row($lang->email_address." *", "", $form->generate_text_box('email', $mybb->input['email'], array('id' => 'email')), 'email'); + + $display_group_options[0] = $lang->use_primary_user_group; + $options = array(); + $query = $db->simple_select("usergroups", "gid, title", "gid != '1'", array('order_by' => 'title')); + while($usergroup = $db->fetch_array($query)) + { + $options[$usergroup['gid']] = $usergroup['title']; + $display_group_options[$usergroup['gid']] = $usergroup['title']; + } + + $form_container->output_row($lang->primary_user_group." *", "", $form->generate_select_box('usergroup', $options, $mybb->input['usergroup'], array('id' => 'usergroup')), 'usergroup'); + $form_container->output_row($lang->additional_user_groups, $lang->additional_user_groups_desc, $form->generate_select_box('additionalgroups[]', $options, $mybb->input['additionalgroups'], array('id' => 'additionalgroups', 'multiple' => true, 'size' => 5)), 'additionalgroups'); + $form_container->output_row($lang->display_user_group." *", "", $form->generate_select_box('displaygroup', $display_group_options, $mybb->input['displaygroup'], array('id' => 'displaygroup')), 'displaygroup'); + + // Output custom profile fields - required + output_custom_profile_fields($profile_fields['required'], $mybb->input['profile_fields'], $form_container, $form); + + $form_container->end(); + $buttons[] = $form->generate_submit_button($lang->save_user); + $form->output_submit_wrapper($buttons); + + $form->end(); + $page->output_footer(); +} + +if($mybb->input['action'] == "edit") +{ + $user = get_user($mybb->input['uid']); + + // Does the user not exist? + if(!$user['uid']) + { + flash_message($lang->error_invalid_user, 'error'); + admin_redirect("index.php?module=user-users"); + } + + $plugins->run_hooks("admin_user_users_edit"); + + if($mybb->request_method == "post") + { + if(is_super_admin($mybb->input['uid']) && $mybb->user['uid'] != $mybb->input['uid'] && !is_super_admin($mybb->user['uid'])) + { + flash_message($lang->error_no_perms_super_admin, 'error'); + admin_redirect("index.php?module=user-users"); + } + + // Determine the usergroup stuff + if(is_array($mybb->input['additionalgroups'])) + { + foreach($mybb->input['additionalgroups'] as $key => $gid) + { + if($gid == $mybb->input['usergroup']) + { + unset($mybb->input['additionalgroups'][$key]); + } + } + $additionalgroups = implode(",", $mybb->input['additionalgroups']); + } + else + { + $additionalgroups = ''; + } + + $returndate = ""; + if(!empty($mybb->input['away_day'])) + { + $awaydate = TIME_NOW; + // If the user has indicated that they will return on a specific day, but not month or year, assume it is current month and year + if(!$mybb->input['away_month']) + { + $mybb->input['away_month'] = my_date('n', $awaydate); + } + if(!$mybb->input['away_year']) + { + $mybb->input['away_year'] = my_date('Y', $awaydate); + } + + $return_month = (int)substr($mybb->input['away_month'], 0, 2); + $return_day = (int)substr($mybb->input['away_day'], 0, 2); + $return_year = min((int)$mybb->input['away_year'], 9999); + + // Check if return date is after the away date. + $returntimestamp = gmmktime(0, 0, 0, $return_month, $return_day, $return_year); + $awaytimestamp = gmmktime(0, 0, 0, my_date('n', $awaydate), my_date('j', $awaydate), my_date('Y', $awaydate)); + if($return_year < my_date('Y', $awaydate) || ($returntimestamp < $awaytimestamp && $return_year == my_date('Y', $awaydate))) + { + $away_in_past = true; + } + + $returndate = "{$return_day}-{$return_month}-{$return_year}"; + } + + // Set up user handler. + require_once MYBB_ROOT."inc/datahandlers/user.php"; + $userhandler = new UserDataHandler('update'); + + // Set the data for the new user. + $updated_user = array( + "uid" => $mybb->input['uid'], + "username" => $mybb->input['username'], + "email" => $mybb->input['email'], + "email2" => $mybb->input['email'], + "usergroup" => $mybb->input['usergroup'], + "additionalgroups" => $additionalgroups, + "displaygroup" => $mybb->input['displaygroup'], + "postnum" => $mybb->input['postnum'], + "threadnum" => $mybb->input['threadnum'], + "usertitle" => $mybb->input['usertitle'], + "timezone" => $mybb->input['timezone'], + "language" => $mybb->input['language'], + "profile_fields" => $mybb->input['profile_fields'], + "profile_fields_editable" => true, + "website" => $mybb->input['website'], + "icq" => $mybb->input['icq'], + "aim" => $mybb->input['aim'], + "yahoo" => $mybb->input['yahoo'], + "skype" => $mybb->input['skype'], + "google" => $mybb->input['google'], + "birthday" => array( + "day" => $mybb->input['bday1'], + "month" => $mybb->input['bday2'], + "year" => $mybb->input['bday3'] + ), + "style" => $mybb->input['style'], + "signature" => $mybb->input['signature'], + "dateformat" => (int)$mybb->input['dateformat'], + "timeformat" => (int)$mybb->input['timeformat'], + "language" => $mybb->input['language'], + "usernotes" => $mybb->input['usernotes'], + "away" => array( + "away" => $mybb->input['away'], + "date" => TIME_NOW, + "returndate" => $returndate, + "awayreason" => $mybb->input['awayreason'] + ) + ); + + if($user['usergroup'] == 5 && $mybb->input['usergroup'] != 5) + { + if($user['coppauser'] == 1) + { + $updated_user['coppa_user'] = 0; + } + } + if($mybb->input['new_password']) + { + $updated_user['password'] = $mybb->input['new_password']; + $updated_user['password2'] = $mybb->input['confirm_new_password']; + } + + $updated_user['options'] = array( + "allownotices" => $mybb->input['allownotices'], + "hideemail" => $mybb->input['hideemail'], + "subscriptionmethod" => $mybb->input['subscriptionmethod'], + "invisible" => $mybb->input['invisible'], + "dstcorrection" => $mybb->input['dstcorrection'], + "threadmode" => $mybb->input['threadmode'], + "classicpostbit" => $mybb->input['classicpostbit'], + "showimages" => $mybb->input['showimages'], + "showvideos" => $mybb->input['showvideos'], + "showsigs" => $mybb->input['showsigs'], + "showavatars" => $mybb->input['showavatars'], + "showquickreply" => $mybb->input['showquickreply'], + "receivepms" => $mybb->input['receivepms'], + "receivefrombuddy" => $mybb->input['receivefrombuddy'], + "pmnotice" => $mybb->input['pmnotice'], + "daysprune" => $mybb->input['daysprune'], + "showcodebuttons" => $mybb->input['showcodebuttons'], + "sourceeditor" => $mybb->input['sourceeditor'], + "pmnotify" => $mybb->input['pmnotify'], + "showredirect" => $mybb->input['showredirect'] + ); + + if($mybb->settings['usertppoptions']) + { + $updated_user['options']['tpp'] = (int)$mybb->input['tpp']; + } + + if($mybb->settings['userpppoptions']) + { + $updated_user['options']['ppp'] = (int)$mybb->input['ppp']; + } + + // Set the data of the user in the datahandler. + $userhandler->set_data($updated_user); + $errors = ''; + + // Validate the user and get any errors that might have occurred. + if(!$userhandler->validate_user()) + { + $errors = $userhandler->get_friendly_errors(); + } + else + { + // Are we removing an avatar from this user? + if($mybb->input['remove_avatar']) + { + $extra_user_updates = array( + "avatar" => "", + "avatardimensions" => "", + "avatartype" => "" + ); + remove_avatars($user['uid']); + } + + // Are we uploading a new avatar? + if($_FILES['avatar_upload']['name']) + { + $avatar = upload_avatar($_FILES['avatar_upload'], $user['uid']); + if($avatar['error']) + { + $errors = array($avatar['error']); + } + else + { + if($avatar['width'] > 0 && $avatar['height'] > 0) + { + $avatar_dimensions = $avatar['width']."|".$avatar['height']; + } + $extra_user_updates = array( + "avatar" => $avatar['avatar'].'?dateline='.TIME_NOW, + "avatardimensions" => $avatar_dimensions, + "avatartype" => "upload" + ); + } + } + // Are we setting a new avatar from a URL? + else if($mybb->input['avatar_url'] && $mybb->input['avatar_url'] != $user['avatar']) + { + if(filter_var($mybb->input['avatar_url'], FILTER_VALIDATE_EMAIL) !== false) + { + // Gravatar + $email = md5(strtolower(trim($mybb->input['avatar_url']))); + + $s = ''; + if(!$mybb->settings['maxavatardims']) + { + $mybb->settings['maxavatardims'] = '100x100'; // Hard limit of 100 if there are no limits + } + + // Because Gravatars are square, hijack the width + list($maxwidth, $maxheight) = explode("x", my_strtolower($mybb->settings['maxavatardims'])); + + $s = "?s={$maxwidth}"; + $maxheight = (int)$maxwidth; + + $extra_user_updates = array( + "avatar" => "http://www.gravatar.com/avatar/{$email}{$s}", + "avatardimensions" => "{$maxheight}|{$maxheight}", + "avatartype" => "gravatar" + ); + } + else + { + $mybb->input['avatar_url'] = preg_replace("#script:#i", "", $mybb->input['avatar_url']); + $mybb->input['avatar_url'] = htmlspecialchars($mybb->input['avatar_url']); + $ext = get_extension($mybb->input['avatar_url']); + + // Copy the avatar to the local server (work around remote URL access disabled for getimagesize) + $file = fetch_remote_file($mybb->input['avatar_url']); + if(!$file) + { + $avatar_error = $lang->error_invalidavatarurl; + } + else + { + $tmp_name = "../".$mybb->settings['avataruploadpath']."/remote_".md5(random_str()); + $fp = @fopen($tmp_name, "wb"); + if(!$fp) + { + $avatar_error = $lang->error_invalidavatarurl; + } + else + { + fwrite($fp, $file); + fclose($fp); + list($width, $height, $type) = @getimagesize($tmp_name); + @unlink($tmp_name); + echo $type; + if(!$type) + { + $avatar_error = $lang->error_invalidavatarurl; + } + } + } + + if(empty($avatar_error)) + { + if($width && $height && $mybb->settings['maxavatardims'] != "") + { + list($maxwidth, $maxheight) = explode("x", my_strtolower($mybb->settings['maxavatardims'])); + if(($maxwidth && $width > $maxwidth) || ($maxheight && $height > $maxheight)) + { + $lang->error_avatartoobig = $lang->sprintf($lang->error_avatartoobig, $maxwidth, $maxheight); + $avatar_error = $lang->error_avatartoobig; + } + } + } + + if(empty($avatar_error)) + { + if($width > 0 && $height > 0) + { + $avatar_dimensions = (int)$width."|".(int)$height; + } + $extra_user_updates = array( + "avatar" => $db->escape_string($mybb->input['avatar_url'].'?dateline='.TIME_NOW), + "avatardimensions" => $avatar_dimensions, + "avatartype" => "remote" + ); + remove_avatars($user['uid']); + } + else + { + $errors = array($avatar_error); + } + } + } + + // Moderator "Options" (suspend signature, suspend/moderate posting) + $moderator_options = array( + 1 => array( + "action" => "suspendsignature", // The moderator action we're performing + "period" => "action_period", // The time period we've selected from the dropdown box + "time" => "action_time", // The time we've entered + "update_field" => "suspendsignature", // The field in the database to update if true + "update_length" => "suspendsigtime" // The length of suspension field in the database + ), + 2 => array( + "action" => "moderateposting", + "period" => "modpost_period", + "time" => "modpost_time", + "update_field" => "moderateposts", + "update_length" => "moderationtime" + ), + 3 => array( + "action" => "suspendposting", + "period" => "suspost_period", + "time" => "suspost_time", + "update_field" => "suspendposting", + "update_length" => "suspensiontime" + ) + ); + + require_once MYBB_ROOT."inc/functions_warnings.php"; + foreach($moderator_options as $option) + { + if(!$mybb->input[$option['action']]) + { + if($user[$option['update_field']] == 1) + { + // We're revoking the suspension + $extra_user_updates[$option['update_field']] = 0; + $extra_user_updates[$option['update_length']] = 0; + } + + // Skip this option if we haven't selected it + continue; + } + + if($mybb->input[$option['action']]) + { + if((int)$mybb->input[$option['time']] == 0 && $mybb->input[$option['period']] != "never" && $user[$option['update_field']] != 1) + { + // User has selected a type of ban, but not entered a valid time frame + $string = $option['action']."_error"; + $errors[] = $lang->$string; + } + + if(!is_array($errors)) + { + $suspend_length = fetch_time_length((int)$mybb->input[$option['time']], $mybb->input[$option['period']]); + + if($user[$option['update_field']] == 1 && ($mybb->input[$option['time']] || $mybb->input[$option['period']] == "never")) + { + // We already have a suspension, but entered a new time + if($suspend_length == "-1") + { + // Permanent ban on action + $extra_user_updates[$option['update_length']] = 0; + } + elseif($suspend_length && $suspend_length != "-1") + { + // Temporary ban on action + $extra_user_updates[$option['update_length']] = TIME_NOW + $suspend_length; + } + } + elseif(!$user[$option['update_field']]) + { + // New suspension for this user... bad user! + $extra_user_updates[$option['update_field']] = 1; + if($suspend_length == "-1") + { + $extra_user_updates[$option['update_length']] = 0; + } + else + { + $extra_user_updates[$option['update_length']] = TIME_NOW + $suspend_length; + } + } + } + } + } + + if($extra_user_updates['moderateposts'] && $extra_user_updates['suspendposting']) + { + $errors[] = $lang->suspendmoderate_error; + } + + if(isset($away_in_past)) + { + $errors[] = $lang->error_acp_return_date_past; + } + + if(!$errors) + { + $user_info = $userhandler->update_user(); + + $plugins->run_hooks("admin_user_users_edit_commit_start"); + + $db->update_query("users", $extra_user_updates, "uid='{$user['uid']}'"); + + // if we're updating the user's signature preferences, do so now + if($mybb->input['update_posts'] == 'enable' || $mybb->input['update_posts'] == 'disable') + { + $update_signature = array( + 'includesig' => ($mybb->input['update_posts'] == 'enable' ? 1 : 0) + ); + $db->update_query("posts", $update_signature, "uid='{$user['uid']}'"); + } + + $plugins->run_hooks("admin_user_users_edit_commit"); + + // Log admin action + log_admin_action($user['uid'], $mybb->input['username']); + + flash_message($lang->success_user_updated, 'success'); + admin_redirect("index.php?module=user-users"); + } + } + } + + if(!$errors) + { + $user['usertitle'] = htmlspecialchars_decode($user['usertitle']); + $mybb->input = array_merge($mybb->input, $user); + + $options = array( + 'bday1', 'bday2', 'bday3', + 'new_password', 'confirm_new_password', + 'action_time', 'action_period', + 'modpost_period', 'moderateposting', 'modpost_time', 'suspost_period', 'suspost_time' + ); + + foreach($options as $option) + { + if(!isset($input_user[$option])) + { + $mybb->input[$option] = ''; + } + } + + // We need to fetch this users profile field values + $query = $db->simple_select("userfields", "*", "ufid='{$user['uid']}'"); + $mybb->input['profile_fields'] = $db->fetch_array($query); + } + + if($mybb->input['bday1'] || $mybb->input['bday2'] || $mybb->input['bday3']) + { + $mybb->input['bday'][0] = $mybb->input['bday1']; + $mybb->input['bday'][1] = $mybb->input['bday2']; + $mybb->input['bday'][2] = (int)$mybb->input['bday3']; + } + else + { + $mybb->input['bday'] = array(0, 0, ''); + + if($user['birthday']) + { + $mybb->input['bday'] = explode('-', $user['birthday']); + } + } + + if($mybb->input['away_day'] || $mybb->input['away_month'] || $mybb->input['away_year']) + { + $mybb->input['away_year'] = (int)$mybb->input['away_year']; + } + else + { + $mybb->input['away_day'] = 0; + $mybb->input['away_month'] = 0; + $mybb->input['away_year'] = ''; + + if($user['returndate']) + { + list($mybb->input['away_day'], $mybb->input['away_month'], $mybb->input['away_year']) = explode('-', $user['returndate']); + } + } + + // Fetch custom profile fields + $query = $db->simple_select("profilefields", "*", "", array('order_by' => 'disporder')); + + $profile_fields = array(); + while($profile_field = $db->fetch_array($query)) + { + if($profile_field['required'] == 1) + { + $profile_fields['required'][] = $profile_field; + } + else + { + $profile_fields['optional'][] = $profile_field; + } + } + + $page->add_breadcrumb_item($lang->edit_user.": ".htmlspecialchars_uni($user['username'])); + + $page->extra_header .= << + + +EOF; + $page->output_header($lang->edit_user); + + $sub_tabs['edit_user'] = array( + 'title' => $lang->edit_user, + 'description' => $lang->edit_user_desc + ); + + $form = new Form("index.php?module=user-users&action=edit&uid={$user['uid']}", "post", "", 1); + + $page->output_nav_tabs($sub_tabs, 'edit_user'); + + // If we have any error messages, show them + if($errors) + { + $page->output_inline_error($errors); + } + + // Is this user a COPPA user? We show a warning & activate link + if($user['coppauser']) + { + echo $lang->sprintf($lang->warning_coppa_user, $user['uid']); + } + + $tabs = array( + "overview" => $lang->overview, + "profile" => $lang->profile, + "settings" => $lang->account_settings, + "signature" => $lang->signature, + "avatar" => $lang->avatar, + "modoptions" => $lang->mod_options + ); + $tabs = $plugins->run_hooks("admin_user_users_edit_graph_tabs", $tabs); + $page->output_tab_control($tabs); + + // + // OVERVIEW + // + echo "
\n"; + $table = new Table; + $table->construct_header($lang->avatar, array('class' => 'align_center')); + $table->construct_header($lang->general_account_stats, array('colspan' => '2', 'class' => 'align_center')); + + // Avatar + $avatar_dimensions = explode("|", $user['avatardimensions']); + if($user['avatar']) + { + if($user['avatardimensions']) + { + require_once MYBB_ROOT."inc/functions_image.php"; + list($width, $height) = explode("|", $user['avatardimensions']); + $scaled_dimensions = scale_image($width, $height, 120, 120); + } + else + { + $scaled_dimensions = array( + "width" => 120, + "height" => 120 + ); + } + if(my_substr($user['avatar'], 0, 7) !== 'http://' && my_substr($user['avatar'], 0, 8) !== 'https://') + { + $user['avatar'] = "../{$user['avatar']}\n"; + } + } + else + { + $user['avatar'] = "../".$mybb->settings['useravatar']; + $scaled_dimensions = array( + "width" => 120, + "height" => 120 + ); + } + $avatar_top = ceil((126-$scaled_dimensions['height'])/2); + if($user['lastactive']) + { + $last_active = my_date('relative', $user['lastactive']); + } + else + { + $last_active = $lang->never; + } + $reg_date = my_date('relative', $user['regdate']); + if($user['dst'] == 1) + { + $timezone = $user['timezone']+1; + } + else + { + $timezone = $user['timezone']; + } + $local_date = gmdate($mybb->settings['dateformat'], TIME_NOW + ($timezone * 3600)); + $local_time = gmdate($mybb->settings['timeformat'], TIME_NOW + ($timezone * 3600)); + + $localtime = $lang->sprintf($lang->local_time_format, $local_date, $local_time); + $days_registered = (TIME_NOW - $user['regdate']) / (24*3600); + $posts_per_day = 0; + if($days_registered > 0) + { + $posts_per_day = round($user['postnum'] / $days_registered, 2); + if($posts_per_day > $user['postnum']) + { + $posts_per_day = $user['postnum']; + } + } + $posts_per_day = my_number_format($posts_per_day); + + $stats = $cache->read("stats"); + $posts = $stats['numposts']; + if($posts == 0) + { + $percent_posts = "0"; + } + else + { + $percent_posts = round($user['postnum']*100/$posts, 2); + } + + $user_permissions = user_permissions($user['uid']); + + // Fetch the reputation for this user + if($user_permissions['usereputationsystem'] == 1 && $mybb->settings['enablereputation'] == 1) + { + $reputation = get_reputation($user['reputation']); + } + else + { + $reputation = "-"; + } + + if($mybb->settings['enablewarningsystem'] != 0 && $user_permissions['canreceivewarnings'] != 0) + { + $warning_level = round($user['warningpoints']/$mybb->settings['maxwarningpoints']*100); + if($warning_level > 100) + { + $warning_level = 100; + } + $warning_level = get_colored_warning_level($warning_level); + } + + $age = $lang->na; + if($user['birthday']) + { + $age = get_age($user['birthday']); + } + + $postnum = my_number_format($user['postnum']); + + $table->construct_cell("
\"\"
", array('rowspan' => 6, 'width' => 1)); + $table->construct_cell("{$lang->email_address}: ".htmlspecialchars_uni($user['email']).""); + $table->construct_cell("{$lang->last_active}: {$last_active}"); + $table->construct_row(); + $table->construct_cell("{$lang->registration_date}: {$reg_date}"); + $table->construct_cell("{$lang->local_time}: {$localtime}"); + $table->construct_row(); + $table->construct_cell("{$lang->posts}: {$postnum}"); + $table->construct_cell("{$lang->age}: {$age}"); + $table->construct_row(); + $table->construct_cell("{$lang->posts_per_day}: {$posts_per_day}"); + $table->construct_cell("{$lang->reputation}: {$reputation}"); + $table->construct_row(); + $table->construct_cell("{$lang->percent_of_total_posts}: {$percent_posts}"); + $table->construct_cell("{$lang->warning_level}: {$warning_level}"); + $table->construct_row(); + $table->construct_cell("{$lang->registration_ip}: ".my_inet_ntop($db->unescape_binary($user['regip']))); + $table->construct_cell("{$lang->last_known_ip}: ".my_inet_ntop($db->unescape_binary($user['lastip']))); + $table->construct_row(); + + $table->output("{$lang->user_overview}: {$user['username']}"); + echo "
\n"; + + // + // PROFILE + // + echo "
\n"; + + $form_container = new FormContainer($lang->required_profile_info.": {$user['username']}"); + $form_container->output_row($lang->username." *", "", $form->generate_text_box('username', $mybb->input['username'], array('id' => 'username')), 'username'); + $form_container->output_row($lang->new_password, $lang->new_password_desc, $form->generate_password_box('new_password', $mybb->input['new_password'], array('id' => 'new_password', 'autocomplete' => 'off')), 'new_password'); + $form_container->output_row($lang->confirm_new_password, $lang->new_password_desc, $form->generate_password_box('confirm_new_password', $mybb->input['confirm_new_password'], array('id' => 'confirm_new_password')), 'confirm_new_password'); + $form_container->output_row($lang->email_address." *", "", $form->generate_text_box('email', $mybb->input['email'], array('id' => 'email')), 'email'); + + $display_group_options[0] = $lang->use_primary_user_group; + $options = array(); + $query = $db->simple_select("usergroups", "gid, title", "gid != '1'", array('order_by' => 'title')); + while($usergroup = $db->fetch_array($query)) + { + $options[$usergroup['gid']] = $usergroup['title']; + $display_group_options[$usergroup['gid']] = $usergroup['title']; + } + + if(!is_array($mybb->input['additionalgroups'])) + { + $mybb->input['additionalgroups'] = explode(',', $mybb->input['additionalgroups']); + } + + $form_container->output_row($lang->primary_user_group." *", "", $form->generate_select_box('usergroup', $options, $mybb->input['usergroup'], array('id' => 'usergroup')), 'usergroup'); + $form_container->output_row($lang->additional_user_groups, $lang->additional_user_groups_desc, $form->generate_select_box('additionalgroups[]', $options, $mybb->input['additionalgroups'], array('id' => 'additionalgroups', 'multiple' => true, 'size' => 5)), 'additionalgroups'); + $form_container->output_row($lang->display_user_group." *", "", $form->generate_select_box('displaygroup', $display_group_options, $mybb->input['displaygroup'], array('id' => 'displaygroup')), 'displaygroup'); + $form_container->output_row($lang->post_count." *", "", $form->generate_numeric_field('postnum', $mybb->input['postnum'], array('id' => 'postnum')), 'postnum'); + $form_container->output_row($lang->thread_count." *", "", $form->generate_numeric_field('threadnum', $mybb->input['threadnum'], array('id' => 'threadnum')), 'threadnum'); + + // Output custom profile fields - required + if(!isset($profile_fields['required'])) + { + $profile_fields['required'] = array(); + } + output_custom_profile_fields($profile_fields['required'], $mybb->input['profile_fields'], $form_container, $form); + + $form_container->end(); + + $form_container = new FormContainer($lang->optional_profile_info.": {$user['username']}"); + $form_container->output_row($lang->custom_user_title, $lang->custom_user_title_desc, $form->generate_text_box('usertitle', $mybb->input['usertitle'], array('id' => 'usertitle')), 'usertitle'); + $form_container->output_row($lang->website, "", $form->generate_text_box('website', $mybb->input['website'], array('id' => 'website')), 'website'); + $form_container->output_row($lang->icq_number, "", $form->generate_numeric_field('icq', $mybb->input['icq'], array('id' => 'icq')), 'icq'); + $form_container->output_row($lang->aim_handle, "", $form->generate_text_box('aim', $mybb->input['aim'], array('id' => 'aim')), 'aim'); + $form_container->output_row($lang->yahoo_messanger_handle, "", $form->generate_text_box('yahoo', $mybb->input['yahoo'], array('id' => 'yahoo')), 'yahoo'); + $form_container->output_row($lang->skype_handle, "", $form->generate_text_box('skype', $mybb->input['skype'], array('id' => 'skype')), 'skype'); + $form_container->output_row($lang->google_handle, "", $form->generate_text_box('google', $mybb->input['google'], array('id' => 'google')), 'google'); + + // Birthday + $birthday_days = array(0 => ''); + for($i = 1; $i <= 31; $i++) + { + $birthday_days[$i] = $i; + } + + $birthday_months = array( + 0 => '', + 1 => $lang->january, + 2 => $lang->february, + 3 => $lang->march, + 4 => $lang->april, + 5 => $lang->may, + 6 => $lang->june, + 7 => $lang->july, + 8 => $lang->august, + 9 => $lang->september, + 10 => $lang->october, + 11 => $lang->november, + 12 => $lang->december + ); + + $birthday_row = $form->generate_select_box('bday1', $birthday_days, $mybb->input['bday'][0], array('id' => 'bday_day')); + $birthday_row .= ' '.$form->generate_select_box('bday2', $birthday_months, $mybb->input['bday'][1], array('id' => 'bday_month')); + $birthday_row .= ' '.$form->generate_numeric_field('bday3', $mybb->input['bday'][2], array('id' => 'bday_year', 'style' => 'width: 3em;')); + + $form_container->output_row($lang->birthday, "", $birthday_row, 'birthday'); + + // Output custom profile fields - optional + output_custom_profile_fields($profile_fields['optional'], $mybb->input['profile_fields'], $form_container, $form); + + $form_container->end(); + + + if($mybb->settings['allowaway'] != 0) + { + $form_container = new FormContainer($lang->away_information.": {$user['username']}"); + $awaycheck = array(false, true); + if($mybb->input['away'] == 1) + { + $awaycheck = array(true, false); + } + $form_container->output_row($lang->away_status, $lang->away_status_desc, $form->generate_radio_button('away', 1, $lang->im_away, array('id' => 'away', "checked" => $awaycheck[0]))." ".$form->generate_radio_button('away', 0, $lang->im_here, array('id' => 'away2', "checked" => $awaycheck[1])), 'away'); + $form_container->output_row($lang->away_reason, $lang->away_reason_desc, $form->generate_text_box('awayreason', $mybb->input['awayreason'], array('id' => 'awayreason')), 'awayreason'); + + //Return date (we can use the arrays from birthday) + $return_row = $form->generate_select_box('away_day', $birthday_days, $mybb->input['away_day'], array('id' => 'away_day')); + $return_row .= ' '.$form->generate_select_box('away_month', $birthday_months, $mybb->input['away_month'], array('id' => 'away_month')); + $return_row .= ' '.$form->generate_numeric_field('away_year', $mybb->input['away_year'], array('id' => 'away_year', 'style' => 'width: 3em;')); + + $form_container->output_row($lang->return_date, $lang->return_date_desc, $return_row, 'away_date'); + + $form_container->end(); + } + + echo "
\n"; + + // + // ACCOUNT SETTINGS + // + + // Plugin hook note - we should add hooks in above each output_row for the below so users can add their own options to each group :> + + echo "
\n"; + $form_container = new FormContainer($lang->account_settings.": {$user['username']}"); + $login_options = array( + $form->generate_check_box("invisible", 1, $lang->hide_from_whos_online, array("checked" => $mybb->input['invisible'])), + ); + $form_container->output_row($lang->login_cookies_privacy, "", "
".implode("
", $login_options)."
"); + + if($mybb->input['pmnotice'] > 1) + { + $mybb->input['pmnotice'] = 1; + } + + $messaging_options = array( + $form->generate_check_box("allownotices", 1, $lang->recieve_admin_emails, array("checked" => $mybb->input['allownotices'])), + $form->generate_check_box("hideemail", 1, $lang->hide_email_from_others, array("checked" => $mybb->input['hideemail'])), + $form->generate_check_box("receivepms", 1, $lang->recieve_pms_from_others, array("checked" => $mybb->input['receivepms'])), + $form->generate_check_box("receivefrombuddy", 1, $lang->recieve_pms_from_buddy, array("checked" => $mybb->input['receivefrombuddy'])), + $form->generate_check_box("pmnotice", 1, $lang->alert_new_pms, array("checked" => $mybb->input['pmnotice'])), + $form->generate_check_box("pmnotify", 1, $lang->email_notify_new_pms, array("checked" => $mybb->input['pmnotify'])), + "
".$form->generate_select_box("subscriptionmethod", array($lang->do_not_subscribe, $lang->no_email_notification, $lang->instant_email_notification), $mybb->input['subscriptionmethod'], array('id' => 'subscriptionmethod')) + ); + $form_container->output_row($lang->messaging_and_notification, "", "
".implode("
", $messaging_options)."
"); + + $date_format_options = array($lang->use_default); + foreach($date_formats as $key => $format) + { + $date_format_options[$key] = my_date($format, TIME_NOW, "", 0); + } + + $time_format_options = array($lang->use_default); + foreach($time_formats as $key => $format) + { + $time_format_options[$key] = my_date($format, TIME_NOW, "", 0); + } + + $date_options = array( + "
".$form->generate_select_box("dateformat", $date_format_options, $mybb->input['dateformat'], array('id' => 'dateformat')), + "
".$form->generate_select_box("timeformat", $time_format_options, $mybb->input['timeformat'], array('id' => 'timeformat')), + "
".build_timezone_select("timezone", $mybb->input['timezone']), + "
".$form->generate_select_box("dstcorrection", array(2 => $lang->automatically_detect, 1 => $lang->always_use_dst_correction, 0 => $lang->never_use_dst_correction), $mybb->input['dstcorrection'], array('id' => 'dstcorrection')) + ); + $form_container->output_row($lang->date_and_time_options, "", "
".implode("
", $date_options)."
"); + + + $tpp_options = array($lang->use_default); + if($mybb->settings['usertppoptions']) + { + $explodedtpp = explode(",", $mybb->settings['usertppoptions']); + if(is_array($explodedtpp)) + { + foreach($explodedtpp as $tpp) + { + if($tpp <= 0) continue; + $tpp_options[$tpp] = $tpp; + } + } + } + + $thread_age_options = array( + 0 => $lang->use_default, + 1 => $lang->show_threads_last_day, + 5 => $lang->show_threads_last_5_days, + 10 => $lang->show_threads_last_10_days, + 20 => $lang->show_threads_last_20_days, + 50 => $lang->show_threads_last_50_days, + 75 => $lang->show_threads_last_75_days, + 100 => $lang->show_threads_last_100_days, + 365 => $lang->show_threads_last_year, + 9999 => $lang->show_all_threads + ); + + $forum_options = array( + "
".$form->generate_select_box("tpp", $tpp_options, $mybb->input['tpp'], array('id' => 'tpp')), + "
".$form->generate_select_box("daysprune", $thread_age_options, $mybb->input['daysprune'], array('id' => 'daysprune')) + ); + $form_container->output_row($lang->forum_display_options, "", "
".implode("
", $forum_options)."
"); + + $ppp_options = array($lang->use_default); + if($mybb->settings['userpppoptions']) + { + $explodedppp = explode(",", $mybb->settings['userpppoptions']); + if(is_array($explodedppp)) + { + foreach($explodedppp as $ppp) + { + if($ppp <= 0) continue; + $ppp_options[$ppp] = $ppp; + } + } + } + + $thread_options = array( + $form->generate_check_box("classicpostbit", 1, $lang->show_classic_postbit, array("checked" => $mybb->input['classicpostbit'])), + $form->generate_check_box("showimages", 1, $lang->display_images, array("checked" => $mybb->input['showimages'])), + $form->generate_check_box("showvideos", 1, $lang->display_videos, array("checked" => $mybb->input['showvideos'])), + $form->generate_check_box("showsigs", 1, $lang->display_users_sigs, array("checked" => $mybb->input['showsigs'])), + $form->generate_check_box("showavatars", 1, $lang->display_users_avatars, array("checked" => $mybb->input['showavatars'])), + $form->generate_check_box("showquickreply", 1, $lang->show_quick_reply, array("checked" => $mybb->input['showquickreply'])), + "
".$form->generate_select_box("ppp", $ppp_options, $mybb->input['ppp'], array('id' => 'ppp')), + "
".$form->generate_select_box("threadmode", array("" => $lang->use_default, "linear" => $lang->linear_mode, "threaded" => $lang->threaded_mode), $mybb->input['threadmode'], array('id' => 'threadmode')) + ); + $form_container->output_row($lang->thread_view_options, "", "
".implode("
", $thread_options)."
"); + + $languages = array_merge(array('' => $lang->use_default), $lang->get_languages()); + + $other_options = array( + $form->generate_check_box("showredirect", 1, $lang->show_redirect, array("checked" => $mybb->input['showredirect'])), + $form->generate_check_box("showcodebuttons", "1", $lang->show_code_buttons, array("checked" => $mybb->input['showcodebuttons'])), + $form->generate_check_box("sourceeditor", "1", $lang->source_editor, array("checked" => $mybb->input['sourceeditor'])), + "
".build_theme_select("style", $mybb->input['style'], 0, "", true, false, true), + "
".$form->generate_select_box("language", $languages, $mybb->input['language'], array('id' => 'language')) + ); + $form_container->output_row($lang->other_options, "", "
".implode("
", $other_options)."
"); + + $form_container->end(); + echo "
\n"; + + // + // SIGNATURE EDITOR + // + $signature_editor = $form->generate_text_area("signature", $mybb->input['signature'], array('id' => 'signature', 'rows' => 15, 'cols' => '70', 'style' => 'height: 250px; width: 95%')); + $sig_smilies = $lang->off; + if($mybb->settings['sigsmilies'] == 1) + { + $sig_smilies = $lang->on; + } + $sig_mycode = $lang->off; + if($mybb->settings['sigmycode'] == 1) + { + $sig_mycode = $lang->on; + $signature_editor .= build_mycode_inserter("signature"); + } + $sig_html = $lang->off; + if($mybb->settings['sightml'] == 1) + { + $sig_html = $lang->on; + } + $sig_imgcode = $lang->off; + if($mybb->settings['sigimgcode'] == 1) + { + $sig_imgcode = $lang->on; + } + echo "
\n"; + $form_container = new FormContainer("{$lang->signature}: {$user['username']}"); + $form_container->output_row($lang->signature, $lang->sprintf($lang->signature_desc, $sig_mycode, $sig_smilies, $sig_imgcode, $sig_html), $signature_editor, 'signature'); + + $periods = array( + "hours" => $lang->expire_hours, + "days" => $lang->expire_days, + "weeks" => $lang->expire_weeks, + "months" => $lang->expire_months, + "never" => $lang->expire_permanent + ); + + // Are we already suspending the signature? + if($mybb->input['suspendsignature']) + { + $sig_checked = 1; + + // Display how much time is left on the ban for the user to extend it + if($user['suspendsigtime'] == "0") + { + // Permanent + $lang->suspend_expire_info = $lang->suspend_sig_perm; + } + else + { + // There's a limit to the suspension! + $expired = my_date('relative', $user['suspendsigtime']); + $lang->suspend_expire_info = $lang->sprintf($lang->suspend_expire_info, $expired); + } + $user_suspend_info = ' + + '.$lang->suspend_expire_info.'
'.$lang->suspend_sig_extend.' + '; + } + else + { + $sig_checked = 0; + $user_suspend_info = ''; + } + + $actions = ' + + +
+
'.$form->generate_check_box("suspendsignature", 1, $lang->suspend_sig_box, array('checked' => $sig_checked, 'onclick' => 'toggleAction();')).'
+
+ '.$user_suspend_info.' + + + + +
'.$lang->expire_length.''.$form->generate_numeric_field('action_time', $mybb->input['action_time'], array('style' => 'width: 2em;')).' '.$form->generate_select_box('action_period', $periods, $mybb->input['action_period']).'
+
+
+ + '; + + $form_container->output_row($lang->suspend_sig, $lang->suspend_sig_info, $actions); + + $signature_options = array( + $form->generate_radio_button("update_posts", "enable", $lang->enable_sig_in_all_posts, array("checked" => 0)), + $form->generate_radio_button("update_posts", "disable", $lang->disable_sig_in_all_posts, array("checked" => 0)), + $form->generate_radio_button("update_posts", "no", $lang->do_nothing, array("checked" => 1)) + ); + + $form_container->output_row($lang->signature_preferences, "", implode("
", $signature_options)); + + $form_container->end(); + echo "
\n"; + + // + // AVATAR MANAGER + // + echo "
\n"; + $table = new Table; + $table->construct_header($lang->current_avatar, array('colspan' => 2)); + + $table->construct_cell("
\"\"
", array('width' => 1)); + + $avatar_url = ''; + if($user['avatartype'] == "upload" || stristr($user['avatar'], $mybb->settings['avataruploadpath'])) + { + $current_avatar_msg = "
{$lang->user_current_using_uploaded_avatar}"; + } + elseif($user['avatartype'] == "remote" || my_strpos(my_strtolower($user['avatar']), "http://") !== false) + { + $current_avatar_msg = "
{$lang->user_current_using_remote_avatar}"; + $avatar_url = $user['avatar']; + } + + if($errors) + { + $avatar_url = $mybb->input['avatar_url']; + } + + if($mybb->settings['maxavatardims'] != "") + { + list($max_width, $max_height) = explode("x", my_strtolower($mybb->settings['maxavatardims'])); + $max_size = "
{$lang->max_dimensions_are} {$max_width}x{$max_height}"; + } + + if($mybb->settings['avatarsize']) + { + $maximum_size = get_friendly_size($mybb->settings['avatarsize']*1024); + $max_size .= "
{$lang->avatar_max_size} {$maximum_size}"; + } + + if($user['avatar']) + { + $remove_avatar = "

".$form->generate_check_box("remove_avatar", 1, "{$lang->remove_avatar}"); + } + + $table->construct_cell($lang->avatar_desc."{$remove_avatar}
{$max_size}"); + $table->construct_row(); + + $table->output($lang->avatar.": {$user['username']}"); + + // Custom avatar + if($mybb->settings['avatarresizing'] == "auto") + { + $auto_resize = $lang->avatar_auto_resize; + } + else if($mybb->settings['avatarresizing'] == "user") + { + $auto_resize = " "; + } + $form_container = new FormContainer($lang->specify_custom_avatar); + $form_container->output_row($lang->upload_avatar, $auto_resize, $form->generate_file_upload_box('avatar_upload', array('id' => 'avatar_upload')), 'avatar_upload'); + $form_container->output_row($lang->or_specify_avatar_url, "", $form->generate_text_box('avatar_url', $avatar_url, array('id' => 'avatar_url')), 'avatar_url'); + $form_container->end(); + echo "
\n"; + + // + // MODERATOR OPTIONS + // + $periods = array( + "hours" => $lang->expire_hours, + "days" => $lang->expire_days, + "weeks" => $lang->expire_weeks, + "months" => $lang->expire_months, + "never" => $lang->expire_permanent + ); + + echo "
\n"; + $form_container = new FormContainer($lang->mod_options.": {$user['username']}"); + $form_container->output_row($lang->user_notes, '', $form->generate_text_area('usernotes', $mybb->input['usernotes'], array('id' => 'usernotes')), 'usernotes'); + + // Mod posts + // Generate check box + $modpost_options = $form->generate_select_box('modpost_period', $periods, $mybb->input['modpost_period'], array('id' => 'modpost_period')); + + // Do we have any existing suspensions here? + $existing_info = ''; + if($user['moderateposts'] || ($mybb->input['moderateposting'] && !empty($errors))) + { + $mybb->input['moderateposting'] = 1; + if($user['moderationtime'] != 0) + { + $expired = my_date('relative', $user['moderationtime']); + $existing_info = $lang->sprintf($lang->moderate_length, $expired); + } + else + { + $existing_info = $lang->moderated_perm; + } + } + + $modpost_div = '
'.$existing_info.''.$lang->moderate_for.' '.$form->generate_numeric_field("modpost_time", $mybb->input['modpost_time'], array('style' => 'width: 2em;')).' '.$modpost_options.'
'; + $lang->moderate_posts_info = $lang->sprintf($lang->moderate_posts_info, $user['username']); + $form_container->output_row($form->generate_check_box("moderateposting", 1, $lang->moderate_posts, array("id" => "moderateposting", "onclick" => "toggleBox('modpost');", "checked" => $mybb->input['moderateposting'])), $lang->moderate_posts_info, $modpost_div); + + // Suspend posts + // Generate check box + $suspost_options = $form->generate_select_box('suspost_period', $periods, $mybb->input['suspost_period'], array('id' => 'suspost_period')); + + // Do we have any existing suspensions here? + if($user['suspendposting'] || ($mybb->input['suspendposting'] && !empty($errors))) + { + $mybb->input['suspendposting'] = 1; + + if($user['suspensiontime'] == 0 || $mybb->input['suspost_period'] == "never") + { + $existing_info = $lang->suspended_perm; + } + else + { + $suspost_date = my_date('relative', $user['suspensiontime']); + $existing_info = $lang->sprintf($lang->suspend_length, $suspost_date); + } + } + + $suspost_div = '
'.$existing_info.''.$lang->suspend_for.' '.$form->generate_numeric_field("suspost_time", $mybb->input['suspost_time'], array('style' => 'width: 2em;')).' '.$suspost_options.'
'; + $lang->suspend_posts_info = $lang->sprintf($lang->suspend_posts_info, $user['username']); + $form_container->output_row($form->generate_check_box("suspendposting", 1, $lang->suspend_posts, array("id" => "suspendposting", "onclick" => "toggleBox('suspost');", "checked" => $mybb->input['suspendposting'])), $lang->suspend_posts_info, $suspost_div); + + + $form_container->end(); + echo "
\n"; + + $plugins->run_hooks("admin_user_users_edit_graph"); + + $buttons[] = $form->generate_submit_button($lang->save_user); + $form->output_submit_wrapper($buttons); + + $form->end(); + + echo ''; + + $page->output_footer(); +} + +if($mybb->input['action'] == "delete") +{ + $user = get_user($mybb->input['uid']); + + // Does the user not exist? + if(!$user['uid']) + { + flash_message($lang->error_invalid_user, 'error'); + admin_redirect("index.php?module=user-users"); + } + + if(is_super_admin($mybb->input['uid']) && $mybb->user['uid'] != $mybb->input['uid'] && !is_super_admin($mybb->user['uid'])) + { + flash_message($lang->error_no_perms_super_admin, 'error'); + admin_redirect("index.php?module=user-users"); + } + + // User clicked no + if($mybb->input['no']) + { + admin_redirect("index.php?module=user-users"); + } + + $plugins->run_hooks("admin_user_users_delete"); + + if($mybb->request_method == "post") + { + $plugins->run_hooks("admin_user_users_delete_commit"); + + // Set up user handler. + require_once MYBB_ROOT.'inc/datahandlers/user.php'; + $userhandler = new UserDataHandler('delete'); + + // Delete the user + if(!$userhandler->delete_user($user['uid'])) + { + flash_message($lang->error_cannot_delete_user, 'error'); + admin_redirect("index.php?module=user-users"); + } + + $plugins->run_hooks("admin_user_users_delete_commit_end"); + + log_admin_action($user['uid'], $user['username']); + + flash_message($lang->success_user_deleted, 'success'); + admin_redirect("index.php?module=user-users"); + } + else + { + $page->output_confirm_action("index.php?module=user-users&action=delete&uid={$user['uid']}", $lang->user_deletion_confirmation); + } +} + +if($mybb->input['action'] == "referrers") +{ + $page->add_breadcrumb_item($lang->show_referrers); + $page->output_header($lang->show_referrers); + + $sub_tabs['referrers'] = array( + 'title' => $lang->show_referrers, + 'link' => "index.php?module=user-users&action=referrers&uid={$mybb->input['uid']}", + 'description' => $lang->show_referrers_desc + ); + + $plugins->run_hooks("admin_user_users_referrers"); + + $page->output_nav_tabs($sub_tabs, 'referrers'); + + // Fetch default admin view + $default_view = fetch_default_view("user"); + if(!$default_view) + { + $default_view = "0"; + } + $query = $db->simple_select("adminviews", "*", "type='user' AND (vid='{$default_view}' OR uid=0)", array("order_by" => "uid", "order_dir" => "desc")); + $admin_view = $db->fetch_array($query); + + if($mybb->input['type']) + { + $admin_view['view_type'] = $mybb->input['type']; + } + + $admin_view['conditions'] = my_unserialize($admin_view['conditions']); + $admin_view['conditions']['referrer'] = $mybb->input['uid']; + + $view = build_users_view($admin_view); + + // No referred users + if(!$view) + { + $table = new Table; + $table->construct_cell($lang->error_no_referred_users); + $table->construct_row(); + $table->output($lang->show_referrers); + } + else + { + echo $view; + } + + $page->output_footer(); +} + +if($mybb->input['action'] == "ipaddresses") +{ + $page->add_breadcrumb_item($lang->ip_addresses); + $page->output_header($lang->ip_addresses); + + $sub_tabs['ipaddresses'] = array( + 'title' => $lang->show_ip_addresses, + 'link' => "index.php?module=user-users&action=ipaddresses&uid={$mybb->input['uid']}", + 'description' => $lang->show_ip_addresses_desc + ); + + $plugins->run_hooks("admin_user_users_ipaddresses"); + + $page->output_nav_tabs($sub_tabs, 'ipaddresses'); + + $query = $db->simple_select("users", "uid, regip, username, lastip", "uid='{$mybb->input['uid']}'", array('limit' => 1)); + $user = $db->fetch_array($query); + + // Log admin action + log_admin_action($user['uid'], $user['username']); + + $table = new Table; + + $table->construct_header($lang->ip_address); + $table->construct_header($lang->controls, array('width' => 200, 'class' => "align_center")); + + if(empty($user['lastip'])) + { + $user['lastip'] = $lang->unknown; + $controls = ''; + } + else + { + $user['lastip'] = my_inet_ntop($db->unescape_binary($user['lastip'])); + $popup = new PopupMenu("user_last", $lang->options); + $popup->add_item($lang->show_users_regged_with_ip, + "index.php?module=user-users&action=search&results=1&conditions=".urlencode(serialize(array("regip" => $user['lastip'])))); + $popup->add_item($lang->show_users_posted_with_ip, "index.php?module=user-users&results=1&action=search&conditions=".urlencode(serialize(array("postip" => $user['lastip'])))); + $popup->add_item($lang->info_on_ip, "index.php?module=user-users&action=iplookup&ipaddress={$user['lastip']}", "MyBB.popupWindow('index.php?module=user-users&action=iplookup&ipaddress={$user['lastip']}', null, true); return false;"); + $popup->add_item($lang->ban_ip, "index.php?module=config-banning&filter={$user['lastip']}"); + $controls = $popup->fetch(); + } + $table->construct_cell("{$lang->last_known_ip}: ".$user['lastip']); + $table->construct_cell($controls, array('class' => "align_center")); + $table->construct_row(); + + if(empty($user['regip'])) + { + $user['regip'] = $lang->unknown; + $controls = ''; + } + else + { + $user['regip'] = my_inet_ntop($db->unescape_binary($user['regip'])); + $popup = new PopupMenu("user_reg", $lang->options); + $popup->add_item($lang->show_users_regged_with_ip, "index.php?module=user-users&results=1&action=search&conditions=".urlencode(serialize(array("regip" => $user['regip'])))); + $popup->add_item($lang->show_users_posted_with_ip, "index.php?module=user-users&results=1&action=search&conditions=".urlencode(serialize(array("postip" => $user['regip'])))); + $popup->add_item($lang->info_on_ip, "index.php?module=user-users&action=iplookup&ipaddress={$user['regip']}", "MyBB.popupWindow('index.php?module=user-users&action=iplookup&ipaddress={$user['regip']}', null, true); return false;"); + $popup->add_item($lang->ban_ip, "index.php?module=config-banning&filter={$user['regip']}"); + $controls = $popup->fetch(); + } + $table->construct_cell("{$lang->registration_ip}: ".$user['regip']); + $table->construct_cell($controls, array('class' => "align_center")); + $table->construct_row(); + + $counter = 0; + + $query = $db->simple_select("posts", "DISTINCT ipaddress", "uid='{$mybb->input['uid']}'"); + while($ip = $db->fetch_array($query)) + { + ++$counter; + $ip['ipaddress'] = my_inet_ntop($db->unescape_binary($ip['ipaddress'])); + $popup = new PopupMenu("id_{$counter}", $lang->options); + $popup->add_item($lang->show_users_regged_with_ip, "index.php?module=user-users&results=1&action=search&conditions=".urlencode(serialize(array("regip" => $ip['ipaddress'])))); + $popup->add_item($lang->show_users_posted_with_ip, "index.php?module=user-users&results=1&action=search&conditions=".urlencode(serialize(array("postip" => $ip['ipaddress'])))); + $popup->add_item($lang->info_on_ip, "index.php?module=user-users&action=iplookup&ipaddress={$ip['ipaddress']}", "MyBB.popupWindow('index.php?module=user-users&action=iplookup&ipaddress={$ip['ipaddress']}', null, true); return false;"); + $popup->add_item($lang->ban_ip, "index.php?module=config-banning&filter={$ip['ipaddress']}"); + $controls = $popup->fetch(); + + $table->construct_cell($ip['ipaddress']); + $table->construct_cell($controls, array('class' => "align_center")); + $table->construct_row(); + } + + $table->output($lang->ip_address_for." {$user['username']}"); + + $page->output_footer(); +} + +if($mybb->input['action'] == "merge") +{ + $plugins->run_hooks("admin_user_users_merge"); + + if($mybb->request_method == "post") + { + $source_user = get_user_by_username($mybb->input['source_username'], array('fields' => '*')); + if(!$source_user['uid']) + { + $errors[] = $lang->error_invalid_user_source; + } + + $destination_user = get_user_by_username($mybb->input['destination_username'], array('fields' => '*')); + if(!$destination_user['uid']) + { + $errors[] = $lang->error_invalid_user_destination; + } + + // If we're not a super admin and we're merging a source super admin or a destination super admin then dissallow this action + if(!is_super_admin($mybb->user['uid']) && (is_super_admin($source_user['uid']) || is_super_admin($destination_user['uid']))) + { + flash_message($lang->error_no_perms_super_admin, 'error'); + admin_redirect("index.php?module=user-users"); + } + + if($source_user['uid'] == $destination_user['uid']) + { + $errors[] = $lang->error_cannot_merge_same_account; + } + + if(empty($errors)) + { + // Begin to merge the accounts + $uid_update = array( + "uid" => $destination_user['uid'] + ); + $query = $db->simple_select("adminoptions", "uid", "uid='{$destination_user['uid']}'"); + $existing_admin_options = $db->fetch_field($query, "uid"); + + // Only carry over admin options/permissions if we don't already have them + if(!$existing_admin_options) + { + $db->update_query("adminoptions", $uid_update, "uid='{$source_user['uid']}'"); + } + + $db->update_query("adminlog", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("announcements", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("events", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("threadsubscriptions", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("forumsubscriptions", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("joinrequests", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("moderatorlog", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("pollvotes", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("posts", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("privatemessages", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("reportedcontent", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("threadratings", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("threads", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("warnings", $uid_update, "uid='{$source_user['uid']}'"); + $db->update_query("warnings", array("revokedby" => $destination_user['uid']), "revokedby='{$source_user['uid']}'"); + $db->update_query("warnings", array("issuedby" => $destination_user['uid']), "issuedby='{$source_user['uid']}'"); + + // Banning + $db->update_query("banned", array('admin' => $destination_user['uid']), "admin = '{$source_user['uid']}'"); + + // Merging Reputation + // First, let's change all the details over to our new user... + $db->update_query("reputation", array("adduid" => $destination_user['uid']), "adduid = '".$source_user['uid']."'"); + $db->update_query("reputation", array("uid" => $destination_user['uid']), "uid = '".$source_user['uid']."'"); + + // Now that all the repuation is merged, figure out what to do with this user's comments... + $options = array( + "order_by" => "uid", + "order_dir" => "ASC" + ); + + $to_remove = array(); + $query = $db->simple_select("reputation", "*", "adduid = '".$destination_user['uid']."'"); + while($rep = $db->fetch_array($query)) + { + if($rep['pid'] == 0 && $mybb->settings['multirep'] == 0 && $last_result['uid'] == $rep['uid']) + { + // Multiple reputation is disallowed, and this isn't a post, so let's remove this comment + $to_remove[] = $rep['rid']; + } + + // Remove comments or posts liked by "me" + if($last_result['uid'] == $destination_user['uid'] || $rep['uid'] == $destination_user['uid']) + { + if(!in_array($rep['rid'], $to_remove)) + { + $to_remove[] = $rep['rid']; + continue; + } + } + + $last_result = array( + "rid" => $rep['rid'], + "uid" => $rep['uid'] + ); + } + + // Remove any reputations we've selected to remove... + if(!empty($to_remove)) + { + $imp = implode(",", $to_remove); + $db->delete_query("reputation", "rid IN (".$imp.")"); + } + + // Calculate the new reputation for this user... + $query = $db->simple_select("reputation", "SUM(reputation) as total_rep", "uid='{$destination_user['uid']}'"); + $total_reputation = $db->fetch_field($query, "total_rep"); + + $db->update_query("users", array('reputation' => (int)$total_reputation), "uid='{$destination_user['uid']}'"); + + // Calculate warning points + $query = $db->query(" + SELECT SUM(points) as warn_lev + FROM ".TABLE_PREFIX."warnings + WHERE uid='{$source_user['uid']}' AND expired='0' + "); + $original_warn_level = $db->fetch_field($query, "warn_lev"); + + $query = $db->query(" + SELECT SUM(points) as warn_lev + FROM ".TABLE_PREFIX."warnings + WHERE uid='{$destination_user['uid']}' AND expired='0' + "); + $new_warn_level = $db->fetch_field($query, "warn_lev"); + $db->update_query("users", array("warningpoints" => (int)$original_warn_level + $new_warn_level), "uid='{$destination_user['uid']}'"); + + // Additional updates for non-uid fields + $last_poster = array( + "lastposteruid" => $destination_user['uid'], + "lastposter" => $db->escape_string($destination_user['username']) + ); + $db->update_query("forums", $last_poster, "lastposteruid='{$source_user['uid']}'"); + $db->update_query("threads", $last_poster, "lastposteruid='{$source_user['uid']}'"); + $edit_uid = array( + "edituid" => $destination_user['uid'] + ); + $db->update_query("posts", $edit_uid, "edituid='{$source_user['uid']}'"); + + $from_uid = array( + "fromid" => $destination_user['uid'] + ); + $db->update_query("privatemessages", $from_uid, "fromid='{$source_user['uid']}'"); + $to_uid = array( + "toid" => $destination_user['uid'] + ); + $db->update_query("privatemessages", $to_uid, "toid='{$source_user['uid']}'"); + + // Buddy/ignore lists + $destination_buddies = explode(',', $destination_user['buddylist']); + $source_buddies = explode(',', $source_user['buddylist']); + $buddies = array_unique(array_merge($source_buddies, $destination_buddies)); + // Make sure the new buddy list doesn't contain either users + $buddies_array = array_diff($buddies, array($destination_user['uid'], $source_user['uid'])); + + $destination_ignored = explode(',', $destination_user['ignorelist']); + $source_ignored = explode(',', $destination_user['ignorelist']); + $ignored = array_unique(array_merge($source_ignored, $destination_ignored)); + // ... and the same for the new ignore list + $ignored_array = array_diff($ignored, array($destination_user['uid'], $source_user['uid'])); + + // Remove any ignored users from the buddy list + $buddies = array_diff($buddies_array, $ignored_array); + // implode the arrays so we get a nice neat list for each + $buddies = trim(implode(',', $buddies), ','); + $ignored = trim(implode(',', $ignored_array), ','); + + $lists = array( + "buddylist" => $buddies, + "ignorelist" => $ignored + ); + $db->update_query("users", $lists, "uid='{$destination_user['uid']}'"); + + // Set up user handler. + require_once MYBB_ROOT.'inc/datahandlers/user.php'; + $userhandler = new UserDataHandler('delete'); + + // Delete the old user + $userhandler->delete_user($source_user['uid']); + + // Get a list of forums where post count doesn't apply + $fids = array(); + $query = $db->simple_select("forums", "fid", "usepostcounts=0"); + while($fid = $db->fetch_field($query, "fid")) + { + $fids[] = $fid; + } + + $fids_not_in = ''; + if(!empty($fids)) + { + $fids_not_in = "AND fid NOT IN(".implode(',', $fids).")"; + } + + // Update user post count + $query = $db->simple_select("posts", "COUNT(*) AS postnum", "uid='".$destination_user['uid']."' {$fids_not_in}"); + $num = $db->fetch_array($query); + $updated_count = array( + "postnum" => $num['postnum'] + ); + $db->update_query("users", $updated_count, "uid='{$destination_user['uid']}'"); + + // Update user thread count + $query = $db->simple_select("threads", "COUNT(*) AS threadnum", "uid='".$destination_user['uid']."' {$fids_not_in}"); + $num = $db->fetch_array($query); + $updated_count = array( + "threadnum" => $num['threadnum'] + ); + $db->update_query("users", $updated_count, "uid='{$destination_user['uid']}'"); + + // Use the earliest registration date + if($destination_user['regdate'] > $source_user['regdate']) + { + $db->update_query("users", array('regdate' => $source_user['regdate']), "uid='{$destination_user['uid']}'"); + } + + $plugins->run_hooks("admin_user_users_merge_commit"); + + // Log admin action + log_admin_action($source_user['uid'], $source_user['username'], $destination_user['uid'], $destination_user['username']); + + // Redirect! + flash_message("{$source_user['username']} {$lang->success_merged} {$destination_user['username']}", "success"); + admin_redirect("index.php?module=user-users"); + exit; + } + } + + $page->add_breadcrumb_item($lang->merge_users); + $page->output_header($lang->merge_users); + + $page->output_nav_tabs($sub_tabs, 'merge_users'); + + // If we have any error messages, show them + if($errors) + { + $page->output_inline_error($errors); + } + + $form = new Form("index.php?module=user-users&action=merge", "post"); + + $form_container = new FormContainer($lang->merge_users); + $form_container->output_row($lang->source_account." *", $lang->source_account_desc, $form->generate_text_box('source_username', $mybb->input['source_username'], array('id' => 'source_username')), 'source_username'); + $form_container->output_row($lang->destination_account." *", $lang->destination_account_desc, $form->generate_text_box('destination_username', $mybb->input['destination_username'], array('id' => 'destination_username')), 'destination_username'); + $form_container->end(); + + // Autocompletion for usernames + echo ' + + + '; + + $buttons[] = $form->generate_submit_button($lang->merge_user_accounts); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "search") +{ + $plugins->run_hooks("admin_user_users_search"); + + if($mybb->request_method == "post" || $mybb->input['results'] == 1) + { + // Build view options from incoming search options + if($mybb->input['vid']) + { + $query = $db->simple_select("adminviews", "*", "vid='".$mybb->get_input('vid', 1)."'"); + $admin_view = $db->fetch_array($query); + // View does not exist or this view is private and does not belong to the current user + if(!$admin_view['vid'] || ($admin_view['visibility'] == 1 && $admin_view['uid'] != $mybb->user['uid'])) + { + unset($admin_view); + } + } + + if($mybb->input['search_id'] && $admin_session['data']['user_views'][$mybb->input['search_id']]) + { + $admin_view = $admin_session['data']['user_views'][$mybb->input['search_id']]; + unset($admin_view['extra_sql']); + } + else + { + // Don't have a view? Fetch the default + if(!$admin_view['vid']) + { + $default_view = fetch_default_view("user"); + if(!$default_view) + { + $default_view = "0"; + } + $query = $db->simple_select("adminviews", "*", "type='user' AND (vid='{$default_view}' OR uid=0)", array("order_by" => "uid", "order_dir" => "desc")); + $admin_view = $db->fetch_array($query); + } + } + + // Override specific parts of the view + unset($admin_view['vid']); + + if($mybb->input['type']) + { + $admin_view['view_type'] = $mybb->input['type']; + } + + if($mybb->input['conditions']) + { + $admin_view['conditions'] = $mybb->input['conditions']; + } + + if($mybb->input['sortby']) + { + $admin_view['sortby'] = $mybb->input['sortby']; + } + + if($mybb->get_input('perpage', 1)) + { + $admin_view['perpage'] = $mybb->input['perpage']; + } + + if($mybb->input['order']) + { + $admin_view['sortorder'] = $mybb->input['order']; + } + + if($mybb->input['displayas']) + { + $admin_view['view_type'] = $mybb->input['displayas']; + } + + if($mybb->input['profile_fields']) + { + $admin_view['custom_profile_fields'] = $mybb->input['profile_fields']; + } + + $plugins->run_hooks("admin_user_users_search_commit"); + + $results = build_users_view($admin_view); + + if($results) + { + $page->output_header($lang->find_users); + echo ""; + $page->output_nav_tabs($sub_tabs, 'find_users'); + echo $results; + $page->output_footer(); + } + else + { + if($mybb->input['from'] == "home") + { + flash_message($lang->error_no_users_found, 'error'); + admin_redirect("index.php"); + exit; + } + else + { + $errors[] = $lang->error_no_users_found; + } + } + } + + $page->add_breadcrumb_item($lang->find_users); + $page->output_header($lang->find_users); + + $page->output_nav_tabs($sub_tabs, 'find_users'); + + // If we have any error messages, show them + if($errors) + { + $page->output_inline_error($errors); + } + + if(!$mybb->input['displayas']) + { + $mybb->input['displayas'] = "card"; + } + + $form = new Form("index.php?module=user-users&action=search", "post"); + + user_search_conditions($mybb->input, $form); + + $form_container = new FormContainer($lang->display_options); + $sort_directions = array( + "asc" => $lang->ascending, + "desc" => $lang->descending + ); + $form_container->output_row($lang->sort_results_by, "", $form->generate_select_box('sortby', $sort_options, $mybb->input['sortby'], array('id' => 'sortby'))." {$lang->in} ".$form->generate_select_box('order', $sort_directions, $mybb->input['order'], array('id' => 'order')), 'sortby'); + $form_container->output_row($lang->results_per_page, "", $form->generate_numeric_field('perpage', $mybb->input['perpage'], array('id' => 'perpage')), 'perpage'); + $form_container->output_row($lang->display_results_as, "", $form->generate_radio_button('displayas', 'table', $lang->table, array('checked' => ($mybb->input['displayas'] != "card" ? true : false)))."
".$form->generate_radio_button('displayas', 'card', $lang->business_card, array('checked' => ($mybb->input['displayas'] == "card" ? true : false)))); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->find_users); + $form->output_submit_wrapper($buttons); + $form->end(); + + $page->output_footer(); +} + +if($mybb->input['action'] == "inline_edit") +{ + $plugins->run_hooks("admin_user_users_inline"); + + if($mybb->input['vid'] || $mybb->cookies['acp_view']) + { + // We have a custom view + if(!$mybb->cookies['acp_view']) + { + // Set a cookie + my_setcookie("acp_view", $mybb->input['vid'], 60); + } + elseif($mybb->cookies['acp_view']) + { + // We already have a cookie, so let's use it... + $mybb->input['vid'] = $mybb->cookies['acp_view']; + } + + $vid_url = "&vid=".$mybb->input['vid']; + } + + // First, collect the user IDs that we're performing the moderation on + $ids = explode("|", $mybb->cookies['inlinemod_useracp']); + foreach($ids as $id) + { + if($id != '') + { + $selected[] = (int)$id; + } + } + + // If there isn't anything to select, then output an error + if(!is_array($selected)) + { + if($mybb->input['inline_action'] != "multilift" && $mybb->request_method != "post") + { + $errors[] = $lang->error_inline_no_users_selected; + } + } + + if($errors) + { + // Don't show views, but show the user list if there's errors + $inline = true; + $mybb->input['action'] = ''; + } + else + { + // Let's continue! + // Verify incoming POST request + if(!verify_post_check($mybb->input['my_post_key'])) + { + flash_message($lang->invalid_post_verify_key2, 'error'); + admin_redirect("index.php?module=user-user"); + } + $sub_tabs['manage_users'] = array( + "title" => $lang->manage_users, + "link" => "./", + "description" => $lang->manage_users_desc + ); + $page->add_breadcrumb_item($lang->manage_users); + + if(!is_array($selected)) + { + // Not selected any users, show error + flash_message($lang->error_inline_no_users_selected, 'error'); + admin_redirect("index.php?module=user-users".$vid_url); + } + + switch($mybb->input['inline_action']) + { + case 'multiactivate': + // Run through the activating users, so that users already registered (but have been selected) aren't affected + if(is_array($selected)) + { + $sql_array = implode(",", $selected); + $query = $db->simple_select("users", "uid", "usergroup = '5' AND uid IN (".$sql_array.")"); + while($user = $db->fetch_array($query)) + { + $to_update[] = $user['uid']; + } + } + + if(is_array($to_update)) + { + $sql_array = implode(",", $to_update); + $db->write_query("UPDATE ".TABLE_PREFIX."users SET usergroup = '2' WHERE uid IN (".$sql_array.")"); + + $cache->update_awaitingactivation(); + + // Action complete, grab stats and show success message - redirect user + $to_update_count = count($to_update); + $lang->inline_activated = $lang->sprintf($lang->inline_activated, my_number_format($to_update_count)); + + if($to_update_count != count($selected)) + { + // The update count is different to how many we selected! + $not_updated_count = count($selected) - $to_update_count; + $lang->inline_activated_more = $lang->sprintf($lang->inline_activated_more, my_number_format($not_updated_count)); + $lang->inline_activated = $lang->inline_activated."
".$lang->inline_activated_more; // Add these stats to the message + } + + $mybb->input['action'] = "inline_activated"; // Force a change to the action so we can add it to the adminlog + log_admin_action($to_update_count); // Add to adminlog + my_unsetcookie("inlinemod_useracp"); // Unset the cookie, so that the users aren't still selected when we're redirected + + flash_message($lang->inline_activated, 'success'); + admin_redirect("index.php?module=user-users".$vid_url); + } + else + { + // Nothing was updated, show an error + flash_message($lang->inline_activated_failed, 'error'); + admin_redirect("index.php?module=user-users".$vid_url); + } + break; + case 'multilift': + // Get the users that are banned, and check that they have been selected + if($mybb->input['no']) + { + admin_redirect("index.php?module=user-users".$vid_url); // User clicked on 'No' + } + + if($mybb->request_method == "post") + { + $sql_array = implode(",", $selected); + $query = $db->simple_select("banned", "*", "uid IN (".$sql_array.")"); + $to_be_unbanned = $db->num_rows($query); + while($ban = $db->fetch_array($query)) + { + $updated_group = array( + "usergroup" => $ban['oldgroup'], + "additionalgroups" => $ban['oldadditionalgroups'], + "displaygroup" => $ban['olddisplaygroup'] + ); + $db->update_query("users", $updated_group, "uid = '".$ban['uid']."'"); + $db->delete_query("banned", "uid = '".$ban['uid']."'"); + } + + $cache->update_banned(); + $cache->update_moderators(); + + $mybb->input['action'] = "inline_lift"; + log_admin_action($to_be_unbanned); + my_unsetcookie("inlinemod_useracp"); + + $lang->success_ban_lifted = $lang->sprintf($lang->success_ban_lifted, my_number_format($to_be_unbanned)); + flash_message($lang->success_ban_lifted, 'success'); + admin_redirect("index.php?module=user-users".$vid_url); + } + else + { + $page->output_confirm_action("index.php?module=user-users&action=inline_edit&inline_action=multilift", $lang->confirm_multilift); + } + + break; + case 'multiban': + if($mybb->input['processed'] == 1) + { + // We've posted ban information! + // Build an array of users to ban, =D + $sql_array = implode(",", $selected); + // Build a cache array for this users that have been banned already + $query = $db->simple_select("banned", "uid", "uid IN (".$sql_array.")"); + while($user = $db->fetch_array($query)) + { + $bannedcache[] = "u_".$user['uid']; + } + + // Collect the users + $query = $db->simple_select("users", "uid, username, usergroup, additionalgroups, displaygroup", "uid IN (".$sql_array.")"); + + if($mybb->input['bantime'] == '---') + { + $lifted = 0; + } + else + { + $lifted = ban_date2timestamp($mybb->input['bantime']); + } + + $reason = my_substr($mybb->input['reason'], 0, 255); + + $banned_count = 0; + while($user = $db->fetch_array($query)) + { + if($user['uid'] == $mybb->user['uid'] || is_super_admin($user['uid'])) + { + // We remove ourselves and Super Admins from the mix + continue; + } + + if(is_array($bannedcache) && in_array("u_".$user['uid'], $bannedcache)) + { + // User already has a ban, update it! + $update_array = array( + "admin" => (int)$mybb->user['uid'], + "dateline" => TIME_NOW, + "bantime" => $db->escape_string($mybb->input['bantime']), + "lifted" => $db->escape_string($lifted), + "reason" => $db->escape_string($reason) + ); + $db->update_query("banned", $update_array, "uid = '".$user['uid']."'"); + } + else + { + // Not currently banned - insert the ban + $insert_array = array( + 'uid' => $user['uid'], + 'gid' => (int)$mybb->input['usergroup'], + 'oldgroup' => $user['usergroup'], + 'oldadditionalgroups' => $user['additionalgroups'], + 'olddisplaygroup' => $user['displaygroup'], + 'admin' => (int)$mybb->user['uid'], + 'dateline' => TIME_NOW, + 'bantime' => $db->escape_string($mybb->input['bantime']), + 'lifted' => $db->escape_string($lifted), + 'reason' => $db->escape_string($reason) + ); + $db->insert_query('banned', $insert_array); + } + + // Moved the user to the 'Banned' Group + $update_array = array( + 'usergroup' => 7, + 'displaygroup' => 0, + 'additionalgroups' => '', + ); + $db->update_query('users', $update_array, "uid = '{$user['uid']}'"); + + $db->delete_query("forumsubscriptions", "uid = '{$user['uid']}'"); + $db->delete_query("threadsubscriptions", "uid = '{$user['uid']}'"); + + $cache->update_banned(); + ++$banned_count; + } + $mybb->input['action'] = "inline_banned"; + log_admin_action($banned_count, $lifted); + my_unsetcookie("inlinemod_useracp"); // Remove the cookie of selected users as we've finished with them + + $lang->users_banned = $lang->sprintf($lang->users_banned, $banned_count); + flash_message($lang->users_banned, 'success'); + admin_redirect("index.php?module=user-users".$vid_url); + } + + $page->output_header($lang->manage_users); + $page->output_nav_tabs($sub_tabs, 'manage_users'); + + // Provide the user with a warning of what they're about to do + $table = new Table; + $lang->mass_ban_info = $lang->sprintf($lang->mass_ban_info, count($selected)); + $table->construct_cell($lang->mass_ban_info); + $table->construct_row(); + $table->output($lang->important); + + // If there's any errors, display inline + if($errors) + { + $page->output_inline_error($errors); + } + + $form = new Form("index.php?module=user-users", "post"); + echo $form->generate_hidden_field('action', 'inline_edit'); + echo $form->generate_hidden_field('inline_action', 'multiban'); + echo $form->generate_hidden_field('processed', '1'); + + $form_container = new FormContainer(''.$lang->mass_ban); + $form_container->output_row($lang->ban_reason, "", $form->generate_text_area('reason', $mybb->input['reason'], array('id' => 'reason', 'maxlength' => '255')), 'reason'); + $ban_times = fetch_ban_times(); + foreach($ban_times as $time => $period) + { + if($time != '---') + { + $friendly_time = my_date("D, jS M Y @ g:ia", ban_date2timestamp($time)); + $period = "{$period} ({$friendly_time})"; + } + $length_list[$time] = $period; + } + $form_container->output_row($lang->ban_time, "", $form->generate_select_box('bantime', $length_list, $mybb->input['bantime'], array('id' => 'bantime')), 'bantime'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->ban_users); + $form->output_submit_wrapper($buttons); + $form->end(); + $page->output_footer(); + break; + case 'multidelete': + if($mybb->input['no']) + { + admin_redirect("index.php?module=user-users".$vid_url); // User clicked on 'No + } + else + { + if($mybb->input['processed'] == 1) + { + // Set up user handler. + require_once MYBB_ROOT.'inc/datahandlers/user.php'; + $userhandler = new UserDataHandler('delete'); + + // Delete users + $deleted = $userhandler->delete_user($selected); + $to_be_deleted = $deleted['deleted_users']; // Get the correct number of deleted users + + // Update forum stats, remove the cookie and redirect the user + my_unsetcookie("inlinemod_useracp"); + $mybb->input['action'] = "inline_delete"; + log_admin_action($to_be_deleted); + + $lang->users_deleted = $lang->sprintf($lang->users_deleted, $to_be_deleted); + flash_message($lang->users_deleted, 'success'); + admin_redirect("index.php?module=user-users".$vid_url); + } + + $to_be_deleted = count($selected); + $lang->confirm_multidelete = $lang->sprintf($lang->confirm_multidelete, my_number_format($to_be_deleted)); + $page->output_confirm_action("index.php?module=user-users&action=inline_edit&inline_action=multidelete&my_post_key={$mybb->post_code}&processed=1", $lang->confirm_multidelete); + } + break; + case 'multiprune': + if($mybb->input['processed'] == 1) + { + if(($mybb->input['day'] || $mybb->input['month'] || $mybb->input['year']) && $mybb->input['set']) + { + $errors[] = $lang->multi_selected_dates; + } + + $day = (int)$mybb->input['day']; + $month = (int)$mybb->input['month']; + $year = (int)$mybb->input['year']; + + // Selected a date - check if the date the user entered is valid + if($mybb->input['day'] || $mybb->input['month'] || $mybb->input['year']) + { + // Is the date sort of valid? + if($day < 1 || $day > 31 || $month < 1 || $month > 12 || ($month == 2 && $day > 29)) + { + $errors[] = $lang->incorrect_date; + } + + // Check the month + $months = get_bdays($year); + if($day > $months[$month]-1) + { + $errors[] = $lang->incorrect_date; + } + + // Check the year + if($year != 0 && ($year < (date("Y")-100)) || $year > date("Y")) + { + $errors[] = $lang->incorrect_date; + } + + if(!$errors) + { + // No errors, so let's continue and set the date to delete from + $date = mktime(date('H'), date('i'), date('s'), $month, $day, $year); // Generate a unix time stamp + } + } + elseif($mybb->input['set'] > 0) + { + // Set options + // For this purpose, 1 month = 31 days + $base_time = 24 * 60 * 60; + + switch($mybb->input['set']) + { + case '1': + $threshold = $base_time * 31; // 1 month = 31 days, in the standard terms + break; + case '2': + $threshold = $base_time * 93; // 3 months = 31 days * 3 + break; + case '3': + $threshold = $base_time * 183; // 6 months = 365 days / 2 + break; + case '4': + $threshold = $base_time * 365; // 1 year = 365 days + break; + case '5': + $threshold = $base_time * 548; // 18 months = 365 + 183 + break; + case '6': + $threshold = $base_time * 730; // 2 years = 365 * 2 + break; + } + + if(!$threshold) + { + // An option was entered that isn't in the dropdown box + $errors[] = $lang->no_set_option; + } + else + { + $date = TIME_NOW - $threshold; + } + } + else + { + $errors[] = $lang->no_prune_option; + } + + if(!$errors) + { + $sql_array = implode(",", $selected); + $prune_array = array(); + $query = $db->simple_select("users", "uid", "uid IN (".$sql_array.")"); + while($user = $db->fetch_array($query)) + { + // Protect Super Admins + if(is_super_admin($user['uid']) && !is_super_admin($mybb->user['uid'])) + { + continue; + } + + $return_array = delete_user_posts($user['uid'], $date); // Delete user posts, and grab a list of threads to delete + if($return_array && is_array($return_array)) + { + $prune_array = array_merge_recursive($prune_array, $return_array); + } + } + + // No posts were found for the user, return error + if(!is_array($prune_array) || count($prune_array) == 0) + { + flash_message($lang->prune_fail, 'error'); + admin_redirect("index.php?module=user-users".$vid_url); + } + + // Require the rebuild functions + require_once MYBB_ROOT.'/inc/functions.php'; + require_once MYBB_ROOT.'/inc/functions_rebuild.php'; + + // We've finished deleting user's posts, so let's delete the threads + if(is_array($prune_array['to_delete']) && count($prune_array['to_delete']) > 0) + { + foreach($prune_array['to_delete'] as $tid) + { + $db->delete_query("threads", "tid='$tid'"); + $db->delete_query("threads", "closed='moved|$tid'"); + $db->delete_query("threadsubscriptions", "tid='$tid'"); + $db->delete_query("polls", "tid='$tid'"); + $db->delete_query("threadsread", "tid='$tid'"); + $db->delete_query("threadratings", "tid='$tid'"); + } + } + + // After deleting threads, rebuild the thread counters for the affected threads + if(is_array($prune_array['thread_update']) && count($prune_array['thread_update']) > 0) + { + $sql_array = implode(",", $prune_array['thread_update']); + $query = $db->simple_select("threads", "tid", "tid IN (".$sql_array.")", array('order_by' => 'tid', 'order_dir' => 'asc')); + while($thread = $db->fetch_array($query)) + { + rebuild_thread_counters($thread['tid']); + } + } + + // After updating thread counters, update the affected forum counters + if(is_array($prune_array['forum_update']) && count($prune_array['forum_update']) > 0) + { + $sql_array = implode(",", $prune_array['forum_update']); + $query = $db->simple_select("forums", "fid", "fid IN (".$sql_array.")", array('order_by' => 'fid', 'order_dir' => 'asc')); + while($forum = $db->fetch_array($query)) + { + // Because we have a recursive array merge, check to see if there isn't a duplicated forum to update + if($looped_forum == $forum['fid']) + { + continue; + } + $looped_forum = $forum['fid']; + rebuild_forum_counters($forum['fid']); + } + } + + //log_admin_action(); + my_unsetcookie("inlinemod_useracp"); // We've got our users, remove the cookie + flash_message($lang->prune_complete, 'success'); + admin_redirect("index.php?module=user-users".$vid_url); + } + } + + $page->output_header($lang->manage_users); + $page->output_nav_tabs($sub_tabs, 'manage_users'); + + // Display a table warning + $table = new Table; + $lang->mass_prune_info = $lang->sprintf($lang->mass_prune_info, count($selected)); + $table->construct_cell($lang->mass_prune_info); + $table->construct_row(); + $table->output($lang->important); + + if($errors) + { + $page->output_inline_error($errors); + } + + // Display the prune options + $form = new Form("index.php?module=user-users", "post"); + echo $form->generate_hidden_field('action', 'inline_edit'); + echo $form->generate_hidden_field('inline_action', 'multiprune'); + echo $form->generate_hidden_field('processed', '1'); + + $form_container = new FormContainer($lang->mass_prune_posts); + + // Generate a list of days (1 - 31) + $day_options = array(); + $day_options[] = " "; + for($i = 1; $i <= 31; ++$i) + { + $day_options[] = $i; + } + + // Generate a list of months (1 - 12) + $month_options = array(); + $month_options[] = " "; + for($i = 1; $i <= 12; ++$i) + { + $string = "month_{$i}"; + $month_options[] = $lang->$string; + } + $date_box = $form->generate_select_box('day', $day_options, $mybb->input['day']); + $month_box = $form->generate_select_box('month', $month_options, $mybb->input['month']); + $year_box = $form->generate_numeric_field('year', $mybb->input['year'], array('id' => 'year', 'style' => 'width: 50px;')); + + $prune_select = $date_box.$month_box.$year_box; + $form_container->output_row($lang->manual_date, "", $prune_select, 'date'); + + // Generate the set date box + $set_options = array(); + $set_options[] = $lang->set_an_option; + for($i = 1; $i <= 6; ++$i) + { + $string = "option_{$i}"; + $set_options[] = $lang->$string; + } + + $form_container->output_row($lang->relative_date, "", $lang->delete_posts." ".$form->generate_select_box('set', $set_options, $mybb->input['set']), 'set'); + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->prune_posts); + $form->output_submit_wrapper($buttons); + $form->end(); + $page->output_footer(); + break; + case 'multiusergroup': + if($mybb->input['processed'] == 1) + { + // Determine additional usergroups + if(is_array($mybb->input['additionalgroups'])) + { + foreach($mybb->input['additionalgroups'] as $key => $gid) + { + if($gid == $mybb->input['usergroup']) + { + unset($mybb->input['additionalgroups'][$key]); + } + } + + $additionalgroups = implode(",", array_map('intval', $mybb->input['additionalgroups'])); + } + else + { + $additionalgroups = ''; + } + + // Create an update array + $update_array = array( + "usergroup" => (int)$mybb->input['usergroup'], + "additionalgroups" => $additionalgroups, + "displaygroup" => (int)$mybb->input['displaygroup'] + ); + + // Do the usergroup update for all those selected + // If the a selected user is a super admin, don't update that user + foreach($selected as $user) + { + if(!is_super_admin($user)) + { + $users_to_update[] = $user; + } + } + + $to_update_count = count($users_to_update); + if($to_update_count > 0 && is_array($users_to_update)) + { + // Update the users in the database + $sql = implode(",", $users_to_update); + $db->update_query("users", $update_array, "uid IN (".$sql.")"); + + // Redirect the admin... + $mybb->input['action'] = "inline_usergroup"; + log_admin_action($to_update_count); + my_unsetcookie("inlinemod_useracp"); + flash_message($lang->success_mass_usergroups, 'success'); + admin_redirect("index.php?module=user-users".$vid_url); + } + else + { + // They tried to edit super admins! Uh-oh! + $errors[] = $lang->no_usergroup_changed; + } + } + + $page->output_header($lang->manage_users); + $page->output_nav_tabs($sub_tabs, 'manage_users'); + + // Display a table warning + $table = new Table; + $lang->usergroup_info = $lang->sprintf($lang->usergroup_info, count($selected)); + $table->construct_cell($lang->usergroup_info); + $table->construct_row(); + $table->output($lang->important); + + if($errors) + { + $page->output_inline_error($errors); + } + + // Display the usergroup options + $form = new Form("index.php?module=user-users", "post"); + echo $form->generate_hidden_field('action', 'inline_edit'); + echo $form->generate_hidden_field('inline_action', 'multiusergroup'); + echo $form->generate_hidden_field('processed', '1'); + + $form_container = new FormContainer($lang->mass_usergroups); + + // Usergroups + $display_group_options[0] = $lang->use_primary_user_group; + $options = array(); + $query = $db->simple_select("usergroups", "gid, title", "gid != '1'", array('order_by' => 'title')); + while($usergroup = $db->fetch_array($query)) + { + $options[$usergroup['gid']] = $usergroup['title']; + $display_group_options[$usergroup['gid']] = $usergroup['title']; + } + + if(!is_array($mybb->input['additionalgroups'])) + { + $mybb->input['additionalgroups'] = explode(',', $mybb->input['additionalgroups']); + } + + $form_container->output_row($lang->primary_user_group, "", $form->generate_select_box('usergroup', $options, $mybb->input['usergroup'], array('id' => 'usergroup')), 'usergroup'); + $form_container->output_row($lang->additional_user_groups, $lang->additional_user_groups_desc, $form->generate_select_box('additionalgroups[]', $options, $mybb->input['additionalgroups'], array('id' => 'additionalgroups', 'multiple' => true, 'size' => 5)), 'additionalgroups'); + $form_container->output_row($lang->display_user_group, "", $form->generate_select_box('displaygroup', $display_group_options, $mybb->input['displaygroup'], array('id' => 'displaygroup')), 'displaygroup'); + + $form_container->end(); + + $buttons[] = $form->generate_submit_button($lang->alter_usergroups); + $form->output_submit_wrapper($buttons); + $form->end(); + $page->output_footer(); + break; + } + } +} + +if(!$mybb->input['action']) +{ + $plugins->run_hooks("admin_user_users_start"); + + $page->output_header($lang->browse_users); + echo ""; + + $page->output_nav_tabs($sub_tabs, 'browse_users'); + + if(isset($mybb->input['search_id']) && $admin_session['data']['user_views'][$mybb->input['search_id']]) + { + $admin_view = $admin_session['data']['user_views'][$mybb->input['search_id']]; + unset($admin_view['extra_sql']); + } + else + { + // Showing a specific view + if(isset($mybb->input['vid'])) + { + $query = $db->simple_select("adminviews", "*", "vid='".$mybb->get_input('vid', 1)."'"); + $admin_view = $db->fetch_array($query); + // View does not exist or this view is private and does not belong to the current user + if(!$admin_view['vid'] || ($admin_view['visibility'] == 1 && $admin_view['uid'] != $mybb->user['uid'])) + { + unset($admin_view); + } + } + + // Don't have a view? Fetch the default + if(!isset($admin_view)) + { + $default_view = fetch_default_view("user"); + if(!$default_view) + { + $default_view = "0"; + } + $query = $db->simple_select("adminviews", "*", "type='user' AND (vid='{$default_view}' OR uid=0)", array("order_by" => "uid", "order_dir" => "desc")); + $admin_view = $db->fetch_array($query); + } + } + + // Fetch a list of all of the views for this user + $popup = new PopupMenu("views", $lang->views); + + $query = $db->simple_select("adminviews", "*", "type='user' AND (visibility=2 OR uid={$mybb->user['uid']})", array("order_by" => "title")); + while($view = $db->fetch_array($query)) + { + $popup->add_item(htmlspecialchars_uni($view['title']), "index.php?module=user-users&vid={$view['vid']}"); + } + $popup->add_item("{$lang->manage_views}", "index.php?module=user-users&action=views"); + $admin_view['popup'] = $popup->fetch(); + + if(isset($mybb->input['type'])) + { + $admin_view['view_type'] = $mybb->input['type']; + } + + $results = build_users_view($admin_view); + + if(!$results) + { + // If we came from the home page and clicked on the "Activate Users" link, send them back to here + if($admin_session['data']['from'] == "home") + { + flash_message($admin_session['data']['flash_message2']['message'], $admin_session['data']['flash_message2']['type']); + update_admin_session('flash_message2', ''); + update_admin_session('from', ''); + admin_redirect("index.php"); + exit; + } + else + { + $errors[] = $lang->error_no_users_found; + } + } + + // If we have any error messages, show them + if($errors) + { + if($inline != true) + { + echo "
{$admin_view['popup']}

\n"; + } + $page->output_inline_error($errors); + } + + echo $results; + + $page->output_footer(); +} + +function build_users_view($view) +{ + global $mybb, $db, $cache, $lang, $user_view_fields, $page; + + $view_title = ''; + if($view['title']) + { + $title_string = "view_title_{$view['vid']}"; + + if($lang->$title_string) + { + $view['title'] = $lang->$title_string; + } + + $view_title .= " (".htmlspecialchars_uni($view['title']).")"; + } + + // Build the URL to this view + if(!isset($view['url'])) + { + $view['url'] = "index.php?module=user-users"; + } + if(!is_array($view['conditions'])) + { + $view['conditions'] = my_unserialize($view['conditions']); + } + if(!is_array($view['fields'])) + { + $view['fields'] = my_unserialize($view['fields']); + } + if(!is_array($view['custom_profile_fields'])) + { + $view['custom_profile_fields'] = my_unserialize($view['custom_profile_fields']); + } + if(isset($mybb->input['username'])) + { + $view['conditions']['username'] = $mybb->input['username']; + } + if($view['vid']) + { + $view['url'] .= "&vid={$view['vid']}"; + } + else + { + // If this is a custom view we need to save everything ready to pass it on from page to page + global $admin_session; + if(!$mybb->input['search_id']) + { + $search_id = md5(random_str()); + $admin_session['data']['user_views'][$search_id] = $view; + update_admin_session('user_views', $admin_session['data']['user_views']); + $mybb->input['search_id'] = $search_id; + } + $view['url'] .= "&search_id=".htmlspecialchars_uni($mybb->input['search_id']); + } + + if(isset($mybb->input['username'])) + { + $view['url'] .= "&username=".urlencode(htmlspecialchars_uni($mybb->input['username'])); + } + + if(!isset($admin_session['data']['last_users_view']) || $admin_session['data']['last_users_view'] != str_replace("&", "&", $view['url'])) + { + update_admin_session('last_users_url', str_replace("&", "&", $view['url'])); + } + + if(isset($view['conditions']['referrer'])){ + $view['url'] .= "&action=referrers&uid=".htmlspecialchars_uni($view['conditions']['referrer']); + } + + // Do we not have any views? + if(empty($view)) + { + return false; + } + + $table = new Table; + + // Build header for table based view + if($view['view_type'] != "card") + { + foreach($view['fields'] as $field) + { + if(!$user_view_fields[$field]) + { + continue; + } + $view_field = $user_view_fields[$field]; + $field_options = array(); + if($view_field['width']) + { + $field_options['width'] = $view_field['width']; + } + if($view_field['align']) + { + $field_options['class'] = "align_".$view_field['align']; + } + $table->construct_header($view_field['title'], $field_options); + } + $table->construct_header(""); // Create a header for the "select" boxes + } + + $search_sql = '1=1'; + + // Build the search SQL for users + + // List of valid LIKE search fields + $user_like_fields = array("username", "email", "website", "icq", "aim", "yahoo", "skype", "google", "signature", "usertitle"); + foreach($user_like_fields as $search_field) + { + if(!empty($view['conditions'][$search_field]) && !$view['conditions'][$search_field.'_blank']) + { + $search_sql .= " AND u.{$search_field} LIKE '%".$db->escape_string_like($view['conditions'][$search_field])."%'"; + } + else if(!empty($view['conditions'][$search_field.'_blank'])) + { + $search_sql .= " AND u.{$search_field} != ''"; + } + } + + // EXACT matching fields + $user_exact_fields = array("referrer"); + foreach($user_exact_fields as $search_field) + { + if(!empty($view['conditions'][$search_field])) + { + $search_sql .= " AND u.{$search_field}='".$db->escape_string($view['conditions'][$search_field])."'"; + } + } + + // LESS THAN or GREATER THAN + $direction_fields = array("postnum", "threadnum"); + foreach($direction_fields as $search_field) + { + $direction_field = $search_field."_dir"; + if(isset($view['conditions'][$search_field]) && ($view['conditions'][$search_field] || $view['conditions'][$search_field] === '0') && $view['conditions'][$direction_field]) + { + switch($view['conditions'][$direction_field]) + { + case "greater_than": + $direction = ">"; + break; + case "less_than": + $direction = "<"; + break; + default: + $direction = "="; + } + $search_sql .= " AND u.{$search_field}{$direction}'".$db->escape_string($view['conditions'][$search_field])."'"; + } + } + + // Registration searching + $reg_fields = array("regdate"); + foreach($reg_fields as $search_field) + { + if(!empty($view['conditions'][$search_field]) && (int)$view['conditions'][$search_field]) + { + $threshold = TIME_NOW - ((int)$view['conditions'][$search_field] * 24 * 60 * 60); + + $search_sql .= " AND u.{$search_field} >= '{$threshold}'"; + } + } + + // IP searching + $ip_fields = array("regip", "lastip"); + foreach($ip_fields as $search_field) + { + if(!empty($view['conditions'][$search_field])) + { + $ip_range = fetch_ip_range($view['conditions'][$search_field]); + if(!is_array($ip_range)) + { + $ip_sql = "{$search_field}=".$db->escape_binary($ip_range); + } + else + { + $ip_sql = "{$search_field} BETWEEN ".$db->escape_binary($ip_range[0])." AND ".$db->escape_binary($ip_range[1]); + } + $search_sql .= " AND {$ip_sql}"; + } + } + + // Post IP searching + if(!empty($view['conditions']['postip'])) + { + $ip_range = fetch_ip_range($view['conditions']['postip']); + if(!is_array($ip_range)) + { + $ip_sql = "ipaddress=".$db->escape_binary($ip_range); + } + else + { + $ip_sql = "ipaddress BETWEEN ".$db->escape_binary($ip_range[0])." AND ".$db->escape_binary($ip_range[1]); + } + $ip_uids = array(0); + $query = $db->simple_select("posts", "uid", $ip_sql); + while($uid = $db->fetch_field($query, "uid")) + { + $ip_uids[] = $uid; + } + $search_sql .= " AND u.uid IN(".implode(',', $ip_uids).")"; + unset($ip_uids); + } + + // Custom Profile Field searching + if($view['custom_profile_fields']) + { + $userfield_sql = '1=1'; + foreach($view['custom_profile_fields'] as $column => $input) + { + if(is_array($input)) + { + foreach($input as $value => $text) + { + if($value == $column) + { + $value = $text; + } + + if($value == $lang->na) + { + continue; + } + + if(strpos($column, '_blank') !== false) + { + $column = str_replace('_blank', '', $column); + $userfield_sql .= ' AND '.$db->escape_string($column)." != ''"; + } + else + { + $userfield_sql .= ' AND '.$db->escape_string($column)."='".$db->escape_string($value)."'"; + } + } + } + else if(!empty($input)) + { + if($input == $lang->na) + { + continue; + } + + if(strpos($column, '_blank') !== false) + { + $column = str_replace('_blank', '', $column); + $userfield_sql .= ' AND '.$db->escape_string($column)." != ''"; + } + else + { + $userfield_sql .= ' AND '.$db->escape_string($column)." LIKE '%".$db->escape_string($input)."%'"; + } + } + } + + if($userfield_sql != '1=1') + { + $userfield_uids = array(0); + $query = $db->simple_select("userfields", "ufid", $userfield_sql); + while($userfield = $db->fetch_array($query)) + { + $userfield_uids[] = $userfield['ufid']; + } + $search_sql .= " AND u.uid IN(".implode(',', $userfield_uids).")"; + unset($userfield_uids); + } + } + + // Usergroup based searching + if(isset($view['conditions']['usergroup'])) + { + if(!is_array($view['conditions']['usergroup'])) + { + $view['conditions']['usergroup'] = array($view['conditions']['usergroup']); + } + + foreach($view['conditions']['usergroup'] as $usergroup) + { + $usergroup = (int)$usergroup; + + if(!$usergroup) + { + continue; + } + + $additional_sql = ''; + + switch($db->type) + { + case "pgsql": + case "sqlite": + $additional_sql .= " OR ','||additionalgroups||',' LIKE '%,{$usergroup},%'"; + break; + default: + $additional_sql .= "OR CONCAT(',',additionalgroups,',') LIKE '%,{$usergroup},%'"; + } + } + + $search_sql .= " AND (u.usergroup IN (".implode(",", array_map('intval', $view['conditions']['usergroup'])).") {$additional_sql})"; + } + + // COPPA users only? + if(isset($view['conditions']['coppa'])) + { + $search_sql .= " AND u.coppauser=1 AND u.usergroup=5"; + } + + // Extra SQL? + if(isset($view['extra_sql'])) + { + $search_sql .= $view['extra_sql']; + } + + // Lets fetch out how many results we have + $query = $db->query(" + SELECT COUNT(u.uid) AS num_results + FROM ".TABLE_PREFIX."users u + WHERE {$search_sql} + "); + $num_results = $db->fetch_field($query, "num_results"); + + // No matching results then return false + if(!$num_results) + { + return false; + } + // Generate the list of results + else + { + if(!$view['perpage']) + { + $view['perpage'] = 20; + } + $view['perpage'] = (int)$view['perpage']; + + // Establish which page we're viewing and the starting index for querying + if(!isset($mybb->input['page'])) + { + $mybb->input['page'] = 1; + } + else + { + $mybb->input['page'] = $mybb->get_input('page', 1); + } + + if($mybb->input['page']) + { + $start = ($mybb->input['page'] - 1) * $view['perpage']; + } + else + { + $start = 0; + $mybb->input['page'] = 1; + } + + $from_bit = ""; + if(isset($mybb->input['from']) && $mybb->input['from'] == "home") + { + $from_bit = "&from=home"; + } + + switch($view['sortby']) + { + case "regdate": + case "lastactive": + case "postnum": + case "reputation": + $view['sortby'] = $db->escape_string($view['sortby']); + break; + case "numposts": + $view['sortby'] = "postnum"; + break; + case "numthreads": + $view['sortby'] = "threadnum"; + break; + case "warninglevel": + $view['sortby'] = "warningpoints"; + break; + default: + $view['sortby'] = "username"; + } + + if($view['sortorder'] != "desc") + { + $view['sortorder'] = "asc"; + } + + $usergroups = $cache->read("usergroups"); + + // Fetch matching users + $query = $db->query(" + SELECT u.* + FROM ".TABLE_PREFIX."users u + WHERE {$search_sql} + ORDER BY {$view['sortby']} {$view['sortorder']} + LIMIT {$start}, {$view['perpage']} + "); + $users = ''; + while($user = $db->fetch_array($query)) + { + $comma = $groups_list = ''; + $user['view']['username'] = "".format_name($user['username'], $user['usergroup'], $user['displaygroup']).""; + $user['view']['usergroup'] = $usergroups[$user['usergroup']]['title']; + if($user['additionalgroups']) + { + $additional_groups = explode(",", $user['additionalgroups']); + + foreach($additional_groups as $group) + { + $groups_list .= "{$comma}{$usergroups[$group]['title']}"; + $comma = $lang->comma; + } + } + if(!$groups_list) + { + $groups_list = $lang->none; + } + $user['view']['additionalgroups'] = "{$groups_list}"; + $user['view']['email'] = "".htmlspecialchars_uni($user['email']).""; + $user['view']['regdate'] = my_date('relative', $user['regdate']); + $user['view']['lastactive'] = my_date('relative', $user['lastactive']); + + // Build popup menu + $popup = new PopupMenu("user_{$user['uid']}", $lang->options); + $popup->add_item($lang->view_profile, $mybb->settings['bburl'].'/'.get_profile_link($user['uid'])); + $popup->add_item($lang->edit_profile_and_settings, "index.php?module=user-users&action=edit&uid={$user['uid']}"); + + // Banning options... is this user banned? + if($usergroups[$user['usergroup']]['isbannedgroup'] == 1) + { + // Yes, so do we want to edit the ban or pardon his crime? + $popup->add_item($lang->edit_ban, "index.php?module=user-banning&uid={$user['uid']}#username"); + $popup->add_item($lang->lift_ban, "index.php?module=user-banning&action=lift&uid={$user['uid']}&my_post_key={$mybb->post_code}"); + } + else + { + // Not banned... but soon maybe! + $popup->add_item($lang->ban_user, "index.php?module=user-banning&uid={$user['uid']}#username"); + } + + if($user['usergroup'] == 5) + { + if($user['coppauser']) + { + $popup->add_item($lang->approve_coppa_user, "index.php?module=user-users&action=activate_user&uid={$user['uid']}&my_post_key={$mybb->post_code}{$from_bit}"); + } + else + { + $popup->add_item($lang->approve_user, "index.php?module=user-users&action=activate_user&uid={$user['uid']}&my_post_key={$mybb->post_code}{$from_bit}"); + } + } + + $popup->add_item($lang->delete_user, "index.php?module=user-users&action=delete&uid={$user['uid']}&my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->user_deletion_confirmation}')"); + $popup->add_item($lang->show_referred_users, "index.php?module=user-users&action=referrers&uid={$user['uid']}"); + $popup->add_item($lang->show_ip_addresses, "index.php?module=user-users&action=ipaddresses&uid={$user['uid']}"); + $popup->add_item($lang->show_attachments, "index.php?module=forum-attachments&results=1&username=".urlencode(htmlspecialchars_uni($user['username']))); + $user['view']['controls'] = $popup->fetch(); + + // Fetch the reputation for this user + if($usergroups[$user['usergroup']]['usereputationsystem'] == 1 && $mybb->settings['enablereputation'] == 1) + { + $user['view']['reputation'] = get_reputation($user['reputation']); + } + else + { + $reputation = "-"; + } + + if($mybb->settings['enablewarningsystem'] != 0 && $usergroups[$user['usergroup']]['canreceivewarnings'] != 0) + { + $warning_level = round($user['warningpoints']/$mybb->settings['maxwarningpoints']*100); + if($warning_level > 100) + { + $warning_level = 100; + } + $user['view']['warninglevel'] = get_colored_warning_level($warning_level); + } + + if($user['avatar'] && my_substr($user['avatar'], 0, 7) !== 'http://' && my_substr($user['avatar'], 0, 8) !== 'https://') + { + $user['avatar'] = "../{$user['avatar']}"; + } + if($view['view_type'] == "card") + { + $scaled_avatar = fetch_scaled_avatar($user, 80, 80); + } + else + { + $scaled_avatar = fetch_scaled_avatar($user, 34, 34); + } + if(!$user['avatar']) + { + $user['avatar'] = "../".$mybb->settings['useravatar']; + } + $user['view']['avatar'] = "\"\""; + + // Convert IP's to readable + $user['regip'] = my_inet_ntop($db->unescape_binary($user['regip'])); + $user['lastip'] = my_inet_ntop($db->unescape_binary($user['lastip'])); + + if($view['view_type'] == "card") + { + $users .= build_user_view_card($user, $view, $i); + } + else + { + build_user_view_table($user, $view, $table); + } + } + + // If card view, we need to output the results + if($view['view_type'] == "card") + { + $table->construct_cell($users); + $table->construct_row(); + } + } + + if(!isset($view['table_id'])) + { + $view['table_id'] = "users_list"; + } + + $switch_view = "
"; + $switch_url = $view['url']; + if($mybb->input['page'] > 0) + { + $switch_url .= "&page=".$mybb->get_input('page', 1); + } + if($view['view_type'] != "card") + { + $switch_view .= "{$lang->table_view} | {$lang->card_view}"; + } + else + { + $switch_view .= "{$lang->table_view} | {$lang->card_view}"; + } + $switch_view .= "
"; + + // Do we need to construct the pagination? + if($num_results > $view['perpage']) + { + $pagination = draw_admin_pagination($mybb->input['page'], $view['perpage'], $num_results, $view['url']."&type={$view['view_type']}"); + $search_class = "float_right"; + $search_style = ""; + } + else + { + $search_class = ''; + $search_style = "text-align: right;"; + } + + $search_action = $view['url']; + // stop &username= in the query string + if($view_upos = strpos($search_action, '&username=')) + { + $search_action = substr($search_action, 0, $view_upos); + } + $search_action = str_replace("&", "&", $search_action); + $search = new Form(htmlspecialchars_uni($search_action), 'post', 'search_form', 0, '', true); + $built_view = $search->construct_return; + $built_view .= "
"; + $built_view .= $search->generate_hidden_field('action', 'search')."\n"; + if(isset($view['conditions']['username'])) + { + $default_class = ''; + $value = $view['conditions']['username']; + } + else + { + $default_class = "search_default"; + $value = $lang->search_for_user; + } + $built_view .= $search->generate_text_box('username', $value, array('id' => 'search_keywords', 'class' => "{$default_class} field150 field_small"))."\n"; + $built_view .= "search}\" />\n"; + if($view['popup']) + { + $built_view .= "
{$view['popup']}
\n"; + } + $built_view .= "\n"; + $built_view .= "
\n"; + + // Autocompletion for usernames + // TODO Select2 + + $built_view .= $search->end(); + + if(isset($pagination)) + { + $built_view .= $pagination; + } + if($view['view_type'] != "card") + { + $checkbox = ''; + } + else + { + $checkbox = " "; + } + $built_view .= $table->construct_html("{$switch_view}
{$checkbox}{$lang->users}{$view_title}
", 1, "", $view['table_id']); + if(isset($pagination)) + { + $built_view .= $pagination; + } + + $built_view .= ' + +
+ + +
'.$lang->inline_edit.' + +  + +
+
+
+'; + + return $built_view; +} + +function build_user_view_card($user, $view, &$i) +{ + global $user_view_fields; + + ++$i; + if($i == 3) + { + $i = 1; + } + + // Loop through fields user wants to show + foreach($view['fields'] as $field) + { + if(!$user_view_fields[$field]) + { + continue; + } + + $view_field = $user_view_fields[$field]; + + // Special conditions for avatar + if($field == "avatar") + { + $avatar = $user['view']['avatar']; + } + else if($field == "controls") + { + $controls = $user['view']['controls']; + } + // Otherwise, just user data + else if($field != "username") + { + if(isset($user['view'][$field])) + { + $value = $user['view'][$field]; + } + else + { + $value = $user[$field]; + } + + if($field == "postnum") + { + $value = my_number_format($value); + } + + $user_details[] = "{$view_field['title']}: {$value}"; + } + + } + // Floated to the left or right? + if($i == 1) + { + $float = "left"; + } + else + { + $float = "right"; + } + + // And build the final card + $card = "
\n"; + $card .= " {$user['view']['username']}\n"; + if($avatar) + { + $card .= "
{$avatar}
\n"; + } + if($user_details) + { + $card .= "
".implode("
", $user_details)."
\n"; + } + if($controls) + { + $card .= "
{$controls}
\n"; + } + $card .= "
"; + return $card; + +} + +function build_user_view_table($user, $view, &$table) +{ + global $user_view_fields; + + foreach($view['fields'] as $field) + { + if(!$user_view_fields[$field]) + { + continue; + } + $view_field = $user_view_fields[$field]; + $field_options = array(); + if($view_field['align']) + { + $field_options['class'] = "align_".$view_field['align']; + } + if($user['view'][$field]) + { + $value = $user['view'][$field]; + } + else + { + $value = $user[$field]; + } + + if($field == "postnum") + { + $value = my_number_format($user[$field]); + } + $table->construct_cell($value, $field_options); + } + + $table->construct_cell(""); + + $table->construct_row(); +} + +function fetch_scaled_avatar($user, $max_width=80, $max_height=80) +{ + $scaled_dimensions = array( + "width" => $max_width, + "height" => $max_height, + ); + + if($user['avatar']) + { + if($user['avatardimensions']) + { + require_once MYBB_ROOT."inc/functions_image.php"; + list($width, $height) = explode("|", $user['avatardimensions']); + $scaled_dimensions = scale_image($width, $height, $max_width, $max_height); + } + } + + return array("width" => $scaled_dimensions['width'], "height" => $scaled_dimensions['height']); +} + +function output_custom_profile_fields($fields, $values, &$form_container, &$form, $search=false) +{ + global $lang; + + if(!is_array($fields)) + { + return; + } + foreach($fields as $profile_field) + { + $profile_field['type'] = htmlspecialchars_uni($profile_field['type']); + list($type, $options) = explode("\n", $profile_field['type'], 2); + $type = trim($type); + $field_name = "fid{$profile_field['fid']}"; + + switch($type) + { + case "multiselect": + if(!is_array($values[$field_name])) + { + $user_options = explode("\n", $values[$field_name]); + } + else + { + $user_options = $values[$field_name]; + } + + $selected_options = array(); + foreach($user_options as $val) + { + $selected_options[$val] = $val; + } + + $select_options = explode("\n", $options); + $options = array(); + if($search == true) + { + $select_options[''] = $lang->na; + } + + foreach($select_options as $val) + { + $val = trim($val); + $options[$val] = $val; + } + if(!$profile_field['length']) + { + $profile_field['length'] = 3; + } + $code = $form->generate_select_box("profile_fields[{$field_name}][]", $options, $selected_options, array('id' => "profile_field_{$field_name}", 'multiple' => true, 'size' => $profile_field['length'])); + break; + case "select": + $select_options = array(); + if($search == true) + { + $select_options[''] = $lang->na; + } + $select_options += explode("\n", $options); + $options = array(); + foreach($select_options as $val) + { + $val = trim($val); + $options[$val] = $val; + } + if(!$profile_field['length']) + { + $profile_field['length'] = 1; + } + if($search == true) + { + $code = $form->generate_select_box("profile_fields[{$field_name}][{$field_name}]", $options, $values[$field_name], array('id' => "profile_field_{$field_name}", 'size' => $profile_field['length'])); + } + else + { + $code = $form->generate_select_box("profile_fields[{$field_name}]", $options, $values[$field_name], array('id' => "profile_field_{$field_name}", 'size' => $profile_field['length'])); + } + break; + case "radio": + $radio_options = array(); + if($search == true) + { + $radio_options[''] = $lang->na; + } + $radio_options += explode("\n", $options); + $code = ''; + foreach($radio_options as $val) + { + $val = trim($val); + $code .= $form->generate_radio_button("profile_fields[{$field_name}]", $val, $val, array('id' => "profile_field_{$field_name}", 'checked' => ($val == $values[$field_name] ? true : false)))."
"; + } + break; + case "checkbox": + if(!is_array($values[$field_name])) + { + $user_options = explode("\n", $values[$field_name]); + } + else + { + $user_options = $values[$field_name]; + } + foreach($user_options as $val) + { + $selected_options[$val] = $val; + } + $select_options = array(); + if($search == true) + { + $select_options[''] = $lang->na; + } + $select_options += explode("\n", $options); + $code = ''; + foreach($select_options as $val) + { + $val = trim($val); + $code .= $form->generate_check_box("profile_fields[{$field_name}][]", $val, $val, array('id' => "profile_field_{$field_name}", 'checked' => ($val == $selected_options[$val] ? true : false)))."
"; + } + break; + case "textarea": + $extra = ''; + if(isset($mybb->input['action']) && $mybb->input['action'] == "search") + { + $extra = " {$lang->or} ".$form->generate_check_box("profile_fields[{$field_name}_blank]", 1, $lang->is_not_blank, array('id' => "{$field_name}_blank", 'checked' => $values[$field_name.'_blank'])); + } + + $code = $form->generate_text_area("profile_fields[{$field_name}]", $values[$field_name], array('id' => "profile_field_{$field_name}", 'rows' => 6, 'cols' => 50)).$extra; + break; + default: + $extra = ''; + if(isset($mybb->input['action']) && $mybb->input['action'] == "search") + { + $extra = " {$lang->or} ".$form->generate_check_box("profile_fields[{$field_name}_blank]", 1, $lang->is_not_blank, array('id' => "{$field_name}_blank", 'checked' => $values[$field_name.'_blank'])); + } + + $code = $form->generate_text_box("profile_fields[{$field_name}]", $values[$field_name], array('id' => "profile_field_{$field_name}", 'maxlength' => $profile_field['maxlength'], 'length' => $profile_field['length'])).$extra; + break; + } + + $form_container->output_row($profile_field['name'], $profile_field['description'], $code, "", array('id' => "profile_field_{$field_name}")); + $code = $user_options = $selected_options = $radio_options = $val = $options = ''; + } +} + +function user_search_conditions($input=array(), &$form) +{ + global $mybb, $db, $lang; + + if(!$input) + { + $input = $mybb->input; + } + + if(!is_array($input['conditions'])) + { + $input['conditions'] = my_unserialize($input['conditions']); + } + + if(!is_array($input['profile_fields'])) + { + $input['profile_fields'] = my_unserialize($input['profile_fields']); + } + + if(!is_array($input['fields'])) + { + $input['fields'] = my_unserialize($input['fields']); + } + + $form_container = new FormContainer($lang->find_users_where); + $form_container->output_row($lang->username_contains, "", $form->generate_text_box('conditions[username]', $input['conditions']['username'], array('id' => 'username')), 'username'); + $form_container->output_row($lang->email_address_contains, "", $form->generate_text_box('conditions[email]', $input['conditions']['email'], array('id' => 'email')), 'email'); + + $options = array(); + $query = $db->simple_select("usergroups", "gid, title", "gid != '1'", array('order_by' => 'title')); + while($usergroup = $db->fetch_array($query)) + { + $options[$usergroup['gid']] = $usergroup['title']; + } + + $form_container->output_row($lang->is_member_of_groups, $lang->additional_user_groups_desc, $form->generate_select_box('conditions[usergroup][]', $options, $input['conditions']['usergroup'], array('id' => 'usergroups', 'multiple' => true, 'size' => 5)), 'usergroups'); + + $form_container->output_row($lang->website_contains, "", $form->generate_text_box('conditions[website]', $input['conditions']['website'], array('id' => 'website'))." {$lang->or} ".$form->generate_check_box('conditions[website_blank]', 1, $lang->is_not_blank, array('id' => 'website_blank', 'checked' => $input['conditions']['website_blank'])), 'website'); + $form_container->output_row($lang->icq_number_contains, "", $form->generate_numeric_field('conditions[icq]', $input['conditions']['icq'], array('id' => 'icq'))." {$lang->or} ".$form->generate_check_box('conditions[icq_blank]', 1, $lang->is_not_blank, array('id' => 'icq_blank', 'checked' => $input['conditions']['icq_blank'])), 'icq'); + $form_container->output_row($lang->aim_handle_contains, "", $form->generate_text_box('conditions[aim]', $input['conditions']['aim'], array('id' => 'aim'))." {$lang->or} ".$form->generate_check_box('conditions[aim_blank]', 1, $lang->is_not_blank, array('id' => 'aim_blank', 'checked' => $input['conditions']['aim_blank'])), 'aim'); + $form_container->output_row($lang->yahoo_contains, "", $form->generate_text_box('conditions[yahoo]', $input['conditions']['yahoo'], array('id' => 'yahoo'))." {$lang->or} ".$form->generate_check_box('conditions[yahoo_blank]', 1, $lang->is_not_blank, array('id' => 'yahoo_blank', 'checked' => $input['conditions']['yahoo_blank'])), 'yahoo'); + $form_container->output_row($lang->skype_contains, "", $form->generate_text_box('conditions[skype]', $input['conditions']['skype'], array('id' => 'skype'))." {$lang->or} ".$form->generate_check_box('conditions[skype_blank]', 1, $lang->is_not_blank, array('id' => 'skype_blank', 'checked' => $input['conditions']['skype_blank'])), 'skype'); + $form_container->output_row($lang->google_contains, "", $form->generate_text_box('conditions[google]', $input['conditions']['google'], array('id' => 'google'))." {$lang->or} ".$form->generate_check_box('conditions[google_blank]', 1, $lang->is_not_blank, array('id' => 'google_blank', 'checked' => $input['conditions']['google_blank'])), 'google'); + $form_container->output_row($lang->signature_contains, "", $form->generate_text_box('conditions[signature]', $input['conditions']['signature'], array('id' => 'signature'))." {$lang->or} ".$form->generate_check_box('conditions[signature_blank]', 1, $lang->is_not_blank, array('id' => 'signature_blank', 'checked' => $input['conditions']['signature_blank'])), 'signature'); + $form_container->output_row($lang->user_title_contains, "", $form->generate_text_box('conditions[usertitle]', $input['conditions']['usertitle'], array('id' => 'usertitle'))." {$lang->or} ".$form->generate_check_box('conditions[usertitle_blank]', 1, $lang->is_not_blank, array('id' => 'usertitle_blank', 'checked' => $input['conditions']['usertitle_blank'])), 'usertitle'); + $greater_options = array( + "greater_than" => $lang->greater_than, + "is_exactly" => $lang->is_exactly, + "less_than" => $lang->less_than + ); + $form_container->output_row($lang->post_count_is, "", $form->generate_select_box('conditions[postnum_dir]', $greater_options, $input['conditions']['postnum_dir'], array('id' => 'numposts_dir'))." ".$form->generate_numeric_field('conditions[postnum]', $input['conditions']['postnum'], array('id' => 'numposts')), 'numposts'); + $form_container->output_row($lang->thread_count_is, "", $form->generate_select_box('conditions[threadnum_dir]', $greater_options, $input['conditions']['threadnum_dir'], array('id' => 'numthreads_dir'))." ".$form->generate_numeric_field('conditions[threadnum]', $input['conditions']['threadnum'], array('id' => 'numthreads')), 'numthreads'); + + $form_container->output_row($lang->reg_in_x_days, '', $form->generate_text_box('conditions[regdate]', $input['conditions']['regdate'], array('id' => 'regdate')).' '.$lang->days, 'regdate'); + $form_container->output_row($lang->reg_ip_matches, $lang->wildcard, $form->generate_text_box('conditions[regip]', $input['conditions']['regip'], array('id' => 'regip')), 'regip'); + $form_container->output_row($lang->last_known_ip, $lang->wildcard, $form->generate_text_box('conditions[lastip]', $input['conditions']['lastip'], array('id' => 'lastip')), 'lastip'); + $form_container->output_row($lang->posted_with_ip, $lang->wildcard, $form->generate_text_box('conditions[postip]', $input['conditions']['postip'], array('id' => 'postip')), 'postip'); + + $form_container->end(); + + // Custom profile fields go here + $form_container = new FormContainer($lang->custom_profile_fields_match); + + // Fetch custom profile fields + $query = $db->simple_select("profilefields", "*", "", array('order_by' => 'disporder')); + + $profile_fields = array(); + while($profile_field = $db->fetch_array($query)) + { + if($profile_field['required'] == 1) + { + $profile_fields['required'][] = $profile_field; + } + else + { + $profile_fields['optional'][] = $profile_field; + } + } + + output_custom_profile_fields($profile_fields['required'], $input['profile_fields'], $form_container, $form, true); + output_custom_profile_fields($profile_fields['optional'], $input['profile_fields'], $form_container, $form, true); + + $form_container->end(); + + // Autocompletion for usernames + echo ' + + +'; +} diff --git a/Upload/admin/styles/default/config.css b/Upload/admin/styles/default/config.css new file mode 100644 index 0000000..a1995f4 --- /dev/null +++ b/Upload/admin/styles/default/config.css @@ -0,0 +1,77 @@ +/* language editor issue icons */ +.langeditor_ok { + width: 16px; + height: 16px; + display: inline-block; + margin: 1px; + background: url(images/icons/tick.png) no-repeat; +} + +.langeditor_nothingtocompare { + width: 16px; + height: 16px; + display: inline-block; + margin: 1px; + background: url(images/icons/no_change.png) no-repeat; +} + +.langeditor_warning { + width: 16px; + height: 16px; + display: inline-block; + margin: 1px; + background: url(images/icons/warning.png) no-repeat; +} + +/* language editor file list rows */ +.langeditor_editwithfile, +.langeditor_phrases, +.langeditor_editfile, +.langeditor_issues, +.langeditor_edit { + font-weight: bold; + text-align: center; +} + +.langeditor_editwithfile, +.langeditor_editfile { + text-align: left; +} + +.langeditor_edit, +.langeditor_phrases { + font-weight: normal; +} + +/* language editor edit mode textareas */ +.langeditor_textarea_issue { + border: 1px solid red; +} + +.langeditor_textarea_editwith { + background: #E0E0E0; +} +.langeditor_textarea_edit, +.langeditor_textarea_editwith { + width: 98%; + padding: 4px; +} + +/* language editor main page */ +.langeditor_info_name { + font-weight: bold; +} + +.langeditor_info_author { + font-size: x-small; +} + +.langeditor_rtl { + direction: rtl; + unicode-bidi: bidi-override; +} + +.langeditor_ltr { + direction: ltr; + unicode-bidi: bidi-override; +} diff --git a/Upload/admin/styles/default/forum.css b/Upload/admin/styles/default/forum.css new file mode 100644 index 0000000..1c507df --- /dev/null +++ b/Upload/admin/styles/default/forum.css @@ -0,0 +1,76 @@ +/* Moderation Queue */ +.modqueue_message { + overflow: auto; + max-height: 250px; +} + +.modqueue_controls { + width: 270px; + float: right; + text-align: center; + border: 1px solid #ccc; + background: #fff; + padding: 6px; + font-weight: bold; +} + +.modqueue_controls label { + margin-right: 8px; +} + +.label_radio_ignore, .label_radio_delete, .label_radio_approve { + font-weight: bold; +} + +.modqueue_meta { + color: #444; + font-size: 95%; + margin-bottom: 8px; +} + +.modqueue_mass { + list-style: none; + margin: 0; + width: 150px; + padding: 0; +} + +.modqueue_mass li { + margin-bottom: 4px; + padding: 0; +} + +.modqueue_mass li a { + display: block; + padding: 4px; + border: 1px solid transparent; +} + +.modqueue_mass li a:hover { + background: #efefef; + border: 1px solid #ccc; + text-decoration: none; +} + +.forum_settings_bit { + margin-bottom: 8px; +} + +.forum_settings_bit input { + vertical-align: middle; + margin-right: 8px; +} + +.forum_settings_bit select, +.forum_settings_bit input.text_input, +.forum_settings_bit textarea { + margin-top: 8px; +} + +.forum_settings_bit label { + font-weight: normal; +} + +.forum_settings_bit small { + padding-left: 25px; +} \ No newline at end of file diff --git a/Upload/admin/styles/default/home.css b/Upload/admin/styles/default/home.css new file mode 100644 index 0000000..92c11a8 --- /dev/null +++ b/Upload/admin/styles/default/home.css @@ -0,0 +1,15 @@ +#left_menu div.left_menu_box ul.online_admins li a { + background: url('images/icons/user.png') no-repeat 15px 4px; + padding-left: 37px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +#left_menu div.left_menu_box ul.online_admins li.mobile_user a { + background: url('images/icons/mobile_user.png') no-repeat 15px 4px; + padding-left: 37px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} \ No newline at end of file diff --git a/Upload/admin/styles/default/images/close.png b/Upload/admin/styles/default/images/close.png new file mode 100644 index 0000000000000000000000000000000000000000..4de4396d4a09677774f79289de2a09511baeea22 GIT binary patch literal 1910 zcmV-+2Z{KJP)z^Q>-8KIssI20AY({UO#lFGm;eBCjsO7iaR2~=Yybd* zy8r;x$N&H_>;M26yq<`~KL7v*>`6pHRCwBAWWWy?p_swJ!GY=X=g*8ke*9qk`ST}Z zdU`qw7Z(@fv}x0Rf#f+jIR5kU^8P2LK7aoF=BZPs zUOIK^)MsF*`~o`QH`D=t(JcoEAauk84FygG1qFf7&``O#bLZLs4PE;m4ZL{q;_rh8 z5B{QyfBg7y1u$e3few}u6cpqKnFTeI3E3im07CaENCB6OjEqoBOpMCLjT`;`{{8y^ zWZ_n$O7C)YSBAZ*T9f@87@wgQ~r-ckkXvV`F1EUVpg2H5Y-eYuxnRM9M39EBU%&nZ#x+Xt8W|aVwYIj#h+{D^u`kKV z$v=Qu3ogdS#`gK?)2F{dW*t0uupVfZDo|VqWEaTS009KEm>Z}`3Ydy*?%%(^5TtnW z(;G*fzk0D zSSo?}K!do)4&2r=HI`6@Kg;DK;Y5@D8S6f$jA!R2#R=y z-@kw3EZXkgz5D;mmoF#|yK?2qKWvtQ08AWYDKNn@LoH?k2q3V5?BoZ76wef+J_SucZ|q}*4Eat0ppwvn;u{u2G>@=;`K8pCnvlB0SF)lXugsH z7X0Rlii*j=;_ekFPSCRwF!6l>MgdBk`uh5!#Cc9m&JXm$1Xy;1vlOsk$^_bB1{9YD zI&JkwlS1w(;^Z^)!@LCEWfM7lr1G>gQO-(Jludi=U<2%PtU4%`gn2LZ7@5Q~G#ZGZrRXD5)S*xA{=fSSvIdGkEBd`SvUNJ#h& zEi#`0(?mH?%mZWxEIR=N5WD~ZWo}@L!d6H~C^;o1WhN}%Kn9R%DX3Tl1uIBDuwk$s zD3%Dsw#WqtKmai#w>W@Fo)wt5IG#Lt!pzOh{RtR^ngIa;EI|DX!1DGl0}&uLHkM`0 znlZR5`~$4;!Ko9NO&EZQ5}bNLd|;LO3|NQX zDk&*B3FO`b6<$F66o}sdF(~nY(#>Ch0AfUH2(Un1!w0oo5@@*$Fu}2#z zG+4x;SOQq;hynAf5U?N-FflO^1=e1m<_rU{W%&_U5xfEBgts6ML*w!V5Wj@tchKm7 z#Vt550|XEwmS!y*Qm}(kyC5{X2|-gN4>0wE+fTqMj{(U315A|Pffy8wAD|Y29Pu8S zm|(&C3%QvK5I~Grnzu|)pR++TIyW=~c%hErLTWoPKn(*K{0(XeEWv#R;_pxkeqBrOP0*Db$8yndX$XyynEc#&m wB;+m&vSk?cJ3s(2G7t}lRr{Y9MF0T?00rpcocj25u>b%707*qoM6N<$g7WXWmCn0bi#hNr^bt!L7v`EJ$GxUCy)BlkJMZiakY z#~bO5_gPDxS037yYi)T|x8Yp1{JLjv=4k8l&sWGlSSXXQ_U!3R3$95`4cf6Td)XeY z0@L@OZNwQI&ixENY#?%KHG`(=jAfeNYx}n^nKJX!D_M!;Ll%9J9DyfRuDf@Tx6|;D i>2JS#RjvQE&0jGlsxi-;#@W&hN&}v*elF{r5}E*449g_| literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/images/icons/bullet_on.png b/Upload/admin/styles/default/images/icons/bullet_on.png new file mode 100644 index 0000000000000000000000000000000000000000..b0c49219ec6cd2fcaa138f156555134edda128c8 GIT binary patch literal 630 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wk0|R49 zW=KRygs+cPa(=E}VoH8es$NBI0Z=sqgH44MkeQoWlBiITo0C^;Rbi_HR$&EXgM{^! z6u?SKvTce9aV>*FV^Zzz7(_qd_< zeqp58oad6)OIc4XW(WfgfYct0_hM16<8gh>=arf~W-`|7E}67u z%(i#X&Hr zoHgwO@~5B6bQw(gD}RRLoqvbX;8awc*@pb$vf~BbSl}%mdWcH z-X-wz?f1OQA8!=w&x3x z{bL{&i-E`eexFpeM#G^-<#PF}rfCGAd%d21Lk3xN#DFZzEE_t0cd!*O>^jo0ZEby^}0$2 z2OsI^NTF7%MWN8bhS_Xp02&@{$RLZ37zhLcPpj1`RVo$2+iriR#YL%TGMN~FhG)#6 zBL@6_|FX~LTLD{JrSFYKhxYb9G{WKAs{k4vZqpn(V!-S5GLOe|Lz2SJ6{Sx5`=99K zM5FWbUpmn6a6<-Jbi{z$?FL0fY0~cQdpbOpa2U#oQpK*Pfg8D!BB11^^f+*?{& zeygfqXny|IOQ+Mht|)B+(C~0W23d5(06vSw!t8c?+~II+*lf0&c)Q)7{0|+F(L)AV ze8vGdvz!1Y46Ih`eO}rG&{Lli;#@_?I55Mx!f|uvE@Ac}JA>|Tgp}$gQ695300000 LNkvXXu0mjfs9hZ% literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/images/icons/decrease.png b/Upload/admin/styles/default/images/icons/decrease.png new file mode 100644 index 0000000000000000000000000000000000000000..6680a57d3e98ba127a8b689ea45e2e4cd1a0e4f7 GIT binary patch literal 357 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!eSlAh>;M1%e?EHjAT#Ssl=sKm zS099X+(}D47V7vi()U_o)V=`oyJ@NCV*>a4n_o?e+UIY6J|UftDnm{ Hr-UW|WL16% literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/images/icons/default.png b/Upload/admin/styles/default/images/icons/default.png new file mode 100644 index 0000000000000000000000000000000000000000..997a6d387a2fd1508f2a13e4b20a2d9598363760 GIT binary patch literal 364 zcmV-y0h9iTP)XWdf_VRU(MdUbM0b@U0*2Y46ZeMHCl4GFCQmeycF7K^IDyexoK7!F@P zAqLIYtgV+*hGWbMA#D3b{J;^P4Y;56@73eC?}n(V@Nj#)Q+|#Q3f|}2w97QcK-g@s z8Cg?BQS=7hx&NGsverV_Y~a~Rq$!Eq8?4v)cCCTzKv;5Jmkk`dX?Gwjxg94UA_z;X zw$0;|WvPxJEX|*vCg*n_DtNod+3SSAavZP*GL@2-%s*z|-}w)#LA`i5Te3g^0000< KMNUMnLSTa3a-pvP literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/images/icons/delete.png b/Upload/admin/styles/default/images/icons/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..486e5868407dd9ff01aad48de778d37f96b24e2e GIT binary patch literal 695 zcmV;o0!aOdP)tOkDhvI8=*8 z3W&8(ujTIE-MjZ3XhYEm{Fe9fd-;9y`F`Jz=5jdz0AuWQKA-O?6bcA}007znbVj4m zn6B%gVHhl#OnR1Od5J`#s3^({0HB5JC>mwFe*A1~;pgUhmmX6Obf~ExRqs0s1abY4 z_*@V`qA#T-&rLtQ-5jD)%I2M5pCzRv`x2lLLfcf@&O_<>T!ecGL|TWH2%)-4t;vVp z(D{>eu`MP_K^XFeKx9{fAW*vQJ+JpJu5v|hC;Z7Po*BE)_UpG3*7qccN0r!{cV7DJ z39X{*a_!okjiHNYv_*$;uf@VPfe>N`fkH^+*b!Rm?o|Am$HNz3CKP z0{|h!{|V}hyWJ_eTv%d=kXMc;DD dhTSv({s$+;Ira5P=DGj?002ovPDHLkV1kNvMm7Kd literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/images/icons/error.png b/Upload/admin/styles/default/images/icons/error.png new file mode 100644 index 0000000000000000000000000000000000000000..3d65c6c020782018e031137f8cfe8b6f46738784 GIT binary patch literal 647 zcmV;20(kw2P)^@R5(wil0j$_K@^6EB+vw;X_j_f z0>N7g5p!rExt1CTJ(RQvrMN9UxAf>;L4;QD;=zMxX$0Hah*e2NXzjKolptB^Vxbyx z>Iy~=IViig<@x?4J48@CIPfiR-~9hSv$G?JNc<1}-;>~ zx=z;kxDRUdzRb+HFXM3&+TQ|7*jhAdoKH`?pQonitXQPl=qLpPHF}>WC#hL1x*I(` z20SugmA~(Jc-Y2j@5jb`_On?TfI8@(6bke%ownhT0S|@P_*f`7MlMGIuhVI2wOZ6@ zG-!2TfF3D|&zh=IWoXEOM+Q9LljhaE-H{P`o5@f)m7)@h>-9QWmPKoc1eLmYo=SP} z$bkF&V&?PS&fp-G`}=8&Me7XA&1TcD(F@qtG!GsbaF4fhkjXd|UbVu4fXxowJ+Q4P z4m>ho1s6wE&kyLIguY zLmhxP3W!sov;#;SBo9)@fX4vExP;`SDT_CDAHDi){ry*8j^BLzcI%=w+xkG_AbGF> zK0ZDe*w@!rFe)}aW!=H63y<7*edy7fZ)cyp{dNw7LF^qTZZ3(AO-KQ$WAOC!#D<+G z&R^TN`_hX8S08^o0n-e_*PeVjF@4E~i6C_h&dykI!nV^7)_@Gag%4hSvI(S)!OqSO z8_wT%<>fw@VssaP@QK@RkAl=OSXfwK!>N1DKir5*GYFr$@q7nJ9fP5vAvWwedG3no z`>(z_eE;Rw)99Lk0eNoTvbA$T>KL4yoERJ&9KcSuwY6oiv9Vz=H#b*tadWRea`E22 zo6kO@81U@<_luWr-rr$uV_Tx8rY3@6fVH)?JkXHhwQJY^*U;2%pE!N)(#J2}9eMlt z=e4J=-XEQ}VDU-~4b56XK|w7!IXMOt1ArQ}+}zx2cI?>mUsP1AnT3T#3y8yjxDtrl zp)`mu#>dCUfMNj9c8kEk;I<=2&iq$YRO$gLQUziLT$qcCi-CiKg8^o{cS1tSgo_vN z{@2qpmjX0B>~`~3xsM$9~x)tKLmEL zWh=G;2euK2cLB)tg6c=H`@gm*{8sg0E%(HK>iMJViYj$qrEtyj1Yk7+j9;5IZ{a%hRP|vRQ00PeJq76k-U*Fk`#Ke_g zZ|_+To=iwLfN5c%l+L{p{-|1R~wJKR6LGIQ&3O7fn?Zy@x0BXB@yZR+~cS z`?M5|Goy_G2vnWqtekZf2)_S%S7)hL7T@TW1PFyL13D0S5x#}g~vUgXxAvQN&Em^dop@E_=z1GcaxpPdvt|Bm*1qgvZ*A9H_6W}lO zLU2T!q%7QVq%}uIH8JAPna!%jf(Zk?XuL(&*48Y(@$n%|AFW(I-kSQB*BnyX1U&O$ zA(_^?*{8P8dfse$m0)a|j_t^$X0w^1G2q%@8NJ+JOt~EIRtymG=ev@&CKz?;ZRVN6 z`lpteuy%**9N zi&XV^(oz>)F}y_cyUigbZweQb00000NkvXXu0mjfrjBqx literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/images/icons/increase.png b/Upload/admin/styles/default/images/icons/increase.png new file mode 100644 index 0000000000000000000000000000000000000000..1c8c761e8dbd40a7d97c4a30c7872597788a5acb GIT binary patch literal 354 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!Q-Dv1>;M1%@4UL&zN4UZTmIAw zU8QT17TlbgwkR}gy2qiL2MSlkWh@DI@3Sdd9UnQ<%e+~?Wm{g!>IAO|ww5ghrE3zc zS`9Cze|iiwjj<%iFPOpM*^M+1C&}C0g`tC0)&t1lEbxdd2GSt52ZP(mY&#&s%hSa% zMB;LC!UCy;l%zD5r<*ryFk1BC=8cFOk`sUGI2<|HsdD}(ugJs3j)o_dl9oRkMC@H! z8M+k$td|RP8~F5d+_3Nq^wX+jV%TTPxa70vv`(O@swJ)wB`Jv|saDBFsX&Us$iUE8 z*T7QO$Rxzj)XLbz%FsyLz|hLTAn$$PJroVO`6-!cmAEy?Z+e*o)WG2B>gTe~DWM4f Dwb6E3 literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/images/icons/index.html b/Upload/admin/styles/default/images/icons/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/styles/default/images/icons/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/styles/default/images/icons/logout.png b/Upload/admin/styles/default/images/icons/logout.png new file mode 100644 index 0000000000000000000000000000000000000000..44707c1d4f082fd647b86c38151811153ed808c1 GIT binary patch literal 455 zcmV;&0XY7NP)&3ysJ_VZrO1mYO$8IKuEC)@_B)2Kg1*Z||cn+zaLKzs&-t)@SUA;|y`Hte|$ zvh~dL$N&F>Xp{b1F*ps-ZM!%VD0v1OZn^O5fB)@2|3Pe^x)`hmsMVf0(|PsR|Jsw^ z{@0xN_P_f0*Z)<=zW%Q`^5uWQo=^WXw!HsefBO4>kUAjtz%W3rXz!V(b3gu0`tsjk z``7;vxvns02^Qy z(`4WbU2q13*&QomSj4s9a@Y)D24X=VRt922AT|bJX6xc*%*M$jK(-zb%K|Ys5Hn&k xfC-2>fmjHLC4pE94T}RYKM=EFHDJIp698saMLGtS>iqx!002ovPDHLkV1gXN(QN<# literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/images/icons/maillogs_contact.png b/Upload/admin/styles/default/images/icons/maillogs_contact.png new file mode 100644 index 0000000000000000000000000000000000000000..097956d49b2823110dd776494fc13c22393fa24e GIT binary patch literal 681 zcmV;a0#^NrP)U z7w(s5ZmGr=W1=T{Gjr$6^Uj&Mhpj&1;2e-i5=qP@=8mH@E-(fMKn4t(w0tP!K5HS; zRb?=o3`G~_0p`>`XQqs1@eQpnlPZ5Q7$RMhJ;N7{PNgsUBeMz1F(k$%M2 zRdboMR=X;UR!BPnVswQ8DmSHSzANF$R5Ez-eA0Go)qxEGGbXtsmlbeH=`_Bry{hG& zzqC8eHR4~hm52O(B$`?bPh3hm3_gMh+ItMw;D97qrRQ*3wJ$H0tDl}dk(6_{=TFb2 zmpr_!sNCKIS$|lFl4zK+y20WTkKgiDp4Y>AY-SO;?E#VK!9A0G@n33mIo3-Y(eX5L z&9KEy)8t2nM=?8h2kR9NcDmw}-v8WJid@KU7=yeSG!w{@%U^))G{^K~4xQh=( z3H8o_3P{^Jko|5UHhmKw-v|UFSlKiTX4*Ck(}d;=VLW~d@3T+oREt3BAtwHYm@`aH z-+-zG(WSi#RVG+jxEN&6p~a42px#xGxO@*julKj^+HJQ{s8pcQs3{6{ko>a(E-GkH zqFk#X6bQhk?`ErYs6_*QKQ_x{caNm1q5>{=bX{ucItrx{MuI{2rMs4eej##0WFqz| zng+qjwXH2}BcI2Ku`y`m`nT}V)r15iSmuw%m#E}Z_=n(}e`Sv2;D6!=FSG6{vjE>? P00000NkvXXu0mjf$h17Jm^iSYn?3S(mkMvaB`8nQ8g0sMaivbuw7;Y(iT&zt!# zZ)U&{LZHC`F_ecFn^=!~;u#lWNenON^O~c(`L&0qTzSk;b@9*Bn=PVH`=G%Kv5WO_krmBSLySts%!2mbteLcG;c^;bxkySvoCw9b zsf!kw3@c(6TN;a}^FP^gYX}|q9UlH)Y&GW$R7y;LDPPaIE(t85L;K@bE_J~2(sEqe zYiefBx?I_lx}M!uT|EP>RF$`24}CT*F#E70J3n@b0B&fdvP>KpV&dR1Gw<(V#~iiHx03^Fv~_FZ<47j~ z+|b}5gDg7e<_E;#Q6`*YOz6)f<7>Ki@Rvj9Z3J*bQywzNt}w7g;^}eQ=aP{&0=S_m zZ-s#>;e6tjc#Y`=x-#&TzK(kpmj`0xk1r5Bl|i;}AX;y7$AS&MSChRj(kkp3Oj0-; zR^ax>zmxBInrywVCrw9VL3Dl(G~WZ)PTzl@=@|Y*7axC71E=o3qg*bhXub1R4Rnuw zCS=YGCNt=ui&rjo8_~8%lG>xQ`GFI+-cTx)`U#HrC-MWxoO|$r&_Ndin?>!RcG2LC z347lo&0$3Np5Sf1FBGs?EJpy}8@egA5Ikg5R(8&3ysJ_VZrO1mYO$8IKuEC)@_B)2Kg1*Z||cn+zaLKzs&-t)@SUA;|y`Hte|$ zvh~dL$N&F>Xp{b1F*ps-ZM!%VD0v1OZn^O5fB)@2|3Pe^x)`hmsMVf0(|PsR|Jsw^ z{@0xN_P_f0*Z)<=zW%Q`^5uWQo=^WXw!HsefBO4>kUAjtz%W3rXz!V(b3gu0`tsjk z``7;vxvns02^Qy z(`4WbU2q13*&QomSj4s9a@Y)D24X=VRt922AT|bJX6xc*%*M$jK(-zb%K|Ys5Hn&k xfC-2>fmjHLC4pE94T}RYKM=EFHDJIp698saMLGtS>iqx!002ovPDHLkV1gXN(QN<# literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/images/icons/mobile_user.png b/Upload/admin/styles/default/images/icons/mobile_user.png new file mode 100644 index 0000000000000000000000000000000000000000..d733ef5d4cf19c96555aa86f2c8be9767aa0b218 GIT binary patch literal 499 zcmV5lD|s=VI0PvG_Ev%a+pQt zfi#_Mfi@&Kh;zX?I2&%wL2yGu;HYg4QATpm#r_m8iiaB}+s<-URJ!yEFCub?^Q zylVoC$73!Vxn_4lk|cyeAq0a#3|C#IoHP%x!k;^x4&K{sUBl66CN}{_tnefKhINMn zg3ARzyL~ephRB@el=JSw4WytCZnqm=uNOX#2RnYp|2DWhTEo@B7gYHZ=X)PG-R&&i z;4h$Btzs}3pi-&mPVdVC^c7>V7_6M~r8c0Ot$gkV{eIsBh{xlwat@%r2~e-s(d+e~ zX_}pW({j12|7}L6Ipx%&z6rpNv(;*Cb-UeRv)OE4MQ|PC50AfNy|ix$sA^p(p?V002ovPDHLkV1j^{<17FG literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/images/icons/no_change.png b/Upload/admin/styles/default/images/icons/no_change.png new file mode 100644 index 0000000000000000000000000000000000000000..9d45a833953401613ce3347d97649a1269ab3b46 GIT binary patch literal 258 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 + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/styles/default/images/login_logo.png b/Upload/admin/styles/default/images/login_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..18347579cf688fe3f26ed515b2f96276d2be39bc GIT binary patch literal 6299 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 literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/images/spinner_big.gif b/Upload/admin/styles/default/images/spinner_big.gif new file mode 100644 index 0000000000000000000000000000000000000000..3bfd6e24d719c2ac85c3c84a2018f182537f9785 GIT binary patch literal 6586 zcma)=S6tI+_wCb3CkX*U5fVxYH36iHAqfzgLsKK521Er16_v5i7?NL*CI)nr>Vyu8 z3%HQ*z&pDUpJ$KJ@z4uz*wU?j2ud7>(FUS`(eF79- zF`|0*zHM~=;j2$wV+(huKVE+_A5`+_>Z5n1cV1t4_%^-$#l6{2TP}@muX}d$>3j9_ zh2(4F@%7IN`d-#QcpFpuw08JS(XE#k`d`%zzd7AGb8%>{d1U^SditDZ7PvX}OX=hM z-j}JW7m~Kg-&-d|)ldF;{O)Ye?320AZ$5pi9GL5y{P6AjkB?u!e_8$^y)pIq=jX@D z{O9H6A3we>|5*I;{riuVg{9>;AHRM2`hDvCm!)stuRVVE;mh*G{Fmo%m!7^^n)~=| zWbX6e%*T<}pI?6XI{M~w#lY*{$q(-{k6(YDS@>Fh z_x0?Dueseb!!JL*{`l?H;@6jpUthfcGCBX{?Wb?!@0K3D{yg?>Ddoo0gO{KBCKn&Q z`ZT@pMLo7~|K+D=ZXEwj@rR?U^ z-}m3v49zKTzp5UbtH1xY@s3j%4aNKQy)fXv3$)=n<9vCGI*NIg896n1GgIR%A9 zIj+{$8;Z-yD}YTxYdMs`STBcxw^TM&a>5uo&OmJ);E1tb#kty54E}|&sqOOLvdFFW zdfmg)=#WcE3}OFG8Q9)FK+gBQU(7);e(?YtOc?iMH||I&<1D~!oZLE70Eyhk1a9#? zycZGeOY;)~8fKil{6tW8KiwKYT72U$g=gsN5GBYSS;*NWQ*FMux-M6bjue7FRpq)oB-ctbC0LmV^s#LfpDSInve%X@UP($Y`OOyC} z&(tgoa$PVE3fnYvhQoY*IR9#N%!6x-SDw@{US`$N3&|C3le=}C-YA2 z4uk43+hU}@yIoO8v8(3@ljLBS*pjfWL(x%klD;p5E)cP}Ml)^+d{Weyq9cV9cLlB$ z&)w&UMR_YA`jNUlAuxe0K+kUmc?5_XUPyRH1@dDw3cH&< z2pr1pqC)X*0~l0n;V1#YZ2$Uzk6!nPy~`p!5u!%d z-7L25bajf#!oX_@^;9Q`)N=I(C6`Pi+)85G+9fq0iPlQukeiQE!Yh|GiS1Uek%S?R z+080C2TpVtdcyIeRt@UL`u|Z1i{hVFXw<~G8=G!Sf)B9ZHii|eTD0O z_8F=!jRIV= zfGt*+0q1LomL_!}!OG7SSlh-0L_P4%A!(qyoY%I!uOA3*^O8fO@0IdB>3LF@HpG(~ zGKAH^H2|BzXrC$wrqdJU=!ohPPW+!}nk>3HbTC_ya*VK;P%wBGcEda7aIk>|ADI&( zy)tjeL-w4}F+m3OFP51a@HSG&{#xl>ENj4K)Vw8k@RX1CSD(S1seLHV%4hN=>;jh=!wRwu{8_a%`%4^lQg7UDLpD;)wVlUj z^?eZuksFyshe_@_1eoqE=F!`zZrRnNt1FP65N{%qO4XRH$zm-X_c)OT>kwBGn(=&A#s3ukj%l9u>fr(PX{#4Ye%kKj8ou5SR4IH#hK;3_Qv)L6l_2R<)pK+}ZAj;t z69U%uT_>8vUAo?`oG#sW$M7Qg?QNwc6&@Oh?f^8zQgm@H2S7!?6@) z&geW8%}dVdh^L_k{I20(N)%>ua)}!I05JeJ8%^4ai>?od z#FN@0B56)dDu0|nIR@XqMyRTt>nNaJ>BSMt6wJM=;+~v~`G>b(-N4L>*`n#sj`r`q zx5r=3Q4Ng;K*CN~v?W?_*5#B|e_w-eRmjIC zb%QUV1A<-mFk%-E#KxHHjpqJdMRhAD2x#m%Za9JE>Y0Y>50FITcuMx2e%EGhIGS~~ z%?BNZiG2?)a@zoF2KR86%mA%K^%QWneGYXD>YIjP4J+v5t0zMa)AX6d7>xX17wCB2 zDtzfF2cXVuHb@)7M;A{V)|lnacnNVa2MqZ5wD!Zu?Fx#qse~PE7C`;4wTKa7nj}94=MFtL+ZL*HZm$9vdFHSuB5JZo20i29ITV57QsheWT z2Nb&NN58jRxkbxRqE(gIjE{W8-la6mR9m(Al{+g(GmUW z?un?O-SRpGTr@eQthZVzmptxt2s_sp1?-nvSAd?z6}C~gFRZtxnfgswjRVy>e$g(t zz%b*O&)&EQaolF_l;2tg6eFfwt~V8ZgoX6i z)vU@9A$}#3pjda%c+nq*cv2^E7j+=jVBOh`8cP;07D^OFgiU69eu@`iXIkoI7&{Bm zHvC45be|QX&*7;~`MH?bA9X=Eo_t~gpX%WiQ_W7JgF)u zn9J?<^m>pmQ#}3H0E&08b5P?~YZM&?--6!@AP{bj35{)$!$Z5;oH_}sax=jTR(yBn|T+*cw;E#Zh#{Q9qVKnLO&NQ{|r?foQ@CJ{ml(T&je7OUfPa zgX$5&RPDanJ0<-jGAX6M5#1r{_ryB*KyjK-4N9w#Gm3IxEcf83#$zDb2~)xnmFN@# zZt^nDk|ZZYhol)f{Ka(}1BShqew9(i9vr7>u0E(~qlOI*nrvPFM+?=Z?Y3Vr zUr6N9Zt9!)AWYv`2_PtB!z3-=d%r*CcV7}8?u-z%(3m^}jLUthREnYLx$ZBz7iXTH?I+7hj?&*h!RJLE z>?J*f-p+tz#%XkXIbFft&Y}uZRasQCx9cA!#k#PQgS<7BUb2#kkYU|D8HtdV8u^(^ zt6hAyBM3uTdPOVD;`;>~1|G7VR?}WJnQLWV`z^;gW@x&GPGNh1@iy_kXW9w{#EYD> z?;EMxT?d6ZW~fcKDvvTbF|i5d#@?<~u;2iF?IC(W@LHpM|AjkT6$sNiusYF!tn9P&2O@{W#TY*soxXS*~koI^#!9X~qtu6sGGsjf}{0po~wR&g^1NDFkNQJ9p}I z*9%q{n>pTSSrzjD3zGlnQ(j3*H=?3^XOcf#wn~>BsGN;%|c;%#+)7A zPOA03CdAnk0OyOcu zN~S)nxjWB~9J0v*?8J?Q@Ah3%uZlIv@zyJJ;>4Pu*zv_UeirKieXEU9ZI%(4`jomx zK~$Mlg=zUyjte^tG3dM|q4c+dS9nm|d?@r+J0`XA>UK^QiZtp>=t&9?(kk_fEUuug zkJdej2JgSft+Om7E9!2@*y5MGs9~Xo@C9#_g*{pwCB$vj(74jZ&av+MC`MI%tQKfM{uz6XX?3DyamDUq@eg9rTX!WYFBv3CL zH6hRmrhM%Iv8ue0P)cA*6xiag5G2B4FGr|L(WX+nvq@&~ZgG98>Stc7=-0CM^hQ2n zq^;3BrU^E}bQzwKLgHn-8KM{2zsi}$RD(ZxR=K<~17NcPFSlG+!*Z3|R94H_j;uA;HPQr# z{MyaZO1XzE%R}zJx;Nj^Q0s^bz-b3mtjwsYaUL^#B=4A(7DnzcD6{({<=DA8$itaH z-hrJp@U+8RJ${7VPT+EA!@AVwSnFq z6a|Txq$^|`Ucu_5UqByn4f3*Rf@b8bYq9I};3^elQ-jSg*6`1rsW}I%c~zghvoFvk zsMPg9g0D?r^yHE6*Q-zZoB6D;X?R^YB1sN zzvujHf*|c^s{k$RzxMF-1Hi~(c*WMqe>}FH8>b_Yn(LmSQDSdUEr171EU)c>E#~nqJYDidH45G;73YAX| zCxh-_`Qr~Nm|u@y#1Y_0@!d!N5~Zk6j697gmOdW>ia9?A0$*Z;5RFcVnFiKqUA-YV zqSh<)q(pDWd&%FB=zad=i29M#4Mrm%`QLX%QVIBiA!2i$Y^vT@p-i1jBZQ6qX@DUp zt|FUHWaXw4YAd4*F<|D)x0dXI>&P1|?sOwGlG!q1=~n&C{!#>TxlkWLK0a@b)?eU% zXxK}Jbm|)5LR<8Nc3jDTN=cwx@3=b@Hv{1{=pv{ zpNG~2h+qOBOa6H-C4~NVNSwU+Gqv!NvYEOw`6=Sm-b*o!)U-=u@X+LH3Fwr_iRhGj zfbWBZ1}{F|{xgjbuS!oYztCWvgfl42;9B2w#{X^s;Qz1s&(6*5C-Kuf{sa7D<&=#K7S;x7OClu(f7gLsDP9 z9HOa_wcVD6^*>CwSL95#-+x*bsxiHFLq@E12V9P58D5{vN7~!#$%%#$)eX2Jr3n@9 z%50L{H~GCF`uMDioPdZ+M1Z{|AdS+w_5uOYffl%@?y=Bk&F<%QzFhaOPTsO!Zcax=wH{j#D&hOT zFSX0T7thkNhJKB!+tXO2mTo41F`|9(O2B64)e*@7At^j9+h z{ZGGT%D%)+mwJ7{+D*qOcjL@`2nJ0@J*n)?I*GCQt@_{WOe`@z;pAEt>E>}(kki88 zk{bAw4nwF$lh#_D)G>Y;r^hvBAP-4N%iAHc{dI8qQz}Q$E&=NgYzUPq>IsiXE-J1G z&2CoZ8%D8%sE=D#R!?Mf-S!d$1<1Ma%?|pq6_LLEa_0LN9K2&6)dqe$DME&rEu^vH4g8cPT+peFyn({7YnEuW^!l+)2@8HnjCU=7M9CP zey^mjjbqOe4HJUh* z(uocdpHEk1ic2_$fPpj;Hj)?%v)LStn)}e>!N>%+7u!bVIj|LskuXMn;V s8S~W?_;rhr>^}E-7fHYkHBUXsMWAptXA66=jv8wu9D6>Egamo~4^Wi^r~m)} literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/images/submit_bg.png b/Upload/admin/styles/default/images/submit_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..387093b98445806e5782733124a317aa19b9f661 GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{M!3-pCdAEE8QsDtUA+G=b|Nr~%@83UvfB*jd z>-Vo;KY#uB@$>tSAK$-!|MuYb5TXT%^L3Sp2ySvEDVR2*!aySb-B8!2v z2N=7Z%(eqE3_V>OLpZMU9&BZ7FkoO%$Voq*^M8MEW4zMTlcHWzqb_8WRyAKt*%skC z`|iV%owoP*<>DBpd;aw}1=Ors;u=wsl30>zm0Xkxq!^4042^XSEOm`cLJUoZ0002ONklc0EdNGS%ukbt%1^0bZe6H)F;QHDae9te%=R8jej`N`4 zIBX8h$Hw5Ze<(itwo|Ze8wKmSQhb(Wq4>=6O!1kfiQ+SkBL(9yP%sQV#i#E(ici BZ7Bc% literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/images/thead.png b/Upload/admin/styles/default/images/thead.png new file mode 100644 index 0000000000000000000000000000000000000000..e4733e64a5959b1ac24db562d27cfef6005b4761 GIT binary patch literal 2042 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!2~2XTwzyWU|^QZbaoE#baqwWn zun=qwxu1PGK;+-8)VUiTc3Y(ja@u7~%u5L_ah|g+JABvKs8?p&6+LDz%Z-_JOyzCe z2KJlX`Bq2EKeF5XWaqiroL@bO_n1iHk2M`iKHro!&zo)Hs~*g}^ZV}mKi^rZKYtRp z;AdgfWf6UTkz&x-*5iRCwDBT>i?CDjW zmS$q=FpKjL`%xz=?;Q>nGcq51=Dl&QQRIob+R90K-8QRTgY=)KxNhS4_Cdb5`BVIc z6;oc$Ui)02H+Pn#-^H4)d-9gG1wGFgt{$|Hm)PsLV{So&+2h5gbxvnh)(NWZeg3W_ zbH>}$S<@pmg;Zr!_9TU@GtS9;#?9P0>)GYEUjim=m~XP*#5nTvLNaZn@^QdWU~|zke<2dRjT@!|N?_y;r|PPqGTTef!DTWy*(-ln2@~ zdpI@q$)spJnCQflI4k+csvkaLl1g4nE@hU4RBp1kX00)K+FKd-ij(ntJL1H?MsM2j z?ZNMPcU7TKmrub(}N(Z9|fdbp zRtZaP+PH6HT^NVoo;9U>ZI@q{@PsmGkM~s z^LVcJxT&|ny8kWnw%}{A&obkSEkA1&yp;ZX__dySC|jK5fs4g@;tPyRpKxxdiPL#4 zdRyLR-u8xx*0+<_+U6$i>b478eY-?2T8?oy|LUvr&#$_A_xY20?ux~K*j6fYUEB37 zw-uOSI14-?iy0WWg+Z8+Vb&Z81_llpi<;HsXMd|v6mX?|l=&b@WD^hbJTrzjDN{jmELaqnW$n0tI$_!0j!WX3 zF|cA~2=#Pv4B?QK?L8=Xz=4BlV!4*@+Dy-rubKrdzg_uU=XdH{MOF;wZk;`sG_EP| zR>ml0@3}VlFsrA*b!F{)A8uCGT)zHw+ReJNMjOnJ`aRG4#Q*c&(%;NC;$7@t?fIk& PDswzt{an^LB{Ts5P`wTl literal 0 HcmV?d00001 diff --git a/Upload/admin/styles/default/index.html b/Upload/admin/styles/default/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/styles/default/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/admin/styles/default/login.css b/Upload/admin/styles/default/login.css new file mode 100644 index 0000000..6bd2b79 --- /dev/null +++ b/Upload/admin/styles/default/login.css @@ -0,0 +1,191 @@ +/* MyBB Admin CP + * + * Login CSS + */ + +body { + font-family: 'Lucida Grande', Tahoma, Verdana, Arial, sans-serif; + font-size: 12px; + background: #fff; + color: #000000; + margin: 0; +} + +a { + color: #0072BC; + text-decoration: none; +} + +a:hover { + color: #0072BC; + text-decoration: underline; +} + +.invisible { + display: none; +} + +#container { + width: 410px; + margin: 100px auto; +} + +#logo h1 { + height: 82px; + background: transparent url(images/login_logo.png) bottom left no-repeat; + margin: 10px; + padding: 0; +} + +#header h1 a { + float: left; + height: 82px; + width: 410px; +} + +#content { + border: 1px solid #ccc; + background: #fff; + padding: 1px; + border-radius: 6px; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; +} + +p, form { + padding: 0 10px 10px 10px; +} + +form { + padding-bottom: 0; +} + +p { + margin-bottom: 0; +} + +form p { + padding: 0 0 10px 0; +} + +h2 { + background: #02426c url(images/thead.png) repeat-x top left; + border-bottom: 1px solid #263c30; + color:#fff; + margin: 0; + padding: 8px; + font-size: 14px; + border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + -webkit-border-radius: 5px 5px 0 0; +} + +input.text_input { + border: 1px solid #aaa; + width: 255px; + padding: 4px; + font-size: 13px; + font-family: 'Lucida Grande', Tahoma, Verdana, Arial, sans-serif; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + outline: 0; +} + +input.text_input:focus { + border: 1px solid #777; +} + +#message { + margin: 10px 10px 0 10px; + padding: 10px; + font-weight: bold; + background: #efefef; + border: 1px solid #ccc; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +#message.error { + border: 1px solid #FC6; + background: #FFC; + color: #C00; +} + +#message.success { + border: #080 1px solid; + background-color: #E8FCDC; + color: #080; +} + +form .label { + margin-bottom: 3px; + width: 112px; + clear: left; + float: left; + padding: 15px 0 0 8px; + border-top: 1px solid #ddd; +} + +form label { + font-weight: bold; +} + +.form_container .field { + float: left; + padding: 8px 0; + border-top: 1px solid #ddd; +} + +p.submit { + clear: both; + background: #efefef; + border-top: 1px solid #ddd; + padding: 8px 10px; + margin: 8px -10px 0; + text-align: right; + border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + -webkit-border-radius: 0 0 5px 5px; +} + +p.submit input { + border: 1px solid #999; + padding: 4px 7px; + background: #e3e3e3 url(images/submit_bg.png) repeat-x top; + color: #444; + font-weight: bold; + font-family: 'Lucida Grande', Tahoma, Verdana, Arial, sans-serif; + margin-right: 3px; + font-size: 1.1em; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +p.submit input:hover { + border: 1px solid #666; + cursor: pointer; +} + +.forgot_password { + float: left; + padding-top: 8px; + font-size: 11px; +} + +.forgot_password a { + color: #555; +} + +.alert { + padding: 5px 10px; + border: #FC6 1px solid; + background-color: #ffc; + color: #900; + font-style: normal; + font-weight: bold; + padding-left: 10px; + display: block; +} \ No newline at end of file diff --git a/Upload/admin/styles/default/main.css b/Upload/admin/styles/default/main.css new file mode 100644 index 0000000..f83e700 --- /dev/null +++ b/Upload/admin/styles/default/main.css @@ -0,0 +1,1236 @@ +/* MyBB Admin CP + * + * Main CSS + */ + +body, td { + font-family: 'Lucida Grande', Tahoma, Verdana, Arial, sans-serif; + font-size: 12px; + color: #333; + margin: 0; + margin-bottom: 20px; +} + +body { + overflow-y: scroll; +} + +a { + color: #0072BC; + text-decoration: none; +} + +a:hover { + color: #0072BC; + text-decoration: underline; +} + +.invisible { + display: none; +} + +#container { + background: #fff; +} + +#logo { + background: url(images/logo.png) 15px 15px no-repeat; + border-bottom: 1px solid #263C30; + height: 90px; +} + +#logo h1 { + display: none; +} + +#welcome { + position: absolute; + right: 20px; + top: 60px; + color: #999; + height: 20px; + font-size: 90%; +} + +#welcome a, +#welcome a:link, +#welcome a:visited +{ + color: #666; + min-height: 16px; +} + +#welcome .logout { + margin-left: 4px; + padding: 0 18px 2px 0; + background: url(images/icons/logout.png) no-repeat top right; +} + +#welcome .forum { + margin-left: 4px; + padding: 1px 0 2px 20px; + background: url(images/icons/world.png) no-repeat top left; +} + +#welcome .username { + margin-left: 4px; + padding: 0 0 2px 18px; + background: url(images/icons/user.png) no-repeat top left; +} + +/* Menu */ + +#menu ul { + margin: 0; + padding: 5px 5px 0; + list-style: none; + background: #0F0F0F url(images/tcat.png) repeat-x; + border-top: 1px solid #444; + border-bottom: 1px solid #000; +} + +#menu li { + font-size: 12px; + display: inline-block; + margin: 0 8px 0 8px; + padding: 0; + list-style: none; +} + +#menu a { + font-weight: bold; + float: left; + padding: 7px; + text-decoration: none; + color: #ddd; +} + +#menu a:hover { + color: #fff; +} + +#menu li a.active { + padding: 7px 11px 10px; + margin-bottom: -5px; + background: #fff; + border-radius: 5px 5px 0 0; + color: #222; + font-size: 1.1em; +} + +#page { + clear: both; + background: #fff; +} + +/* Main Content */ + +#content { + padding: 10px 15px; + margin: 0; + margin-left: 200px; +} + +#content p { + line-height: 150%; +} + +#content h2 { + font-family: 'Lucida Grande', 'Trebuchet MS', Verdana, Sans-Serif; + font-size: 170%; + letter-spacing: -1px; + font-weight: bold; + color: #666; + margin: 0 0 5px 0; +} + +#content h3 { + border-bottom: 1px solid #ccc; + font-size: 16px; + margin: 10px 0 7px 0; +} + +#content h4 { + font-size: 14px; + margin: 10px 0 -10px 0; +} + +/* Left Menu */ + +#page { + background: #fff; +} + +#left_menu { + width: 200px; + color: #333; + padding: 0; + margin: 0; + float: left; + font-size: 11px; +} + +#left_menu div.left_menu_box { + background: #fff; + list-style: none; + margin: 10px 10px 30px 10px; + padding: 0; +} + +#left_menu div.left_menu_box div.title { + font-weight: bold; + border-bottom: 1px solid #ccc; + padding-bottom: 5px; + font-size: 1.1em; +} + +#left_menu div.left_menu_box ul.menu { + padding: 0; + margin: 0; + list-style: none; +} + +#left_menu div.left_menu_box ul.menu li a { + display: block; + padding: 6px; + border-bottom: 1px solid #ddd; +} + +#left_menu div.left_menu_box ul.menu li a:hover { + text-decoration: none; + background-color: #f5f5f5; +} + +#left_menu div.left_menu_box ul.menu li.active a { + font-weight: bold; + font-size: 120%; + color: #000; +} +/* Fix IE. Hide from IE Mac \*/ +* html #left_menu li a, , * html #left_menu li { + height: 1%; +} +/* End */ + + +/* Tables */ + +.border_wrapper { + margin: 0; + padding: 1px; + margin-bottom: 14px; + border: 1px solid #ccc; + border-radius: 6px; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; +} + +* html .border_wrapper { + height: 1px; +} + +.border_wrapper div.title { + background: #0066a2 url(images/thead.png) top left repeat-x; + color: #ffffff; + border-bottom: 1px solid #263c30; + padding: 8px; + font-weight: bold; + text-align: left; + font-size: 120%; + border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + -webkit-border-radius: 5px 5px 0 0; +} + +.border_wrapper div.title a { + color: #fff; + text-decoration: none; +} + +.border_wrapper div.title a:hover { + text-decoration: underline; +} + +table.general { + width: 100%; +} + +table.general td { + border-top: 1px solid #fafafa; + border-bottom: 1px solid #ccc; + border-right: 1px solid #ccc; + border-left: 1px solid #fafafa; +} + +table.general tr td:last-child { + border-right: 0; +} + +table.general tr td:first-child { + border-left: 0; +} + +table.general tr:last-child td { + border-bottom: 0; +} + +table.bottom_cell_border td { + border-right: 0; + border-left: 0; +} + +table.general td { + background: #f5f5f5; + padding: 6px; +/* vertical-align: top; */ +} + +table.general th { + background: #0f0f0f url(images/tcat.png) repeat-x; + color: #fff; + border-top: 1px solid #444; + border-bottom: 1px solid #000; + padding: 8px; + font-size: 96%; + font-weight: bold; + text-align: left; +} + +table.general th a, table.general th { + color: #fff; + text-decoration: none; +} + +table.general .alt_row td { + background: #f1f1f1; +} + +table.general tr:last-child td:first-child { + border-bottom-left-radius: 5px; + -moz-border-radius-bottomleft: 5px; + -webkit-border-bottom-left-radius: 5px; +} + +table.general tr:last-child td:last-child { + border-bottom-right-radius: 5px; + -moz-border-radius-bottomright: 5px; + -webkit-border-bottom-right-radius: 5px; +} + +/* Page Footer */ +#footer { + clear: both; + border-top: 1px solid #ccc; + background: #eee; + border-bottom: 1px solid #ccc; +} + +#footer p { + padding: 12px; + color: #666; + margin: 0; + font-size: 11px; +} + +#footer .generation { + float: right; +} + +#footer a:link, #footer a:visited { + color: #666666; + font-weight: bold; +} +#footer a:hover, #footer a:active { + color: #444444; + font-weight: bold; + text-decoration: underline; +} +/* Popup Menus */ + +.popup_button { + color: #444; + text-align: right; + border: 1px solid #999; + padding: 3px 6px; + background: #e3e3e3 url(images/submit_bg.png) repeat-x top; + font-weight: bold; + margin-top: 3px; + margin-bottom: 3px; + margin-left: 3px; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +a.popup_button:link, +a.popup_button:visited, +a.popup_button:active, +a.popup_button:hover { + text-decoration: none; + color: #444; +} + +a.popup_button:active, +a.popup_button:hover { + text-decoration: none; + color: #444; + border: 1px solid #666; +} + +.popup_menu { + margin: 1px 0 0 1px; + background: #fff; + border: 1px solid #ccc; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.popup_menu .popup_item_container { + margin: 1px; + text-align: left; +} + +.popup_menu .popup_item { + display: block; + padding: 5px; + text-decoration: none; + white-space: nowrap; + background: #efefef; + color: #333; +} + +.popup_menu .popup_item_container:first-child .popup_item { + border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + -webkit-border-radius: 3px 3px 0 0; +} + +.popup_menu .popup_item_container:last-child .popup_item { + border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + -webkit-border-radius: 0 0 3px 3px; +} + +.popup_menu a.popup_item:hover { + text-decoration: none; + background: #666; + color: #fff; +} + +.transparent, .transparent td { + background: transparent; +} + +.breadcrumb { + margin-bottom: 10px; + font-size: 96%; + color: #aaa; +} + +.breadcrumb a { + color: #666; +} + +.breadcrumb a:hover, +.breadcrumb a:active { + color: #444; + text-decoration: none; +} + +.breadcrumb .active { + font-weight: bold; + color: #222; +} + +.inline_message { + background: #FFF6BF; + border-top: 2px solid #FFD324; + border-bottom: 2px solid #FFD324; + text-align: center; + margin: 10px auto; + padding: 5px 20px; +} + +.notice { + background: #EFEFEF; + border-top: 2px solid #CCC; + border-bottom: 2px solid #CCC; + text-align: center; + margin: 10px auto; + padding: 5px 20px; +} + +table.individual_cell_border { + border-style: collapse; +} + +table.cell_border_bottom td { + border: 1px solid #CCC; + border-style: collapse; + border-spacing: 1px; +} + +/* Forms */ + +form { + border: 0; + margin: 0; +} + +form div.form_container, fieldset { + background: #efefef; + border: 1px solid #ccc; + padding: 2px 7px 5px; + margin-bottom: 10px; +} + +fieldset { + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.form_row { + margin: 5px 0; +} + +legend { + font-weight: bold; +} + +.form_container label { + font-weight: bold; +} + +.form_container .description, small { + font-size: 11px; + color: #444; +} + +input.text_input { + border: 1px solid #aaa; + width: 300px; + padding: 4px; + font-size: 13px; + font-family: 'Lucida Grande', Tahoma, Verdana, Arial, sans-serif; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + outline: 0; +} + +textarea { + border: 1px solid #aaa; + padding: 4px; + width: 400px; + font-size: 12px; + font-family: 'Lucida Grande', Tahoma, Verdana, Arial, sans-serif; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + outline: 0; +} + +textarea[disabled=disabled] { + border: 1px solid #ccc; + padding: 4px; + color: #666; + font-size: 12px; + font-family: 'Lucida Grande', Tahoma, Verdana, Arial, sans-serif; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +select { + border: 1px solid #aaa; + padding: 4px; + font-size: 12px; + font-family: 'Lucida Grande', Tahoma, Verdana, Arial, sans-serif; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + outline: 0; +} + +textarea:focus, input.text_input:focus, select:focus { + border-color: #777; +} + +input.inline_submit { + font-weight: bold; +} + +form p.legend { + margin-bottom: 10px; +} + +form p.legend em { + color: #C00; font-style: normal; +} + +.form_container label em, fieldset label em { + font-style: normal; + color: #C00; +} + +input.submit_button { + border: 1px solid #999; + padding: 4px 7px; + background: #e3e3e3 url(images/submit_bg.png) repeat-x top; + color: #444; + font-weight: bold; + font-family: 'Lucida Grande', Tahoma, Verdana, Arial, sans-serif; + margin-right: 3px; + font-size: 1.1em; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + outline: 0; +} + +input.submit_button:hover { + border: 1px solid #666; + cursor: pointer; +} + +.form_button_wrapper { + margin-top: 5px; + text-align: center; + border: 1px solid #ccc; + background: #efefef; + padding: 3px; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.confirm_action { + margin: 10px 0; + padding: 10px; + font-weight: bold; + border: 1px solid #FC6; + background: #FFC; + color: #C00; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.confirm_action p { + margin: 0; +} + +input.button_yes, +input.button_yes:hover { + background: #D6ECA6; + border: 1px solid #8DC93E; + padding: 4px 6px; + font-weight: bold; + margin-right: 3px; +} + +input.button_no, +input.button_no:hover { + background: #ECA6D6; + border: 1px solid #C93E8D; + padding: 4px 6px; + font-weight: bold; +} + +.label_radio_yes, .label_radio_on, .label_radio_no, .label_radio_off { + padding: 4px 6px; + margin-right: 5px; + margin-top: 5px; + display: block; + width: 60px; + float: left; +} + +.label_radio_yes, .label_radio_on { + background: #D6ECA6; + border: 1px solid #8DC93E; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.label_radio_no, .label_radio_off { + background: #ECA6D6; + border: 1px solid #C93E8D; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +input.radio_input { + vertical-align: middle; + margin: 0; + margin-right: 9px; +} + +#flash_message { + margin: 10px 0; + padding: 10px 10px 10px 32px; + font-weight: bold; + background: #efefef; + border: 1px solid #ccc; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +#flash_message.error { + border: 1px solid #FC6; + background: #FFC url('images/icons/error.png') no-repeat 10px 8px; + color: #C00; +} + +#flash_message.success { + border: #080 1px solid; + color: #080; + background: #E8FCDC url('images/icons/success.png') no-repeat 10px 8px; +} + +.alert { + margin: 10px 0; + padding: 10px 10px 10px 32px; + border: #FC6 1px solid; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + background: #ffc url('images/icons/warning.png') no-repeat 10px 8px; + color: #C00; + font-style: normal; + font-weight: bold; + display: block; +} + +div.error, div.success { + margin: 10px 0; + padding: 10px; +} + +div.error { + border: #FC6 1px solid; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + background: #ffc; +} + +div.success { + border: #080 1px solid; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + background: #E8FCDC; +} + +div.error p, div.success p { + margin: 0; + color: #000; + font-weight: normal; +} + +div.error p em, div.success p em { + font-style: normal; + font-weight: bold; + padding-left: 24px; + display: block; +} + +div.error p em { + color: #C00; + background: url('images/icons/error.png') no-repeat; +} + +div.success p em { + color: #080; + background: url('images/icons/success.png') no-repeat; +} + +div.success ul, div.error.ul { + margin-left: 24px; +} + +.nav_tabs { + margin-bottom: 10px; +} +.nav_tabs ul { + list-style: none; + padding: 0; + margin: 0 0 0 10px; + height: 32px; +} + +.nav_tabs li { + float: left; + padding-right: 5px; +} + +.nav_tabs li.right { + float: right; + padding-left: 5px; + padding-right: 0; +} + +.nav_tabs li a { + float: left; + border-bottom: 0; + display: block; + font-family: 'Lucida Grande', 'Trebuchet MS', Verdana, Sans-Serif; + font-size: 140%; + letter-spacing: -1px; + color: #888; + padding: 5px 8px 3px; + height: 24px; +} + +.nav_tabs li a:hover { + color: #666; + text-decoration: none; +} + +.nav_tabs li.active a { + color: #555; + font-size: 150%; + font-weight: bold; + padding-top: 5px; + border-bottom: 3px solid #555; +} + +.nav_tabs .tab_description { + background: #f3f3f3; + padding: 10px; + border: 1px solid #ddd; + border-top: 3px solid #bbb; + color: #555; + font-size: 95%; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +* html .nav_tabs .tab_description { + margin-left: 3px; +} +*.align_center, table.general th.align_center, input.align_center { + text-align: center; +} + +.float_right { + float: right; +} + +.float_left { + float: left; +} + +a img { + border: 0; +} + +option { + padding-right: 10px; +} + +ul.tabs { + width: 100%; + margin: 10px 0 0 10px; + padding: 0; + list-style: none; + height: 27px; +} + +ul.tabs li { + float: left; + margin: 0; + padding: 0; + list-style: none; +} + +ul.tabs a { + float: left; + padding: 6px 10px; + text-decoration: none; + color: #888; + border: 0; + margin: 0 5px; +} + +ul.tabs a:hover { + color: #666; +} + +ul.tabs li a.active { + color: #fff; + font-size: 100%; + text-align: left; + font-weight: bold; + color: #333; + border: 1px solid #ddd; + border-bottom: 1px solid #ccc; + margin-top: -1px; + background: #f5f5f5; + border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + -webkit-border-radius: 5px 5px 0 0; +} + +.editor { + background: #f1f1f1; + border: 1px solid #ccc; +} + +.editor_control_bar { + background: #fff; + border: 1px solid #0f5c8e; +} + +.toolbar_normal { + background: #f0f0f0; + border: 1px solid #f0f0f0; +} + +.toolbar_hover { + background: #c1d2ee; + border: 1px solid #5296f7; +} + +.toolbar_clicked { + background: #e1F2fe; + border: 1px solid #5296f7; +} + +.user_avatar { + height: 80px; + width: 80px; + background: #fff; + border: 1px solid #ccc; + float: left; + clear: left; + margin-right: 5px; + text-align: center; +} + +.user_avatar img { + vertical-align: middle; +} + +.user_details { + float: left; + margin-left: 5px; + line-height: 1.7; +} + +.pagination { + font-size: 11px; + margin-bottom: 10px; + margin-top: 10px; +} + +.pagination .pages { + font-weight: bold; +} + +.pagination .pagination_current, .pagination a { + padding: 2px 6px; + margin-bottom: 3px; +} + +.pagination a { + background: #f3f3f3; + border: 1px solid #ddd; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.pagination .pagination_current { + background: #fff; + border: 1px solid #fff; + font-weight: bold; + font-size: 110%; +} + +.pagination a:hover { + background: #ddd; + text-decoration: none; + border: 1px solid #999; +} + +.view_fields .enabled, .view_fields .disabled { + width: 200px; + float: left; +} + +.view_fields .disabled { + margin-left: 20px; +} + +.view_fields .fields_title { + font-weight: bold; + font-size: 120%; +} + +.view_fields ul, .view_fields li { + list-style: none; + padding: 0; + margin: 0; +} + +.view_fields ul { + overflow: auto; // Scroll fix for Opera + overflow-y: auto; + overflow-x: hidden; + margin-top: 4px; +} + +.view_fields li { + -moz-border-radius: 3px; + padding: 4px; + background: #666; + color: #fff; + font-size: 11px; + margin-bottom: 2px; + margin-right: 5px; +} + +.quick_perm_fields .enabled, .quick_perm_fields .disabled { + width: 49%; + float: left; +} + +.quick_perm_fields .enabled { + border-right: 5px solid #666; +} + +.quick_perm_fields .disabled { + float: right; + margin-left: 0px; +} + +.quick_perm_fields .fields_title { + font-weight: bold; + font-size: 120%; +} + +.quick_perm_fields ul, .quick_perm_fields li { + list-style: none; + padding: 3px; + margin: 0; +} + +.quick_perm_fields ul { + overflow: auto; // Scroll fix for Opera + overflow-y: auto; + overflow-x: hidden; + height: 120px; + margin-top: 4px; +} + +.quick_perm_fields li { + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + padding: 4px; + background: #666; + color: #fff; + font-size: 11px; + margin-bottom: 2px; + margin-right: 10px; +} + +input.field50 { + width: 50px; +} +input.field150 { + width: 150px; +} + +input.field_small { + font-size: 13px; + padding: 3px; +} + +input.search_default { + text-align: center; + color: #aaa; + padding: 3px; +} + +input.image_button { + margin-left: 5px; + vertical-align: bottom; +} + +input.search_button { + background: #fff url(images/icons/search.png) no-repeat; + background-position: 4px 7px; + border: 0px; + padding: 4px; + padding-left: 23px; + font-size: 14px; + font-family: 'Lucida Grande', 'Trebuchet MS', Verdana, Sans-Serif; + color: #6F6F6F; + font-weight: bold; + height: 30px; +} + +.smalltext { + font-size: 11px; +} + +.inline_element { + font-weight: normal !important; +} + +.inline_selected { + background-color: #FFFBD9; +} + +/* Templates Differential page */ +.differential { + background: #FFF; + margin: 10px auto; + padding: 10px; + overflow: scroll; + height: 400px; + width: 980px; + border: 1px solid #ccc; +} + +/** jGrowl Start **/ + +/** Special IE6 Style Positioning **/ +.ie6 { + position: absolute; +} + +.ie6.top-right { + right: auto; + bottom: auto; + left: expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +.ie6.top-left { + left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +.ie6.bottom-right { + left: expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +.ie6.bottom-left { + left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +.ie6.center { + left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); + width: 100%; +} + + +/** jGrowl Styling **/ +.jGrowl { + z-index: 9999; + color: #fff; + font-size: 12px; + position: fixed; +} + +.jGrowl.top-left { + left: 0px; + top: 0px; +} + +.jGrowl.top-right { + right: 0px; + top: 0px; +} + +.jGrowl.bottom-left { + left: 0px; + bottom: 0px; +} + +.jGrowl.bottom-right { + right: 0px; + bottom: 0px; +} + +.jGrowl.center { + top: 0px; + width: 50%; + left: 25%; +} + +/** Cross Browser Styling **/ +.center .jGrowl-notification, .center .jGrowl-closer { + margin-left: auto; + margin-right: auto; +} + +.jGrowl .jGrowl-notification, .jGrowl .jGrowl-closer { + background-color: #000; + opacity: .85; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=85); + zoom: 1; + width: 235px; + padding: 10px; + margin-top: 5px; + margin-bottom: 5px; + font-family: Tahoma, Arial, Helvetica, sans-serif; + font-size: 1em; + text-align: left; + display: none; + border-radius: 5px; +} + +.jGrowl .jGrowl-notification { + min-height: 40px; +} + +.jGrowl .jGrowl-notification, +.jGrowl .jGrowl-closer { + margin: 10px; +} + +.jGrowl .jGrowl-notification .jGrowl-header { + font-weight: bold; + font-size: .85em; +} + +.jGrowl .jGrowl-notification .jGrowl-close { + z-index: 99; + float: right; + font-weight: bold; + font-size: 1em; + cursor: pointer; +} + +.jGrowl .jGrowl-closer { + padding-top: 4px; + padding-bottom: 4px; + cursor: pointer; + font-size: .9em; + font-weight: bold; + text-align: center; +} + +/** Hide jGrowl when printing **/ +@media print { + .jGrowl { + display: none; + } +} + +/** jGrowl End **/ diff --git a/Upload/admin/styles/default/modal.css b/Upload/admin/styles/default/modal.css new file mode 100644 index 0000000..040101f --- /dev/null +++ b/Upload/admin/styles/default/modal.css @@ -0,0 +1,45 @@ + +.modal { + display: none; + width: 400px; + text-align: left; + background: #fff; + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + -o-border-radius: 8px; + -ms-border-radius: 8px; + border-radius: 8px; + -webkit-box-shadow: 0 0 10px #000; + -moz-box-shadow: 0 0 10px #000; + -o-box-shadow: 0 0 10px #000; + -ms-box-shadow: 0 0 10px #000; + box-shadow: 0 0 10px #000; +} + +.modal a.close-modal { + position: absolute; + top: -12.5px; + right: -12.5px; + display: block; + width: 30px; + height: 30px; + text-indent: -9999px; + background: url(images/close.png) no-repeat 0 0; +} + +.modal-spinner { + display: none; + width: 64px; + height: 64px; + position: fixed; + top: 50%; + left: 50%; + margin-right: -32px; + margin-top: -32px; + background: url(images/spinner.gif) #111 no-repeat center center; + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + -o-border-radius: 8px; + -ms-border-radius: 8px; + border-radius: 8px; +} diff --git a/Upload/admin/styles/default/popup.css b/Upload/admin/styles/default/popup.css new file mode 100644 index 0000000..0202c10 --- /dev/null +++ b/Upload/admin/styles/default/popup.css @@ -0,0 +1,32 @@ +body { + background: #f7f7f7; + padding: 5px; +} + +#popup_container { + background: #fff; + padding: 5px; +} + +#content { + margin: 0; + padding: 0; +} + +.popup_title { + font-family: 'Lucida Grande', 'Trebuchet MS', Verdana, Sans-Serif; + font-size: 170%; + letter-spacing: -1px; + font-weight: bold; + color: #666; + margin: 0 0 5px 0; + border-bottom: 2px solid #999; +} + +.close_link { + float: right; + font-size: 13px; + margin-top: 7px; + font-weight: normal; + letter-spacing: normal; +} \ No newline at end of file diff --git a/Upload/admin/styles/default/style.css b/Upload/admin/styles/default/style.css new file mode 100644 index 0000000..562f833 --- /dev/null +++ b/Upload/admin/styles/default/style.css @@ -0,0 +1,42 @@ +#templatebox { + position: absolute; + top: 40px; + left: 0; + width: 100%; + z-index: 100; + text-align: center; + line-height: 0; +} + +#fader{ + position: absolute; + top: 0; + left: 0; + z-index: 90; + width: 100%; + height: 500px; + background-color: #000; + filter:alpha(opacity=60); + -moz-opacity: 0.6; + opacity: 0.6; +} + +#outerContainer { + position: relative; + background-color: #fff; + width: 70%; + height: 300px; + margin: 0 auto; +} + +ins, del { + color: #000; + padding: 2px; + line-height: 1.5em; + text-decoration: none; + background: #dfd; +} + +del { + background: #fdd; +} \ No newline at end of file diff --git a/Upload/admin/styles/default/style.php b/Upload/admin/styles/default/style.php new file mode 100644 index 0000000..40b1086 --- /dev/null +++ b/Upload/admin/styles/default/style.php @@ -0,0 +1,82 @@ +{$title}"; + * } + * } + * + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

Please make sure IN_MYBB is defined."); +} + +class Page extends DefaultPage +{ + function _generate_breadcrumb() + { + if(!is_array($this->_breadcrumb_trail)) + { + return false; + } + $trail = ""; + foreach($this->_breadcrumb_trail as $key => $crumb) + { + if($this->_breadcrumb_trail[$key+1]) + { + $trail .= "
".$crumb['name'].""; + if($this->_breadcrumb_trail[$key+2]) + { + $trail .= " » "; + } + } + else + { + $trail .= " » ".$crumb['name'].""; + } + } + return $trail; + } +} + +class SidebarItem extends DefaultSidebarItem +{ +} + +class PopupMenu extends DefaultPopupMenu +{ +} + +class Table extends DefaultTable +{ +} + +class Form extends DefaultForm +{ +} + +class FormContainer extends DefaultFormContainer +{ +} diff --git a/Upload/admin/styles/default/user.css b/Upload/admin/styles/default/user.css new file mode 100644 index 0000000..dfb7b74 --- /dev/null +++ b/Upload/admin/styles/default/user.css @@ -0,0 +1,57 @@ +.user_settings_bit { + margin-bottom: 8px; +} + +.user_settings_bit input { + vertical-align: middle; + margin-right: 8px; +} + +.user_settings_bit select { + margin-top: 8px; +} + +.user_settings_bit label { + font-weight: normal; +} + +.group_settings_bit { + margin-bottom: 8px; +} + +.group_settings_bit input { + vertical-align: middle; + margin-right: 8px; +} + +.group_settings_bit select, +.group_settings_bit input.text_input, +.group_settings_bit textarea { + margin-top: 8px; +} + +.group_settings_bit label { + font-weight: normal; +} + +.group_settings_bit small { + padding-left: 25px; +} + +.group_settings_bit small.input { + padding-left: 0; +} +#tab_general td td { + border: 0; + padding: 0 4px; +} + +.view_fields #fields_enabled, .view_fields #fields_disabled { + min-height: 300px; +} + +#fields_enabled li, #fields_disabled li { + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} \ No newline at end of file diff --git a/Upload/admin/styles/index.html b/Upload/admin/styles/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/admin/styles/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/announcements.php b/Upload/announcements.php new file mode 100644 index 0000000..b2834c3 --- /dev/null +++ b/Upload/announcements.php @@ -0,0 +1,126 @@ +load("announcements"); + +$aid = $mybb->get_input('aid', 1); + +// Get announcement fid +$query = $db->simple_select("announcements", "fid", "aid='$aid'"); +$announcement = $db->fetch_array($query); + +$plugins->run_hooks("announcements_start"); + +if(!$announcement) +{ + error($lang->error_invalidannouncement); +} + +// Get forum info +$fid = $announcement['fid']; +if($fid > 0) +{ + $forum = get_forum($fid); + + if(!$forum) + { + error($lang->error_invalidforum); + } + + // Make navigation + build_forum_breadcrumb($forum['fid']); + + // Permissions + $forumpermissions = forum_permissions($forum['fid']); + + if($forumpermissions['canview'] == 0 || $forumpermissions['canviewthreads'] == 0) + { + error_no_permission(); + } + + // Check if this forum is password protected and we have a valid password + check_forum_password($forum['fid']); +} +add_breadcrumb($lang->nav_announcements); + +$archive_url = build_archive_link("announcement", $aid); + +// Get announcement info +$time = TIME_NOW; + +$query = $db->query(" + SELECT u.*, u.username AS userusername, a.*, f.* + FROM ".TABLE_PREFIX."announcements a + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=a.uid) + LEFT JOIN ".TABLE_PREFIX."userfields f ON (f.ufid=u.uid) + WHERE a.startdate<='$time' AND (a.enddate>='$time' OR a.enddate='0') AND a.aid='$aid' +"); + +$announcementarray = $db->fetch_array($query); + +if(!$announcementarray) +{ + error($lang->error_invalidannouncement); +} + +// Gather usergroup data from the cache +// Field => Array Key +$data_key = array( + 'title' => 'grouptitle', + 'usertitle' => 'groupusertitle', + 'stars' => 'groupstars', + 'starimage' => 'groupstarimage', + 'image' => 'groupimage', + 'namestyle' => 'namestyle', + 'usereputationsystem' => 'usereputationsystem' +); + +foreach($data_key as $field => $key) +{ + $announcementarray[$key] = $groupscache[$announcementarray['usergroup']][$field]; +} + +$announcementarray['dateline'] = $announcementarray['startdate']; +$announcementarray['userusername'] = $announcementarray['username']; +$announcement = build_postbit($announcementarray, 3); +$announcementarray['subject'] = $parser->parse_badwords($announcementarray['subject']); +$lang->forum_announcement = $lang->sprintf($lang->forum_announcement, htmlspecialchars_uni($announcementarray['subject'])); + +if($announcementarray['startdate'] > $mybb->user['lastvisit']) +{ + $setcookie = true; + if(isset($mybb->cookies['mybb']['announcements']) && is_scalar($mybb->cookies['mybb']['announcements'])) + { + $cookie = my_unserialize(stripslashes($mybb->cookies['mybb']['announcements'])); + + if(isset($cookie[$announcementarray['aid']])) + { + $setcookie = false; + } + } + + if($setcookie) + { + my_set_array_cookie('announcements', $announcementarray['aid'], $announcementarray['startdate'], -1); + } +} + +$plugins->run_hooks("announcements_end"); + +eval("\$forumannouncement = \"".$templates->get("announcement")."\";"); +output_page($forumannouncement); diff --git a/Upload/archive/global.php b/Upload/archive/global.php new file mode 100644 index 0000000..b96d7fb --- /dev/null +++ b/Upload/archive/global.php @@ -0,0 +1,222 @@ +read("usergroups"); +if(!is_array($groupscache)) +{ + $cache->update_usergroups(); + $groupscache = $cache->read("usergroups"); +} +$fpermissioncache = $cache->read("forumpermissions"); + +// Send headers before anything else. +send_page_headers(); + +// If the installer has not been removed and no lock exists, die. +if(is_dir(MYBB_ROOT."install") && !file_exists(MYBB_ROOT."install/lock")) +{ + echo "Please remove the install directory from your server, or create a file called 'lock' in the install directory. Until you do so, your board will remain unaccessable"; + exit; +} + +// If the server OS is not Windows and not Apache or the PHP is running as a CGI or we have defined ARCHIVE_QUERY_STRINGS, use query strings - DIRECTORY_SEPARATOR checks if running windows +//if((DIRECTORY_SEPARATOR != '\\' && stripos($_SERVER['SERVER_SOFTWARE'], 'apache') == false) || stripos(SAPI_NAME, 'cgi') !== false || defined("ARCHIVE_QUERY_STRINGS")) +// http://dev.mybb.com/issues/1489 - remove automatic detection and rely on users to set the right option here +if($mybb->settings['seourls_archive'] == 1) +{ + if($_SERVER['REQUEST_URI']) + { + $url = $_SERVER['REQUEST_URI']; + } + elseif($_SERVER['REDIRECT_URL']) + { + $url = $_SERVER['REDIRECT_URL']; + } + elseif($_SERVER['PATH_INFO']) + { + $url = $_SERVER['PATH_INFO']; + } + else + { + $url = $_SERVER['PHP_SELF']; + } + $base_url = $mybb->settings['bburl']."/archive/index.php/"; + $endpart = my_substr(strrchr($url, "/"), 1); +} +else +{ + $url = $_SERVER['QUERY_STRING']; + $base_url = $mybb->settings['bburl']."/archive/index.php?"; + $endpart = $url; +} + +$action = "index"; + +// This seems to work the same as the block below except without the css bugs O_o +$archiveurl = $mybb->settings['bburl'].'/archive'; + +if($endpart != "index.php") +{ + $endpart = str_replace(".html", "", $endpart); + $todo = explode("-", $endpart, 3); + if($todo[0]) + { + $action = $action2 = $todo[0]; + } + if(!empty($todo[2])) + { + $page = (int)$todo[2]; + } + else + { + $page = 1; + } + if(!empty($todo[1])) + { + $id = (int)$todo[1]; + } + else + { + $id = 0; + } + + // Get the thread, announcement or forum information. + if($action == "announcement") + { + $time = TIME_NOW; + $query = $db->query(" + SELECT a.*, u.username + FROM ".TABLE_PREFIX."announcements a + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=a.uid) + WHERE a.aid='{$id}' AND startdate < '{$time}' AND (enddate > '{$time}' OR enddate = 0) + "); + $announcement = $db->fetch_array($query); + if(!$announcement['aid']) + { + $action = "404"; + } + } + elseif($action == "thread") + { + $query = $db->simple_select("threads", "*", "tid='{$id}' AND closed NOT LIKE 'moved|%'"); + $thread = $db->fetch_array($query); + if(!$thread['tid']) + { + $action = "404"; + } + } + elseif($action == "forum") + { + $query = $db->simple_select("forums", "*", "fid='{$id}' AND active!=0 AND password=''"); + $forum = $db->fetch_array($query); + if(!$forum['fid']) + { + $action = "404"; + } + } + elseif($action != 'index') + { + $action = "404"; + } +} + +// Define the full MyBB version location of this page. +if($action == "thread") +{ + define('MYBB_LOCATION', get_thread_link($id)); +} +elseif($action == "forum") +{ + define('MYBB_LOCATION', get_forum_link($id)); +} +elseif($action == "announcement") +{ + define('MYBB_LOCATION', get_announcement_link($id)); +} +else +{ + define('MYBB_LOCATION', INDEX_URL); +} + +// Initialise session +$session = new session; +$session->init(); + +if(!$mybb->settings['bblanguage']) +{ + $mybb->settings['bblanguage'] = "english"; +} +$lang->set_language($mybb->settings['bblanguage']); + +// Load global language phrases +$lang->load("global"); +$lang->load("messages"); +$lang->load("archive"); + +// Draw up the basic part of our naviagation +$navbits[0]['name'] = $mybb->settings['bbname_orig']; +$navbits[0]['url'] = $mybb->settings['bburl']."/archive/index.php"; + +// Check banned ip addresses +if(is_banned_ip($session->ipaddress)) +{ + archive_error($lang->error_banned); +} + +// If our board is closed.. +if($mybb->settings['boardclosed'] == 1) +{ + if($mybb->usergroup['canviewboardclosed'] != 1) + { + $lang->error_boardclosed .= "
".$mybb->settings['boardclosed_reason']."
"; + archive_error($lang->error_boardclosed); + } +} + +// Do we require users to login? +if($mybb->settings['forcelogin'] == 1) +{ + if($mybb->user['uid'] == 0) + { + archive_error($lang->error_mustlogin); + } +} + +// Load Limiting - DIRECTORY_SEPARATOR checks if running windows +if(DIRECTORY_SEPARATOR != '\\') +{ + if($uptime = @exec('uptime')) + { + preg_match("/averages?: ([0-9\.]+),[\s]+([0-9\.]+),[\s]+([0-9\.]+)/", $uptime, $regs); + $load = $regs[1]; + if($mybb->usergroup['cancp'] != 1 && $load > $mybb->settings['load'] && $mybb->settings['load'] > 0) + { + archive_error($lang->error_loadlimit); + } + } +} + +if($mybb->usergroup['canview'] == 0) +{ + archive_error_no_permission(); +} diff --git a/Upload/archive/index.php b/Upload/archive/index.php new file mode 100644 index 0000000..87eae76 --- /dev/null +++ b/Upload/archive/index.php @@ -0,0 +1,515 @@ +load("index"); + +$plugins->run_hooks("archive_start"); + +switch($action) +{ + // Display an announcement. + case "announcement": + // Fetch the forum this thread is in + if($announcement['fid'] != -1) + { + $forum = get_forum($announcement['fid']); + if(!$forum['fid'] || $forum['password'] != '') + { + archive_error($lang->error_invalidforum); + } + + // Check if we have permission to view this thread + $forumpermissions = forum_permissions($forum['fid']); + if($forumpermissions['canview'] != 1 || $forumpermissions['canviewthreads'] != 1) + { + archive_error_no_permission(); + } + + check_forum_password_archive($forum['fid']); + } + + $announcement['subject'] = htmlspecialchars_uni($parser->parse_badwords($announcement['subject'])); + + $parser_options = array( + "allow_html" => $announcement['allowhtml'], + "allow_mycode" => $announcement['allowmycode'], + "allow_smilies" => $announcement['allowsmilies'], + "allow_imgcode" => 1, + "allow_videocode" => 1, + "me_username" => $announcement['username'], + "filter_badwords" => 1 + ); + + $announcement['message'] = $parser->parse_message($announcement['message'], $parser_options); + + $profile_link = build_profile_link($announcement['username'], $announcement['uid']); + + // Build the navigation + add_breadcrumb($announcement['subject']); + archive_header($announcement['subject'], $announcement['subject'], $mybb->settings['bburl']."/announcements.php?aid={$id}"); + + // Format announcement contents. + $announcement['startdate'] = my_date('relative', $announcement['startdate']); + + $plugins->run_hooks("archive_announcement_start"); + + echo "
\n
\n

{$announcement['subject']} - {$profile_link}

"; + echo "
{$announcement['startdate']}
\n
\n
{$announcement['message']}
\n
\n"; + + $plugins->run_hooks("archive_announcement_end"); + + archive_footer(); + break; + + // Display a thread. + case "thread": + $thread['subject'] = htmlspecialchars_uni($parser->parse_badwords($thread['subject'])); + + // Fetch the forum this thread is in + $forum = get_forum($thread['fid']); + if(!$forum['fid'] || $forum['password'] != '') + { + archive_error($lang->error_invalidforum); + } + + // Check if we have permission to view this thread + $forumpermissions = forum_permissions($forum['fid']); + if($forumpermissions['canview'] != 1 || $forumpermissions['canviewthreads'] != 1) + { + archive_error_no_permission(); + } + + if($thread['visible'] != 1) + { + if(is_moderator($forum['fid'], "canviewunapprove")) + { + archive_error($lang->sprintf($lang->error_unapproved_thread, $mybb->settings['bburl']."/".get_thread_link($thread['tid'], $page))); + } + else + { + archive_error($lang->error_invalidthread); + } + } + + if(isset($forumpermissions['canonlyviewownthreads']) && $forumpermissions['canonlyviewownthreads'] == 1 && $thread['uid'] != $mybb->user['uid']) + { + archive_error_no_permission(); + } + + check_forum_password_archive($forum['fid']); + + // Build the navigation + build_forum_breadcrumb($forum['fid'], 1); + add_breadcrumb($thread['subject']); + + archive_header($thread['subject'], $thread['subject'], $mybb->settings['bburl']."/".get_thread_link($thread['tid'], $page)); + + $plugins->run_hooks("archive_thread_start"); + + // Paginate this thread + if(!$mybb->settings['postsperpage'] || (int)$mybb->settings['postsperpage'] < 1) + { + $mybb->settings['postsperpage'] = 20; + } + $perpage = $mybb->settings['postsperpage']; + $postcount = (int)$thread['replies']+1; + $pages = ceil($postcount/$perpage); + + if($page > $pages) + { + $page = 1; + } + if($page) + { + $start = ($page-1) * $perpage; + } + else + { + $start = 0; + $page = 1; + } + + $pids = array(); + // Fetch list of post IDs to be shown + $query = $db->simple_select("posts", "pid", "tid='{$id}' AND visible='1'", array('order_by' => 'dateline', 'limit_start' => $start, 'limit' => $perpage)); + while($post = $db->fetch_array($query)) + { + $pids[$post['pid']] = $post['pid']; + } + + if(empty($pids)) + { + archive_error($lang->error_invalidthread); + } + + archive_multipage($postcount, $perpage, $page, "{$base_url}thread-$id"); + + $pids = implode(",", $pids); + + if($pids && $mybb->settings['enableattachments'] == 1) + { + // Build attachments cache + $query = $db->simple_select("attachments", "*", "pid IN ({$pids})"); + while($attachment = $db->fetch_array($query)) + { + $acache[$attachment['pid']][$attachment['aid']] = $attachment; + } + } + + // Start fetching the posts + $query = $db->query(" + SELECT u.*, u.username AS userusername, p.* + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) + WHERE p.pid IN ({$pids}) + ORDER BY p.dateline + "); + while($post = $db->fetch_array($query)) + { + $post['date'] = my_date('relative', $post['dateline']); + if($post['userusername']) + { + $post['username'] = $post['userusername']; + } + + // Parse the message + $parser_options = array( + "allow_html" => $forum['allowhtml'], + "allow_mycode" => $forum['allowmycode'], + "allow_smilies" => $forum['allowsmilies'], + "allow_imgcode" => $forum['allowimgcode'], + "allow_videocode" => $forum['allowvideocode'], + "me_username" => $post['username'], + "filter_badwords" => 1 + ); + if($post['smilieoff'] == 1) + { + $parser_options['allow_smilies'] = 0; + } + + $post['message'] = $parser->parse_message($post['message'], $parser_options); + + // Is there an attachment in this post? + if($mybb->settings['enableattachments'] == 1 && isset($acache[$post['pid']]) && is_array($acache[$post['pid']])) + { + foreach($acache[$post['pid']] as $aid => $attachment) + { + $post['message'] = str_replace("[attachment={$attachment['aid']}]", "[settings['bburl']."/attachment.php?aid={$attachment['aid']}\">attachment={$attachment['aid']}]", $post['message']); + } + } + + // Damn thats a lot of parsing, now to determine which username to show.. + if($post['userusername']) + { + $post['username'] = $post['userusername']; + } + $post['username'] = build_profile_link($post['username'], $post['uid']); + + $plugins->run_hooks("archive_thread_post"); + + // Finally show the post + echo "
\n
\n

{$post['username']}

"; + echo "
{$post['date']}
\n
\n
{$post['message']}
\n
\n"; + } + archive_multipage($postcount, $perpage, $page, "{$base_url}thread-$id"); + + $plugins->run_hooks("archive_thread_end"); + + archive_footer(); + break; + + // Display a category or a forum. + case "forum": + // Check if we have permission to view this forum + $forumpermissions = forum_permissions($forum['fid']); + if($forumpermissions['canview'] != 1) + { + archive_error_no_permission(); + } + + check_forum_password_archive($forum['fid']); + + $useronly = ""; + if(isset($forumpermissions['canonlyviewownthreads']) && $forumpermissions['canonlyviewownthreads'] == 1) + { + $useronly = "AND uid={$mybb->user['uid']}"; + } + + // Paginate this forum + $query = $db->simple_select("threads", "COUNT(tid) AS threads", "fid='{$id}' AND visible='1' {$useronly}"); + $threadcount = $db->fetch_field($query, "threads"); + + // Build the navigation + build_forum_breadcrumb($forum['fid'], 1); + + // No threads and not a category? Error! + if(($threadcount < 1 || $forumpermissions['canviewthreads'] != 1) && $forum['type'] != 'c') + { + archive_header(strip_tags($forum['name']), $forum['name'], $mybb->settings['bburl']."/".get_forum_link($id, $page).""); + archive_error($lang->error_nothreads); + } + + // Build the archive header. + archive_header(strip_tags($forum['name']), $forum['name'], $mybb->settings['bburl']."/".get_forum_link($id, $page), 1); + + $plugins->run_hooks("archive_forum_start"); + + if(!$mybb->settings['threadsperpage'] || (int)$mybb->settings['threadsperpage'] < 1) + { + $mybb->settings['threadsperpage'] = 20; + } + + $perpage = $mybb->settings['threadsperpage']; + $pages = ceil($threadcount/$perpage); + if($page > $pages) + { + $page = 1; + } + + if($page > 0) + { + $start = ($page-1) * $perpage; + } + else + { + $start = 0; + $page = 1; + } + + // Decide what type of listing to show. + if($forum['type'] == 'f') + { + echo "
\n

{$forum['name']}

\n"; + } + elseif($forum['type'] == 'c') + { + echo "
\n

{$forum['name']}

\n"; + } + + // Show subforums. + $query = $db->simple_select("forums", "COUNT(fid) AS subforums", "pid='{$id}'"); + $subforumcount = $db->fetch_field($query, "subforums"); + if($subforumcount > 0) + { + echo "
\n"; + echo "

{$lang->subforums}

\n"; + echo "
    \n"; + $forums = build_archive_forumbits($forum['fid']); + echo $forums; + echo "
\n
\n"; + } + + archive_multipage($threadcount, $perpage, $page, "{$base_url}forum-$id"); + + // Get the announcements if the forum is not a category. + if($forum['type'] == 'f') + { + $sql = build_parent_list($forum['fid'], "fid", "OR", $forum['parentlist']); + $time = TIME_NOW; + $query = $db->simple_select("announcements", "*", "startdate < '{$time}' AND (enddate > '{$time}' OR enddate=0) AND ({$sql} OR fid='-1')"); + if($db->num_rows($query) > 0) + { + echo "
\n"; + echo "

{$lang->forumbit_announcements}

"; + echo "
    \n"; + while($announcement = $db->fetch_array($query)) + { + $announcement['subject'] = $parser->parse_badwords($announcement['subject']); + echo "
  1. ".htmlspecialchars_uni($announcement['subject'])."
  2. "; + } + echo "
\n
\n"; + } + + } + + // Get the stickies if the forum is not a category. + if($forum['type'] == 'f') + { + $options = array( + 'order_by' => 'sticky, lastpost', + 'order_dir' => 'desc', + 'limit_start' => $start, + 'limit' => $perpage + ); + $query = $db->simple_select("threads", "*", "fid='{$id}' AND visible='1' AND sticky='1' AND closed NOT LIKE 'moved|%' {$useronly}", $options); + if($db->num_rows($query) > 0) + { + echo "
\n"; + echo "

{$lang->forumbit_stickies}

"; + echo "
    \n"; + while($sticky = $db->fetch_array($query)) + { + $sticky['subject'] = htmlspecialchars_uni($parser->parse_badwords($sticky['subject'])); + if($sticky['replies'] != 1) + { + $lang_reply_text = $lang->archive_replies; + } + else + { + $lang_reply_text = $lang->archive_reply; + } + + $plugins->run_hooks("archive_forum_thread"); + + $sticky['replies'] = my_number_format($sticky['replies']); + + echo "
  1. {$sticky['subject']}"; + echo " ({$sticky['replies']} {$lang_reply_text})
  2. "; + } + echo "
\n
\n"; + } + } + + // Get the threads if the forum is not a category. + if($forum['type'] == 'f') + { + $options = array( + 'order_by' => 'sticky, lastpost', + 'order_dir' => 'desc', + 'limit_start' => $start, + 'limit' => $perpage + ); + $query = $db->simple_select("threads", "*", "fid='{$id}' AND visible='1' AND sticky='0' AND closed NOT LIKE 'moved|%' {$useronly}", $options); + if($db->num_rows($query) > 0) + { + echo "
\n"; + echo "

{$lang->forumbit_threads}

"; + echo "
    \n"; + while($thread = $db->fetch_array($query)) + { + $thread['subject'] = htmlspecialchars_uni($parser->parse_badwords($thread['subject'])); + if($thread['replies'] != 1) + { + $lang_reply_text = $lang->archive_replies; + } + else + { + $lang_reply_text = $lang->archive_reply; + } + + $plugins->run_hooks("archive_forum_thread"); + + $thread['replies'] = my_number_format($thread['replies']); + + echo "
  1. {$thread['subject']}"; + echo " ({$thread['replies']} {$lang_reply_text})
  2. "; + } + echo "
\n
\n"; + } + } + + echo "
\n"; + + archive_multipage($threadcount, $perpage, $page, "{$base_url}forum-$id"); + + $plugins->run_hooks("archive_forum_end"); + + archive_footer(); + break; + + // Display the board home. + case "index": + // Build our forum listing + $forums = build_archive_forumbits(0); + archive_header("", $mybb->settings['bbname_orig'], $mybb->settings['bburl']."/index.php"); + + $plugins->run_hooks("archive_index_start"); + + echo "
\n
{$mybb->settings['bbname']}
\n
\n
    \n"; + echo $forums; + echo "\n
\n
\n
"; + + $plugins->run_hooks("archive_index_end"); + + archive_footer(); + break; + default: + header("HTTP/1.0 404 Not Found"); + switch($action2) + { + case "announcement": + archive_error($lang->error_invalidannouncement); + case "thread": + archive_error($lang->error_invalidthread); + case "forum": + archive_error($lang->error_invalidforum); + default: + archive_error($lang->archive_not_found); + } +} + +$plugins->run_hooks("archive_end"); + +/** +* Gets a list of forums and possibly subforums. +* +* @param int The parent forum to get the childforums for. +* @return array Array of information regarding the child forums of this parent forum +*/ +function build_archive_forumbits($pid=0) +{ + global $db, $forumpermissions, $mybb, $base_url; + + // Sort out the forum cache first. + static $fcache; + if(!is_array($fcache)) + { + // Fetch forums + $query = $db->simple_select("forums", "*", "active!=0 AND password=''", array('order_by' =>'pid, disporder')); + while($forum = $db->fetch_array($query)) + { + $fcache[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum; + } + $forumpermissions = forum_permissions(); + } + + $forums = ''; + + // Start the process. + if(is_array($fcache[$pid])) + { + foreach($fcache[$pid] as $key => $main) + { + foreach($main as $key => $forum) + { + $perms = $forumpermissions[$forum['fid']]; + if(($perms['canview'] == 1 || $mybb->settings['hideprivateforums'] == 0) && $forum['active'] != 0) + { + if($forum['linkto']) + { + $forums .= "
  • {$forum['name']}"; + } + elseif($forum['type'] == "c") + { + $forums .= "
  • {$forum['name']}"; + } + else + { + $forums .= "
  • {$forum['name']}"; + } + if(!empty($fcache[$forum['fid']])) + { + $forums .= "\n
      \n"; + $forums .= build_archive_forumbits($forum['fid']); + $forums .= "
    \n"; + } + $forums .= "
  • \n"; + } + } + } + } + return $forums; +} diff --git a/Upload/archive/print.css b/Upload/archive/print.css new file mode 100644 index 0000000..56df4ef --- /dev/null +++ b/Upload/archive/print.css @@ -0,0 +1,144 @@ +body { + background: #fff; + color: #000; + font: small Verdana; +} + +#container { + border: 1px solid #ccc; + background: #fff; + padding: 20px; +} + +h1 { + font-family: 'Trebuchet MS', 'Lucida Grande', Verdana, Arial, Sans-Serif; + font-weight: bold; + color: #000; +} +h1 a { + color: #000; + text-decoration: none; +} + +.navigation { + border: 1px solid #ccc; + background: #F5F5F4; + padding: 4px; + margin-bottom: 10px; + font-size: 13px; +} + +#infobox { + padding: 4px; + color: #777; + font-size: 0.8em; + margin-bottom: 10px; +} + +#fullversion { + font-size: 1.1em; +} + +.post { + border: 1px solid #ccc; + padding: 1px; + background: #F5F5F4; + margin-bottom: 10px; +} + +.post .header { + background: #F5F5F4; +} + +.post .header .author a { + color: #000; + text-decoration: none; +} + +.post .header .dateline { + padding: 4px; + color: #777; + float: right; + margin-top: -20px; +} + +.post .message { + background: #fff; + padding: 4px; +} + +.listing { + border: 1px solid #ccc; + margin-bottom: 10px; +} + +.header { + background: #F5F5F4; + font-weight: bold; + padding: 4px; + border-bottom: 1px solid #ccc; +} + +.threadlist .threads { + padding: 4px; +} + +.threadlist .threads .replycount { + color: #777; + font-size: 0.8em; +} + +.header h2 { + font-size: 1.0em; + margin: 0; +} + +h3 { + font-size: 1.0em; + margin: 5px 0 0 10px; +} + +.forumlist .forums ul { + list-style: none; +} + +.error { + border: 1px solid #ccc; + margin-bottom: 10px; +} + +.error .header { + background: #F5F5F4; + font-weight: bold; + padding: 4px; + border-bottom: 1px solid #ccc; +} + +.error .message { + padding: 4px; +} + +.multipage { + background: #F5F5F4; + border: 1px solid #ccc; + margin-bottom: 10px; + padding: 4px; +} + +#printinfo { + display: none; +} + +#footer { + padding-top: 10px; + text-align: center; + font-size: 0.8em; +} + +#footer a { + color: #000; +} + +.quote_body, .code_body { + margin-left: 18px; +} \ No newline at end of file diff --git a/Upload/archive/screen.css b/Upload/archive/screen.css new file mode 100644 index 0000000..56df4ef --- /dev/null +++ b/Upload/archive/screen.css @@ -0,0 +1,144 @@ +body { + background: #fff; + color: #000; + font: small Verdana; +} + +#container { + border: 1px solid #ccc; + background: #fff; + padding: 20px; +} + +h1 { + font-family: 'Trebuchet MS', 'Lucida Grande', Verdana, Arial, Sans-Serif; + font-weight: bold; + color: #000; +} +h1 a { + color: #000; + text-decoration: none; +} + +.navigation { + border: 1px solid #ccc; + background: #F5F5F4; + padding: 4px; + margin-bottom: 10px; + font-size: 13px; +} + +#infobox { + padding: 4px; + color: #777; + font-size: 0.8em; + margin-bottom: 10px; +} + +#fullversion { + font-size: 1.1em; +} + +.post { + border: 1px solid #ccc; + padding: 1px; + background: #F5F5F4; + margin-bottom: 10px; +} + +.post .header { + background: #F5F5F4; +} + +.post .header .author a { + color: #000; + text-decoration: none; +} + +.post .header .dateline { + padding: 4px; + color: #777; + float: right; + margin-top: -20px; +} + +.post .message { + background: #fff; + padding: 4px; +} + +.listing { + border: 1px solid #ccc; + margin-bottom: 10px; +} + +.header { + background: #F5F5F4; + font-weight: bold; + padding: 4px; + border-bottom: 1px solid #ccc; +} + +.threadlist .threads { + padding: 4px; +} + +.threadlist .threads .replycount { + color: #777; + font-size: 0.8em; +} + +.header h2 { + font-size: 1.0em; + margin: 0; +} + +h3 { + font-size: 1.0em; + margin: 5px 0 0 10px; +} + +.forumlist .forums ul { + list-style: none; +} + +.error { + border: 1px solid #ccc; + margin-bottom: 10px; +} + +.error .header { + background: #F5F5F4; + font-weight: bold; + padding: 4px; + border-bottom: 1px solid #ccc; +} + +.error .message { + padding: 4px; +} + +.multipage { + background: #F5F5F4; + border: 1px solid #ccc; + margin-bottom: 10px; + padding: 4px; +} + +#printinfo { + display: none; +} + +#footer { + padding-top: 10px; + text-align: center; + font-size: 0.8em; +} + +#footer a { + color: #000; +} + +.quote_body, .code_body { + margin-left: 18px; +} \ No newline at end of file diff --git a/Upload/attachment.php b/Upload/attachment.php new file mode 100644 index 0000000..63b608a --- /dev/null +++ b/Upload/attachment.php @@ -0,0 +1,187 @@ +settings['enableattachments'] != 1) +{ + error($lang->attachments_disabled); +} + +// Find the AID we're looking for +if(isset($mybb->input['thumbnail'])) +{ + $aid = $mybb->get_input('thumbnail', 1); +} +else +{ + $aid = $mybb->get_input('aid', 1); +} + +$pid = $mybb->get_input('pid', 1); + +// Select attachment data from database +if($aid) +{ + $query = $db->simple_select("attachments", "*", "aid='{$aid}'"); +} +else +{ + $query = $db->simple_select("attachments", "*", "pid='{$pid}'"); +} +$attachment = $db->fetch_array($query); + +$plugins->run_hooks("attachment_start"); + +if(!$attachment) +{ + error($lang->error_invalidattachment); +} + +if($attachment['thumbnail'] == '' && isset($mybb->input['thumbnail'])) +{ + error($lang->error_invalidattachment); +} + +$pid = $attachment['pid']; + +// Don't check the permissions on preview +if($pid || $attachment['uid'] != $mybb->user['uid']) +{ + $post = get_post($pid); + $thread = get_thread($post['tid']); + + if(!$thread && !isset($mybb->input['thumbnail'])) + { + error($lang->error_invalidthread); + } + $fid = $thread['fid']; + + // Get forum info + $forum = get_forum($fid); + + // Permissions + $forumpermissions = forum_permissions($fid); + + if($forumpermissions['canview'] == 0 || $forumpermissions['canviewthreads'] == 0 || (isset($forumpermissions['canonlyviewownthreads']) && $forumpermissions['canonlyviewownthreads'] != 0 && $thread['uid'] != $mybb->user['uid']) || ($forumpermissions['candlattachments'] == 0 && !$mybb->input['thumbnail'])) + { + error_no_permission(); + } + + // Error if attachment is invalid or not visible + if(!$attachment['attachname'] || (!is_moderator($fid, "canviewunapprove") && ($attachment['visible'] != 1 || $thread['visible'] != 1 || $post['visible'] != 1))) + { + error($lang->error_invalidattachment); + } +} + +if(!isset($mybb->input['thumbnail'])) // Only increment the download count if this is not a thumbnail +{ + $attachupdate = array( + "downloads" => $attachment['downloads']+1, + ); + $db->update_query("attachments", $attachupdate, "aid='{$attachment['aid']}'"); +} + +// basename isn't UTF-8 safe. This is a workaround. +$attachment['filename'] = ltrim(basename(' '.$attachment['filename'])); + +$plugins->run_hooks("attachment_end"); + +if(isset($mybb->input['thumbnail'])) +{ + $ext = get_extension($attachment['thumbnail']); + switch($ext) + { + case "gif": + $type = "image/gif"; + break; + case "bmp": + $type = "image/bmp"; + break; + case "png": + $type = "image/png"; + break; + case "jpg": + case "jpeg": + case "jpe": + $type = "image/jpeg"; + break; + default: + $type = "image/unknown"; + break; + } + + header("Content-disposition: filename=\"{$attachment['filename']}\""); + header("Content-type: ".$type); + $thumb = $mybb->settings['uploadspath']."/".$attachment['thumbnail']; + header("Content-length: ".@filesize($thumb)); + $handle = fopen($thumb, 'rb'); + while(!feof($handle)) + { + echo fread($handle, 8192); + } + fclose($handle); +} +else +{ + $ext = get_extension($attachment['filename']); + + switch($attachment['filetype']) + { + case "application/pdf": + case "image/bmp": + case "image/gif": + case "image/jpeg": + case "image/pjpeg": + case "image/png": + case "text/plain": + header("Content-type: {$attachment['filetype']}"); + $disposition = "inline"; + break; + + default: + $filetype = $attachment['filetype']; + + if(!$filetype) + { + $filetype = 'application/force-download'; + } + + header("Content-type: {$filetype}"); + $disposition = "attachment"; + } + + if(strpos(strtolower($_SERVER['HTTP_USER_AGENT']), "msie") !== false) + { + header("Content-disposition: attachment; filename=\"{$attachment['filename']}\""); + } + else + { + header("Content-disposition: {$disposition}; filename=\"{$attachment['filename']}\""); + } + + if(strpos(strtolower($_SERVER['HTTP_USER_AGENT']), "msie 6.0") !== false) + { + header("Expires: -1"); + } + + header("Content-length: {$attachment['filesize']}"); + header("Content-range: bytes=0-".($attachment['filesize']-1)."/".$attachment['filesize']); + $handle = fopen($mybb->settings['uploadspath']."/".$attachment['attachname'], 'rb'); + while(!feof($handle)) + { + echo fread($handle, 8192); + } + fclose($handle); +} diff --git a/Upload/cache/index.html b/Upload/cache/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/cache/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/cache/themes/index.html b/Upload/cache/themes/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/cache/themes/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/calendar.php b/Upload/calendar.php new file mode 100644 index 0000000..9a78030 --- /dev/null +++ b/Upload/calendar.php @@ -0,0 +1,2490 @@ +load("calendar"); + +if($mybb->settings['enablecalendar'] == 0) +{ + error($lang->calendar_disabled); +} + +if($mybb->usergroup['canviewcalendar'] == 0) +{ + error_no_permission(); +} + +$monthnames = array( + "offset", + $lang->alt_month_1, + $lang->alt_month_2, + $lang->alt_month_3, + $lang->alt_month_4, + $lang->alt_month_5, + $lang->alt_month_6, + $lang->alt_month_7, + $lang->alt_month_8, + $lang->alt_month_9, + $lang->alt_month_10, + $lang->alt_month_11, + $lang->alt_month_12 +); + +$plugins->run_hooks("calendar_start"); + +// Make navigation +add_breadcrumb($lang->nav_calendar, "calendar.php"); + +$mybb->input['calendar'] = $mybb->get_input('calendar', 1); +$calendars = cache_calendars(); + +$calendar_jump = ''; +if(count($calendars) > 1) +{ + $calendar_jump = build_calendar_jump($mybb->input['calendar']); +} + +$mybb->input['action'] = $mybb->get_input('action'); +// Add an event +if($mybb->input['action'] == "do_addevent" && $mybb->request_method == "post") +{ + $query = $db->simple_select("calendars", "*", "cid='{$mybb->input['calendar']}'"); + $calendar = $db->fetch_array($query); + + // Invalid calendar? + if(!$calendar) + { + error($lang->invalid_calendar); + } + + // Do we have permission to view this calendar or post events? + $calendar_permissions = get_calendar_permissions($calendar['cid']); + if($calendar_permissions['canviewcalendar'] != 1 || $calendar_permissions['canaddevents'] != 1) + { + error_no_permission(); + } + + // Verify incoming POST request + verify_post_check($mybb->get_input('my_post_key')); + + $plugins->run_hooks("calendar_do_addevent_start"); + + // Set up event handler. + require_once MYBB_ROOT."inc/datahandler.php"; + require_once MYBB_ROOT."inc/datahandlers/event.php"; + $eventhandler = new EventDataHandler("insert"); + + $mybb->input['type'] = $mybb->get_input('type'); + + // Prepare an array for the eventhandler. + $event = array( + "cid" => $calendar['cid'], + "uid" => $mybb->user['uid'], + "name" => $mybb->get_input('name'), + "description" => $mybb->get_input('description'), + "private" => $mybb->get_input('private', 1), + "type" => $mybb->input['type'] + ); + + // Now we add in our date/time info depending on the type of event + if($mybb->input['type'] == "single") + { + $event['start_date'] = array( + "day" => $mybb->get_input('single_day', 1), + "month" => $mybb->get_input('single_month', 1), + "year" => $mybb->get_input('single_year', 1) + ); + $event['repeats'] = ''; + } + else if($mybb->input['type'] == "ranged") + { + $event['start_date'] = array( + "day" => $mybb->get_input('start_day', 1), + "month" => $mybb->get_input('start_month', 1), + "year" => $mybb->get_input('start_year', 1), + "time" => $mybb->get_input('start_time') + ); + $event['end_date'] = array( + "day" => $mybb->get_input('end_day', 1), + "month" => $mybb->get_input('end_month', 1), + "year" => $mybb->get_input('end_year', 1), + "time" => $mybb->get_input('end_time') + ); + $event['timezone'] = $mybb->get_input('timezone'); + $event['ignoretimezone'] = $mybb->get_input('ignoretimezone', 1); + $repeats = array(); + switch($mybb->input['repeats']) + { + case 1: + $repeats['repeats'] = 1; + $repeats['days'] = $mybb->get_input('repeats_1_days', 1); + break; + case 2: + $repeats['repeats'] = 2; + break; + case 3: + $repeats['repeats'] = 3; + $repeats['weeks'] = $mybb->get_input('repeats_3_weeks', 1); + $mybb->input['repeats_3_days'] = $mybb->get_input('repeats_3_days', 2); + ksort($mybb->input['repeats_3_days']); + $days = array(); + foreach($mybb->input['repeats_3_days'] as $weekday => $value) + { + if($value != 1) + { + continue; + } + $days[] = $weekday; + } + $repeats['days'] = $days; + break; + case 4: + $repeats['repeats'] = 4; + if($mybb->get_input('repeats_4_type', 1) == 1) + { + $repeats['day'] = $mybb->get_input('repeats_4_day', 1); + $repeats['months'] = $mybb->get_input('repeats_4_months', 1); + } + else + { + $repeats['months'] = $mybb->get_input('repeats_4_months2', 1); + $repeats['occurance'] = $mybb->get_input('repeats_4_occurance'); + $repeats['weekday'] = $mybb->get_input('repeats_4_weekday', 1); + } + break; + case 5: + $repeats['repeats'] = 5; + if($mybb->get_input('repeats_5_type', 1) == 1) + { + $repeats['day'] = $mybb->get_input('repeats_5_day', 1); + $repeats['month'] = $mybb->get_input('repeats_5_month', 1); + $repeats['years'] = $mybb->get_input('repeats_5_years', 1); + } + else + { + $repeats['occurance'] = $mybb->get_input('repeats_5_occurance'); + $repeats['weekday'] = $mybb->get_input('repeats_5_weekday', 1); + $repeats['month'] = $mybb->get_input('repeats_5_month2', 1); + $repeats['years'] = $mybb->get_input('repeats_5_years', 1); + } + break; + default: + $repeats['repeats'] = 0; + } + $event['repeats'] = $repeats; + } + + $eventhandler->set_data($event); + + // Now let the eventhandler do all the hard work. + if(!$eventhandler->validate_event()) + { + $event_errors = $eventhandler->get_friendly_errors(); + $event_errors = inline_error($event_errors); + $mybb->input['action'] = "addevent"; + } + else + { + $details = $eventhandler->insert_event(); + $plugins->run_hooks("calendar_do_addevent_end"); + if($details['visible'] == 1) + { + redirect(get_event_link($details['eid']), $lang->redirect_eventadded); + } + else + { + redirect(get_calendar_link($event['cid']), $lang->redirect_eventadded_moderation); + } + } +} + +if($mybb->input['action'] == "addevent") +{ + $query = $db->simple_select("calendars", "*", "cid='".$mybb->input['calendar']."'"); + $calendar = $db->fetch_array($query); + + // Invalid calendar? + if(!$calendar['cid']) + { + error($lang->invalid_calendar); + } + + // Do we have permission to view this calendar or post events? + $calendar_permissions = get_calendar_permissions($calendar['cid']); + if($calendar_permissions['canviewcalendar'] != 1 || $calendar_permissions['canaddevents'] != 1) + { + error_no_permission(); + } + + add_breadcrumb(htmlspecialchars_uni($calendar['name']), get_calendar_link($calendar['cid'])); + add_breadcrumb($lang->nav_addevent); + + $plugins->run_hooks("calendar_addevent_start"); + + // If MyCode is on for this forum and the MyCode editor is enabled inthe Admin CP, draw the code buttons and smilie inserter. + if($mybb->settings['bbcodeinserter'] != 0 && (!$mybb->user['uid'] || $mybb->user['showcodebuttons'] != 0) && $calendar['allowmycode'] == 1) + { + $codebuttons = build_mycode_inserter("message", $calendar['allowsmilies']); + if($calendar['allowsmilies'] == 1) + { + $smilieinserter = build_clickable_smilies(); + } + } + + // Previous selections + $name = $description = ''; + if(isset($mybb->input['name'])) + { + $name = htmlspecialchars_uni($mybb->get_input('name')); + } + + if(isset($mybb->input['description'])) + { + $description = htmlspecialchars_uni($mybb->get_input('description')); + } + + $single_month = $start_month = $end_month = $repeats_sel = $repeats_3_days = $repeats_4_occurance = $repeats_4_weekday = $repeats_5_month = $repeats_5_occurance = $repeats_5_weekday = $repeats_5_month2 = array(); + foreach(range(1, 12) as $number) + { + $single_month[$number] = $start_month[$number] = $end_month[$number] = $repeats_5_month[$number] = $repeats_5_month2[$number] = ''; + } + foreach(range(1, 5) as $number) + { + $repeats_sel[$number] = ''; + } + foreach(range(0, 6) as $number) + { + $repeats_3_days[$number] = $repeats_4_weekday[$number] = $repeats_5_weekday[$number] = ''; + } + foreach(range(1, 4) as $number) + { + $repeats_4_occurance[$number] = $repeats_5_occurance[$number] = ''; + } + $repeats_4_occurance['last'] = $repeats_5_occurance['last'] = ''; + $repeats_4_type = array(1 => '', 2 => ''); + $repeats_5_type = array(1 => '', 2 => ''); + + if($mybb->request_method == "post") + { + $single_day = $mybb->get_input('single_day', 1); + $single_month[$mybb->get_input('single_month', 1)] = " selected=\"selected\""; + $single_year = $mybb->get_input('single_year', 1); + $start_day = $mybb->get_input('start_day', 1); + $start_month[$mybb->get_input('start_month', 1)] = " selected=\"selected\""; + $start_year = $mybb->get_input('start_year', 1); + $start_time = htmlspecialchars_uni($mybb->get_input('start_time')); + $end_day = $mybb->get_input('end_day', 1); + $end_month[$mybb->get_input('end_month', 1)] = " selected=\"selected\""; + $end_year = $mybb->get_input('end_year', 1); + $end_time = htmlspecialchars_uni($mybb->get_input('end_time')); + if($mybb->get_input('type') == "single") + { + $type_single = "checked=\"checked\""; + $type_ranged = ''; + $type = "single"; + } + else + { + $type_ranged = "checked=\"checked\""; + $type_single = ''; + $type = "ranged"; + } + if(!empty($mybb->input['repeats'])) + { + $repeats_sel[$mybb->get_input('repeats', 1)] = " selected=\"selected\""; + } + $repeats_1_days = $mybb->get_input('repeats_1_days', 1); + $repeats_3_weeks = $mybb->get_input('repeats_3_weeks', 1); + foreach($mybb->get_input('repeats_3_days', 2) as $day => $val) + { + if($val != 1) + { + continue; + } + $day = (int)$day; + $repeats_3_days[$day] = " checked=\"checked\""; + } + $repeats_4_type = array(); + if($mybb->get_input('repeats_4_type', 1) == 1) + { + $repeats_4_type[1] = "checked=\"checked\""; + $repeats_4_type[2] = ''; + } + else + { + $repeats_4_type[2] = "checked=\"checked\""; + $repeats_4_type[1] = ''; + } + $repeats_4_day = $mybb->get_input('repeats_4_day', 1); + $repeats_4_months = $mybb->get_input('repeats_4_months', 1); + $repeats_4_occurance[$mybb->get_input('repeats_4_occurance')] = "selected=\"selected\""; + $repeats_4_weekday[$mybb->get_input('repeats_4_weekday', 1)] = "selected=\"selected\""; + $repeats_4_months2 = $mybb->get_input('repeats_4_months2', 1); + if($mybb->get_input('repeats_5_type', 1) == 1) + { + $repeats_5_type[1] = "checked=\"checked\""; + } + else + { + $repeats_5_type[2] = "checked=\"checked\""; + } + $repeats_5_day = $mybb->get_input('repeats_5_day', 1); + $repeats_5_month[$mybb->get_input('repeats_5_month', 1)] = "selected=\"selected\""; + $repeats_5_years = $mybb->get_input('repeats_5_years', 1); + $repeats_5_occurance[$mybb->get_input('repeats_5_occurance')] = "selected=\"selected\""; + $repeats_5_weekday[$mybb->get_input('repeats_5_weekday', 1)] = "selected=\"selected\""; + $repeats_5_month2[$mybb->get_input('repeats_5_month2', 1)] = "selected=\"selected\""; + $repeats_5_years2 = $mybb->get_input('repeats_5_years2', 1); + + $timezone = $mybb->get_input('timezone', 1); + } + else + { + if(!empty($mybb->input['day'])) + { + $single_day = $start_day = $end_day = $mybb->get_input('day', 1); + } + else + { + $single_day = $start_day = $end_day = my_date("j"); + } + if(!empty($mybb->input['month'])) + { + $month = $mybb->get_input('month', 1); + } + else + { + $month = my_date("n"); + } + $single_month[$month] = $start_month[$month] = $end_month[$month] = "selected=\"selected\""; + if(!empty($mybb->input['year'])) + { + $single_year = $start_year = $end_year = $mybb->get_input('year', 1); + } + else + { + $single_year = $start_year = $end_year = my_date("Y"); + } + $start_time = $end_time = ""; + $type_single = "checked=\"checked\""; + $type_ranged = ''; + $type = "single"; + $repeats_1_days = 1; + $repeats_3_weeks = 1; + $repeats_4_type[1] = "checked=\"checked\""; + $repeats_4_day = 1; + $repeats_4_months = 1; + $repeats_4_occurance[1] = "selected=\"selected\""; + $repeats_4_weekday[0] = "selected=\"selected\""; + $repeats_4_months2 = 1; + $repeats_5_type[1] = "checked=\"checked\""; + $repeats_5_day = 1; + $repeats_5_month[1] = "selected=\"selected\""; + $repeats_5_years = 1; + $repeats_5_occurance[1] = "selected=\"selected\""; + $repeats_5_weekday[0] = "selected=\"selected\""; + $repeats_5_month2[1] = "selected=\"selected\""; + $repeats_5_years2 = 1; + $timezone = $mybb->user['timezone']; + } + + $single_years = $start_years = $end_years = ''; + + // Construct option list for years + for($year = my_date('Y'); $year < (my_date('Y') + 5); ++$year) + { + if($year == $single_year) + { + $selected = "selected=\"selected\""; + eval("\$single_years .= \"".$templates->get("calendar_year")."\";"); + } + else + { + $selected = ""; + eval("\$single_years .= \"".$templates->get("calendar_year")."\";"); + } + + if($year == $start_year) + { + $selected = "selected=\"selected\""; + eval("\$start_years .= \"".$templates->get("calendar_year")."\";"); + } + else + { + $selected = ""; + eval("\$start_years .= \"".$templates->get("calendar_year")."\";"); + } + + if($year == $end_year) + { + $selected = "selected=\"selected\""; + eval("\$end_years .= \"".$templates->get("calendar_year")."\";"); + } + else + { + $selected = ""; + eval("\$end_years .= \"".$templates->get("calendar_year")."\";"); + } + } + + $single_days = $start_days = $end_days = ''; + + // Construct option list for days + for($day = 1; $day <= 31; ++$day) + { + if($day == $single_day) + { + $selected = "selected=\"selected\""; + eval("\$single_days .= \"".$templates->get("calendar_day")."\";"); + } + else + { + $selected = ""; + eval("\$single_days .= \"".$templates->get("calendar_day")."\";"); + } + + if($day == $start_day) + { + $selected = "selected=\"selected\""; + eval("\$start_days .= \"".$templates->get("calendar_day")."\";"); + } + else + { + $selected = ""; + eval("\$start_days .= \"".$templates->get("calendar_day")."\";"); + } + + if($day == $end_day) + { + $selected = "selected=\"selected\""; + eval("\$end_days .= \"".$templates->get("calendar_day")."\";"); + } + else + { + $selected = ""; + eval("\$end_days .= \"".$templates->get("calendar_day")."\";"); + } + } + + $timezones = build_timezone_select("timezone", $timezone); + + if($mybb->get_input('ignoretimezone', 1) == 1) + { + $ignore_timezone = "checked=\"checked\""; + } + else + { + $ignore_timezone = ''; + } + + if($mybb->get_input('private', 1) == 1) + { + $privatecheck = " checked=\"checked\""; + } + else + { + $privatecheck = ''; + } + + $select_calendar = $calendar_select = ''; + $calendarcount = 0; + + // Build calendar select + $calendar_permissions = get_calendar_permissions(); + $query = $db->simple_select("calendars", "*", "", array("order_by" => "name", "order_dir" => "asc")); + while($calendar_option = $db->fetch_array($query)) + { + if($calendar_permissions[$calendar['cid']]['canviewcalendar'] == 1) + { + $calendar_option['name'] = htmlspecialchars_uni($calendar_option['name']); + if($calendar_option['cid'] == $mybb->input['calendar']) + { + $selected = " selected=\"selected\""; + } + else + { + $selected = ""; + } + + ++$calendarcount; + eval("\$select_calendar .= \"".$templates->get("calendar_select")."\";"); + } + } + + if($calendarcount > 1) + { + eval("\$calendar_select .= \"".$templates->get("calendar_addevent_calendarselect")."\";"); + } + else + { + eval("\$calendar_select .= \"".$templates->get("calendar_addevent_calendarselect_hidden")."\";"); + } + + $event_errors = ''; + + $plugins->run_hooks("calendar_addevent_end"); + + eval("\$addevent = \"".$templates->get("calendar_addevent")."\";"); + output_page($addevent); +} + +// Edit an event +if($mybb->input['action'] == "do_editevent" && $mybb->request_method == "post") +{ + $query = $db->simple_select("events", "*", "eid='{$mybb->input['eid']}'"); + $event = $db->fetch_array($query); + + if(!$event) + { + error($lang->error_invalidevent); + } + + $query = $db->simple_select("calendars", "*", "cid='{$event['cid']}'"); + $calendar = $db->fetch_array($query); + + // Invalid calendar? + if(!$calendar) + { + error($lang->invalid_calendar); + } + + // Do we have permission to view this calendar or post events? + $calendar_permissions = get_calendar_permissions($calendar['cid']); + if($calendar_permissions['canviewcalendar'] != 1 || $calendar_permissions['canaddevents'] != 1) + { + error_no_permission(); + } + + if(($event['uid'] != $mybb->user['uid'] || $mybb->user['uid'] == 0) && $calendar_permissions['canmoderateevents'] != 1) + { + error_no_permission(); + } + + // Verify incoming POST request + verify_post_check($mybb->get_input('my_post_key')); + + // Are we going to delete this event or just edit it? + if($mybb->get_input('delete', 1) == 1) + { + $db->delete_query("events", "eid='{$event['eid']}'"); + + // Redirect back to the main calendar view. + redirect("calendar.php", $lang->redirect_eventdeleted); + } + + $plugins->run_hooks("calendar_do_editevent_start"); + + // Set up event handler. + require_once MYBB_ROOT."inc/datahandler.php"; + require_once MYBB_ROOT."inc/datahandlers/event.php"; + $eventhandler = new EventDataHandler("update"); + $mybb->input['type'] = $mybb->get_input('type'); + + // Prepare an array for the eventhandler. + $event = array( + "eid" => $event['eid'], + "name" => $mybb->get_input('name'), + "description" => $mybb->get_input('description'), + "private" => $mybb->get_input('private', 1), + "type" => $mybb->input['type'] + ); + + // Now we add in our date/time info depending on the type of event + if($mybb->input['type'] == "single") + { + $event['start_date'] = array( + "day" => $mybb->get_input('single_day', 1), + "month" => $mybb->get_input('single_month', 1), + "year" => $mybb->get_input('single_year', 1) + ); + $event['repeats'] = ''; + } + else if($mybb->input['type'] == "ranged") + { + $event['start_date'] = array( + "day" => $mybb->get_input('start_day', 1), + "month" => $mybb->get_input('start_month', 1), + "year" => $mybb->get_input('start_year', 1), + "time" => $mybb->get_input('start_time') + ); + $event['end_date'] = array( + "day" => $mybb->get_input('end_day', 1), + "month" => $mybb->get_input('end_month', 1), + "year" => $mybb->get_input('end_year', 1), + "time" => $mybb->get_input('end_time') + ); + $event['timezone'] = $mybb->get_input('timezone'); + $event['ignoretimezone'] = $mybb->get_input('ignoretimezone', 1); + $repeats = array(); + switch($mybb->input['repeats']) + { + case 1: + $repeats['repeats'] = 1; + $repeats['days'] = $mybb->get_input('repeats_1_days', 1); + break; + case 2: + $repeats['repeats'] = 2; + break; + case 3: + $repeats['repeats'] = 3; + $repeats['weeks'] = $mybb->get_input('repeats_3_weeks', 1); + $mybb->input['repeats_3_days'] = $mybb->get_input('repeats_3_days', 2); + ksort($mybb->input['repeats_3_days']); + $days = array(); + foreach($mybb->input['repeats_3_days'] as $weekday => $value) + { + if($value != 1) + { + continue; + } + $days[] = $weekday; + } + $repeats['days'] = $days; + break; + case 4: + $repeats['repeats'] = 4; + if($mybb->get_input('repeats_4_type', 1) == 1) + { + $repeats['day'] = $mybb->get_input('repeats_4_day', 1); + $repeats['months'] = $mybb->get_input('repeats_4_months', 1); + } + else + { + $repeats['months'] = $mybb->get_input('repeats_4_months2', 1); + $repeats['occurance'] = $mybb->get_input('repeats_4_occurance'); + $repeats['weekday'] = $mybb->get_input('repeats_4_weekday', 1); + } + break; + case 5: + $repeats['repeats'] = 5; + if($mybb->get_input('repeats_5_type', 1) == 1) + { + $repeats['day'] = $mybb->get_input('repeats_5_day', 1); + $repeats['month'] = $mybb->get_input('repeats_5_month', 1); + $repeats['years'] = $mybb->get_input('repeats_5_years', 1); + } + else + { + $repeats['occurance'] = $mybb->get_input('repeats_5_occurance'); + $repeats['weekday'] = $mybb->get_input('repeats_5_weekday', 1); + $repeats['month'] = $mybb->get_input('repeats_5_month2', 1); + $repeats['years'] = $mybb->get_input('repeats_5_years', 1); + } + break; + default: + $repeats['repeats'] = 0; + } + $event['repeats'] = $repeats; + } + + $eventhandler->set_data($event); + + // Now let the eventhandler do all the hard work. + if(!$eventhandler->validate_event()) + { + $event_errors = $eventhandler->get_friendly_errors(); + $event_errors = inline_error($event_errors); + $mybb->input['action'] = "editevent"; + } + else + { + $details = $eventhandler->update_event(); + $plugins->run_hooks("calendar_do_editevent_end"); + redirect(get_event_link($event['eid']), $lang->redirect_eventupdated); + } +} + +if($mybb->input['action'] == "editevent") +{ + // Event already fetched in do_editevent? + if(!isset($event)) + { + $query = $db->simple_select("events", "*", "eid='{$mybb->input['eid']}'"); + $event = $db->fetch_array($query); + + if(!$event) + { + error($lang->error_invalidevent); + } + + $query = $db->simple_select("calendars", "*", "cid='{$event['cid']}'"); + $calendar = $db->fetch_array($query); + + // Invalid calendar? + if(!$calendar['cid']) + { + error($lang->invalid_calendar); + } + + // Do we have permission to view this calendar or post events? + $calendar_permissions = get_calendar_permissions($calendar['cid']); + if($calendar_permissions['canviewcalendar'] != 1 || $calendar_permissions['canaddevents'] != 1) + { + error_no_permission(); + } + + if(($event['uid'] != $mybb->user['uid'] || $mybb->user['uid'] == 0) && $calendar_permissions['canmoderateevents'] != 1) + { + error_no_permission(); + } + } + + $event['name'] = htmlspecialchars_uni($event['name']); + + add_breadcrumb(htmlspecialchars_uni($calendar['name']), get_calendar_link($calendar['cid'])); + add_breadcrumb($event['name'], get_event_link($event['eid'])); + add_breadcrumb($lang->nav_editevent); + + $plugins->run_hooks("calendar_editevent_start"); + + // If MyCode is on for this forum and the MyCode editor is enabled inthe Admin CP, draw the code buttons and smilie inserter. + if($mybb->settings['bbcodeinserter'] != 0 && (!$mybb->user['uid'] || $mybb->user['showcodebuttons'] != 0) && $calendar['allowmycode'] == 1) + { + $codebuttons = build_mycode_inserter("message", $calendar['allowsmilies']); + if($calendar['allowsmilies'] == 1) + { + $smilieinserter = build_clickable_smilies(); + } + } + + $single_month = $start_month = $end_month = $repeats_sel = $repeats_3_days = $repeats_4_occurance = $repeats_4_weekday = $repeats_5_month = $repeats_5_occurance = $repeats_5_weekday = $repeats_5_month2 = array(); + foreach(range(1, 12) as $number) + { + $single_month[$number] = $start_month[$number] = $end_month[$number] = $repeats_5_month[$number] = $repeats_5_month2[$number] = ''; + } + foreach(range(1, 5) as $number) + { + $repeats_sel[$number] = ''; + } + foreach(range(0, 6) as $number) + { + $repeats_3_days[$number] = $repeats_4_weekday[$number] = $repeats_5_weekday[$number] = ''; + } + foreach(range(1, 4) as $number) + { + $repeats_4_occurance[$number] = $repeats_5_occurance[$number] = ''; + } + $repeats_4_occurance['last'] = $repeats_5_occurance['last'] = ''; + $repeats_4_type = array(1 => '', 2 => ''); + $repeats_5_type = array(1 => '', 2 => ''); + + // Previous selections + if(isset($event_errors)) + { + $name = htmlspecialchars_uni($mybb->get_input('name')); + $description = htmlspecialchars_uni($mybb->get_input('description')); + $single_day = $mybb->get_input('single_day', 1); + $single_month[$mybb->get_input('single_month', 1)] = " selected=\"selected\""; + $single_year = $mybb->get_input('single_year', 1); + $start_day = $mybb->get_input('start_day', 1); + $start_month[$mybb->get_input('start_month', 1)] = " selected=\"selected\""; + $start_year = $mybb->get_input('start_year', 1); + $start_time = htmlspecialchars_uni($mybb->get_input('start_time')); + $end_day = $mybb->get_input('end_day', 1); + $end_month[$mybb->get_input('end_month', 1)] = " selected=\"selected\""; + $end_year = $mybb->get_input('end_year', 1); + $end_time = htmlspecialchars_uni($mybb->get_input('end_time')); + if($mybb->get_input('type') == "single") + { + $type_single = "checked=\"checked\""; + $type_ranged = ''; + $type = "single"; + } + else + { + $type_ranged = "checked=\"checked\""; + $type_single = ''; + $type = "ranged"; + } + if(!empty($mybb->input['repeats'])) + { + $repeats_sel[$mybb->get_input('repeats', 1)] = " selected=\"selected\""; + } + $repeats_1_days = $mybb->get_input('repeats_1_days', 1); + $repeats_3_weeks = $mybb->get_input('repeats_3_weeks', 1); + foreach($mybb->get_input('repeats_3_days', 2) as $day => $val) + { + if($val != 1) + { + continue; + } + $day = (int)$day; + $repeats_3_days[$day] = " checked=\"checked\""; + } + $repeats_4_type = array(); + if($mybb->get_input('repeats_4_type', 1) == 1) + { + $repeats_4_type[1] = "checked=\"checked\""; + $repeats_4_type[2] = ''; + } + else + { + $repeats_4_type[2] = "checked=\"checked\""; + $repeats_4_type[1] = ''; + } + $repeats_4_day = $mybb->get_input('repeats_4_day', 1); + $repeats_4_months = $mybb->get_input('repeats_4_months', 1); + $repeats_4_occurance[$mybb->get_input('repeats_4_occurance')] = "selected=\"selected\""; + $repeats_4_weekday[$mybb->get_input('repeats_4_weekday', 1)] = "selected=\"selected\""; + $repeats_4_months2 = $mybb->get_input('repeats_4_months2', 1); + if($mybb->get_input('repeats_5_type', 1) == 1) + { + $repeats_5_type[1] = "checked=\"checked\""; + } + else + { + $repeats_5_type[2] = "checked=\"checked\""; + } + $repeats_5_day = $mybb->get_input('repeats_5_day', 1); + $repeats_5_month[$mybb->get_input('repeats_5_month', 1)] = "selected=\"selected\""; + $repeats_5_years = $mybb->get_input('repeats_5_years', 1); + $repeats_5_occurance[$mybb->get_input('repeats_5_occurance')] = "selected=\"selected\""; + $repeats_5_weekday[$mybb->get_input('repeats_5_weekday', 1)] = "selected=\"selected\""; + $repeats_5_month2[$mybb->get_input('repeats_5_month2', 1)] = "selected=\"selected\""; + $repeats_5_years2 = $mybb->get_input('repeats_5_years2', 1); + + if($mybb->get_input('private', 1) == 1) + { + $privatecheck = " checked=\"checked\""; + } + else + { + $privatecheck = ''; + } + + if($mybb->get_input('ignoretimezone', 1) == 1) + { + $ignore_timezone = "checked=\"checked\""; + } + else + { + $ignore_timezone = ''; + } + + $timezone = $mybb->get_input('timezone'); + } + else + { + $event_errors = ''; + $mybb->input['calendar'] = $event['cid']; + $name = htmlspecialchars_uni($event['name']); + $description = htmlspecialchars_uni($event['description']); + if($event['private'] == 1) + { + $privatecheck = " checked=\"checked\""; + } + else + { + $privatecheck = ''; + } + $start_date = explode("-", gmdate("j-n-Y-g:i A", $event['starttime']+$event['timezone']*3600)); + $single_day = $start_date[0]; + $single_month[$start_date[1]] = " selected=\"selected\""; + $single_year = $start_date[2]; + $start_day = $start_date[0]; + $start_month[$start_date[1]] = " selected=\"selected\""; + $start_year = $start_date[2]; + if($event['usingtime']) + { + $start_time = gmdate($mybb->settings['timeformat'], $event['starttime']+$event['timezone']*3600); + } + else + { + $start_time = ''; + } + if($event['endtime']) + { + $end_date = explode("-", gmdate("j-n-Y-g:i A", $event['endtime']+$event['timezone']*3600)); + $end_day = $end_date[0]; + $end_month[$end_date[1]] = " selected=\"selected\""; + $end_year = $end_date[2]; + if($event['usingtime']) + { + $end_time = gmdate($mybb->settings['timeformat'], $event['endtime']+$event['timezone']*3600); + } + else + { + $end_time = ''; + } + $type_ranged = "checked=\"checked\""; + $type_single = ''; + $type = "ranged"; + $repeats = my_unserialize($event['repeats']); + if($repeats['repeats'] >= 0) + { + $repeats_sel[$repeats['repeats']] = " selected=\"selected\""; + switch($repeats['repeats']) + { + case 1: + $repeats_1_days = $repeats['days']; + $repeats_3_weeks = 1; + $repeats_4_type[1] = "checked=\"checked\""; + $repeats_4_day = 1; + $repeats_4_months = 1; + $repeats_4_months2 = 1; + $repeats_5_type[1] = "checked=\"checked\""; + $repeats_5_day = 1; + $repeats_5_years = $repeats_5_years2 = 1; + break; + case 3: + $repeats_1_days = 1; + $repeats_3_weeks = $repeats['weeks']; + if(is_array($repeats['days'])) + { + foreach($repeats['days'] as $weekday) + { + $repeats_3_days[$weekday] = " checked=\"checked\""; + } + } + $repeats_4_type[1] = "checked=\"checked\""; + $repeats_4_day = 1; + $repeats_4_months = 1; + $repeats_4_months2 = 1; + $repeats_5_type[1] = "checked=\"checked\""; + $repeats_5_day = 1; + $repeats_5_years = $repeats_5_years2 = 1; + break; + case 4: + $repeats_1_days = 1; + $repeats_3_weeks = 1; + if($repeats['day']) + { + $repeats_4_type[1] = "checked=\"checked\""; + $repeats_4_day = $repeats['day']; + $repeats_4_months = $repeats_4_months2 = $repeats['months']; + } + else + { + $repeats_4_type[2] = "checked=\"checked\""; + $repeats_4_day = 1; + $repeats_4_months2 = $repeats_4_months = $repeats['months']; + $repeats_4_occurance[$repeats['occurance']] = "selected=\"selected\""; + $repeats_4_weekday[$repeats['weekday']] = "selected=\"selected\""; + } + $repeats_5_type[1] = "checked=\"checked\""; + $repeats_5_day = 1; + $repeats_5_years = $repeats_5_years2 = 1; + break; + case 5: + $repeats_1_days = 1; + $repeats_3_weeks = 1; + $repeats_4_type[1] = "checked=\"checked\""; + $repeats_4_day = 1; + $repeats_4_months = 1; + $repeats_4_months2 = 1; + if($repeats['day']) + { + $repeats_5_type[1] = "checked=\"checked\""; + $repeats_5_day = $repeats['day']; + $repeats_5_month[$repeats['month']] = $repeats_5_month2[$repeats['month']] = "selected=\"selected\""; + $repeats_5_years = $repeats_5_years2 = $repeats['years']; + } + else + { + $repeats_5_type[2] = "checked=\"checked\""; + $repeats_5_occurance[$repeats['occurance']] = "selected=\"selected\""; + $repeats_5_weekday[$repeats['weekday']] = "selected=\"selected\""; + $repeats_5_month[$repeats['month']] = $repeats_5_month2[$repeats['month']] = "selected=\"selected\""; + $repeats_5_years = $repeats_5_years2 = $repeats['years']; + } + break; + } + } + if($event['ignoretimezone']) + { + $timezone = 0; + $ignore_timezone = "checked=\"checked\""; + } + else + { + $timezone = $event['timezone']; + $ignore_timezone = ''; + } + } + else + { + $type_single = "checked=\"checked\""; + $type_ranged = $ignore_timezone = $repeats_1_days = $repeats_3_weeks = $repeats_4_day = $repeats_4_months = $repeats_4_months2 = $repeats_5_day = $repeats_5_years = $timezone = $end_time = ''; + $type = "single"; + // set some defaults if the user wants to make a ranged event + $end_day = $start_day; + $end_month = $start_month; + $end_year = $start_year; + } + } + + $single_years = $start_years = $end_years = ''; + + // Construct option list for years + for($year = my_date('Y'); $year < (my_date('Y') + 5); ++$year) + { + if($year == $single_year) + { + $selected = "selected=\"selected\""; + eval("\$single_years .= \"".$templates->get("calendar_year")."\";"); + } + else + { + $selected = ""; + eval("\$single_years .= \"".$templates->get("calendar_year")."\";"); + } + + if($year == $start_year) + { + $selected = "selected=\"selected\""; + eval("\$start_years .= \"".$templates->get("calendar_year")."\";"); + } + else + { + $selected = ""; + eval("\$start_years .= \"".$templates->get("calendar_year")."\";"); + } + + if($year == $end_year) + { + $selected = "selected=\"selected\""; + eval("\$end_years .= \"".$templates->get("calendar_year")."\";"); + } + else + { + $selected = ""; + eval("\$end_years .= \"".$templates->get("calendar_year")."\";"); + } + } + + $single_days = $start_days = $end_days = ''; + + // Construct option list for days + for($day = 1; $day <= 31; ++$day) + { + if($day == $single_day) + { + $selected = "selected=\"selected\""; + eval("\$single_days .= \"".$templates->get("calendar_day")."\";"); + } + else + { + $selected = ""; + eval("\$single_days .= \"".$templates->get("calendar_day")."\";"); + } + + if($day == $start_day) + { + $selected = "selected=\"selected\""; + eval("\$start_days .= \"".$templates->get("calendar_day")."\";"); + } + else + { + $selected = ""; + eval("\$start_days .= \"".$templates->get("calendar_day")."\";"); + } + + if($day == $end_day) + { + $selected = "selected=\"selected\""; + eval("\$end_days .= \"".$templates->get("calendar_day")."\";"); + } + else + { + $selected = ""; + eval("\$end_days .= \"".$templates->get("calendar_day")."\";"); + } + } + + $timezones = build_timezone_select("timezone", $timezone); + + $plugins->run_hooks("calendar_editevent_end"); + + eval("\$editevent = \"".$templates->get("calendar_editevent")."\";"); + output_page($editevent); +} + +// Move an event to another calendar +if($mybb->input['action'] == "move") +{ + $query = $db->simple_select("events", "*", "eid='{$mybb->input['eid']}'"); + $event = $db->fetch_array($query); + + if(!$event) + { + error($lang->error_invalidevent); + } + + $query = $db->simple_select("calendars", "*", "cid='{$event['cid']}'"); + $calendar = $db->fetch_array($query); + + // Invalid calendar? + if(!$calendar) + { + error($lang->invalid_calendar); + } + + // Do we have permission to view this calendar or post events? + $calendar_permissions = get_calendar_permissions(); + if($calendar_permissions[$calendar['cid']]['canviewcalendar'] != 1) + { + error_no_permission(); + } + + if($calendar_permissions[$calendar['cid']]['canmoderateevents'] != 1) + { + error_no_permission(); + } + + $event['name'] = htmlspecialchars_uni($event['name']); + + add_breadcrumb(htmlspecialchars_uni($calendar['name']), get_calendar_link($calendar['cid'])); + add_breadcrumb($event['name'], get_event_link($event['eid'])); + add_breadcrumb($lang->nav_move_event); + + $plugins->run_hooks("calendar_move_start"); + + $calendar_select = $selected = ''; + + // Build calendar select + $query = $db->simple_select("calendars", "*", "", array("order_by" => "name", "order_dir" => "asc")); + while($calendar_option = $db->fetch_array($query)) + { + if($calendar_permissions[$calendar['cid']]['canviewcalendar'] == 1) + { + $calendar_option['name'] = htmlspecialchars_uni($calendar_option['name']); + eval("\$calendar_select .= \"".$templates->get("calendar_select")."\";"); + } + } + + $plugins->run_hooks("calendar_move_end"); + + eval("\$moveevent = \"".$templates->get("calendar_move")."\";"); + output_page($moveevent); +} + +// Actually move the event +if($mybb->input['action'] == "do_move" && $mybb->request_method == "post") +{ + // Verify incoming POST request + verify_post_check($mybb->get_input('my_post_key')); + + $query = $db->simple_select("events", "*", "eid='{$mybb->input['eid']}'"); + $event = $db->fetch_array($query); + + if(!$event) + { + error($lang->error_invalidevent); + } + + $query = $db->simple_select("calendars", "*", "cid='{$event['cid']}'"); + $calendar = $db->fetch_array($query); + + // Invalid calendar? + if(!$calendar) + { + error($lang->invalid_calendar); + } + + // Do we have permission to view this calendar? + $calendar_permissions = get_calendar_permissions(); + if($calendar_permissions[$calendar['cid']]['canviewcalendar'] != 1) + { + error_no_permission(); + } + + if($calendar_permissions[$calendar['cid']]['canmoderateevents'] != 1) + { + error_no_permission(); + } + + $query = $db->simple_select("calendars", "*", "cid='".$mybb->get_input('new_calendar', 1)."'"); + $new_calendar = $db->fetch_array($query); + + if(!$new_calendar) + { + error($lang->invalid_calendar); + } + + if($calendar_permissions[$mybb->input['new_calendar']]['canviewcalendar'] != 1) + { + error_no_permission(); + } + + $updated_event = array( + "cid" => $new_calendar['cid'] + ); + + $plugins->run_hooks("calendar_do_move_start"); + + $db->update_query("events", $updated_event, "eid='{$event['eid']}'"); + + $plugins->run_hooks("calendar_do_move_end"); + + redirect(get_event_link($event['eid']), $lang->redirect_eventmoved); +} + +// Approve an event +if($mybb->input['action'] == "approve") +{ + // Verify incoming POST request + verify_post_check($mybb->get_input('my_post_key')); + + $query = $db->simple_select("events", "*", "eid='{$mybb->input['eid']}'"); + $event = $db->fetch_array($query); + + if(!$event) + { + error($lang->error_invalidevent); + } + + $query = $db->simple_select("calendars", "*", "cid='{$event['cid']}'"); + $calendar = $db->fetch_array($query); + + // Invalid calendar? + if(!$calendar) + { + error($lang->invalid_calendar); + } + + // Do we have permission to view this calendar? + $calendar_permissions = get_calendar_permissions($calendar['cid']); + if($calendar_permissions['canviewcalendar'] != 1) + { + error_no_permission(); + } + + if($calendar_permissions['canmoderateevents'] != 1) + { + error_no_permission(); + } + + $updated_event = array( + "visible" => 1 + ); + + $plugins->run_hooks("calendar_approve_start"); + + $db->update_query("events", $updated_event, "eid='{$event['eid']}'"); + + $plugins->run_hooks("calendar_approve_end"); + + redirect(get_event_link($event['eid']), $lang->redirect_eventapproved); +} + +// Unapprove an event +if($mybb->input['action'] == "unapprove") +{ + // Verify incoming POST request + verify_post_check($mybb->get_input('my_post_key')); + + $query = $db->simple_select("events", "*", "eid='{$mybb->input['eid']}'"); + $event = $db->fetch_array($query); + + if(!$event) + { + error($lang->error_invalidevent); + } + + $query = $db->simple_select("calendars", "*", "cid='{$event['cid']}'"); + $calendar = $db->fetch_array($query); + + // Invalid calendar? + if(!$calendar) + { + error($lang->invalid_calendar); + } + + // Do we have permission to view this calendar? + $calendar_permissions = get_calendar_permissions($calendar['cid']); + if($calendar_permissions['canviewcalendar'] != 1) + { + error_no_permission(); + } + + if($calendar_permissions['canmoderateevents'] != 1) + { + error_no_permission(); + } + + $updated_event = array( + "visible" => 0 + ); + + $plugins->run_hooks("calendar_unapprove_start"); + + $db->update_query("events", $updated_event, "eid='{$event['eid']}'"); + + $plugins->run_hooks("calendar_unapprove_end"); + + redirect(get_event_link($event['eid']), $lang->redirect_eventunapproved); +} + +// Showing specific event +if($mybb->input['action'] == "event") +{ + $query = $db->query(" + SELECT u.*, e.* + FROM ".TABLE_PREFIX."events e + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=e.uid) + WHERE e.eid='{$mybb->input['eid']}' + "); + $event = $db->fetch_array($query); + + if(!$event || ($event['private'] == 1 && $event['uid'] != $mybb->user['uid'])) + { + error($lang->error_invalidevent); + } + + $query = $db->simple_select("calendars", "*", "cid='{$event['cid']}'"); + $calendar = $db->fetch_array($query); + + // Invalid calendar? + if(!$calendar) + { + error($lang->invalid_calendar); + } + + // Do we have permission to view this calendar? + $calendar_permissions = get_calendar_permissions($calendar['cid']); + if($calendar_permissions['canviewcalendar'] != 1 || ($calendar_permissions['canmoderateevents'] != 1 && $event['visible'] == 0)) + { + error_no_permission(); + } + + $event['name'] = htmlspecialchars_uni($event['name']); + + add_breadcrumb(htmlspecialchars_uni($calendar['name']), get_calendar_link($calendar['cid'])); + add_breadcrumb($event['name'], get_event_link($event['eid'])); + + $plugins->run_hooks("calendar_event_start"); + + $event_parser_options = array( + "allow_html" => $calendar['allowhtml'], + "allow_mycode" => $calendar['allowmycode'], + "allow_smilies" => $calendar['allowsmilies'], + "allow_imgcode" => $calendar['allowimgcode'], + "allow_videocode" => $calendar['allowvideocode'] + ); + + if($mybb->user['showimages'] != 1 && $mybb->user['uid'] != 0 || $mybb->settings['guestimages'] != 1 && $mybb->user['uid'] == 0) + { + $event_parser_options['allow_imgcode'] = 0; + } + + if($mybb->user['showvideos'] != 1 && $mybb->user['uid'] != 0 || $mybb->settings['guestvideos'] != 1 && $mybb->user['uid'] == 0) + { + $event_parser_options['allow_videocode'] = 0; + } + + $event['description'] = $parser->parse_message($event['description'], $event_parser_options); + + // Get the usergroup + if($event['username']) + { + if(!$event['displaygroup']) + { + $event['displaygroup'] = $event['usergroup']; + } + $user_usergroup = $groupscache[$event['displaygroup']]; + } + else + { + $user_usergroup = $groupscache[1]; + } + + $titles_cache = $cache->read("usertitles"); + + // Event made by registered user + if($event['uid'] > 0 && $event['username']) + { + $event['profilelink'] = build_profile_link(format_name($event['username'], $event['usergroup'], $event['displaygroup']), $event['uid']); + + $hascustomtitle = 0; + if(trim($event['usertitle']) != "") + { + $hascustomtitle = 1; + } + + if($user_usergroup['usertitle'] != "" && !$hascustomtitle) + { + $event['usertitle'] = $user_usergroup['usertitle']; + } + elseif(is_array($titles_cache) && !$user_usergroup['usertitle']) + { + reset($titles_cache); + foreach($titles_cache as $key => $title) + { + if($event['postnum'] >= $key) + { + if(!$hascustomtitle) + { + $event['usertitle'] = $title['title']; + } + $event['stars'] = $title['stars']; + $event['starimage'] = $title['starimage']; + break; + } + } + } + + if($user_usergroup['stars']) + { + $event['stars'] = $user_usergroup['stars']; + } + + if(empty($event['starimage'])) + { + $event['starimage'] = $user_usergroup['starimage']; + } + $event['starimage'] = str_replace("{theme}", $theme['imgdir'], $event['starimage']); + + $event['userstars'] = ''; + for($i = 0; $i < $event['stars']; ++$i) + { + eval("\$event['userstars'] .= \"".$templates->get("calendar_event_userstar", 1, 0)."\";"); + } + + if($event['userstars'] && $event['starimage'] && $event['stars']) + { + $event['userstars'] .= "
    "; + } + } + // Created by a guest or an unknown user + else + { + if(!$event['username']) + { + $event['username'] = $lang->guest; + } + + $event['profilelink'] = format_name($event['username'], 1); + + if($user_usergroup['usertitle']) + { + $event['usertitle'] = $user_usergroup['usertitle']; + } + else + { + $event['usertitle'] = $lang->guest; + } + $event['userstars'] = ''; + } + + $event['usertitle'] = htmlspecialchars_uni($event['usertitle']); + + if($event['ignoretimezone'] == 0) + { + $offset = $event['timezone']; + } + else + { + $offset = $mybb->user['timezone']; + } + + $event['starttime_user'] = $event['starttime']+$offset*3600; + + // Events over more than one day + $time_period = ''; + if($event['endtime'] > 0 && $event['endtime'] != $event['starttime']) + { + $event['endtime_user'] = $event['endtime']+$offset*3600; + $start_day = gmmktime(0, 0, 0, gmdate("n", $event['starttime_user']), gmdate("j", $event['starttime_user']), gmdate("Y", $event['starttime_user'])); + $end_day = gmmktime(0, 0, 0, gmdate("n", $event['endtime_user']), gmdate("j", $event['endtime_user']), gmdate("Y", $event['endtime_user'])); + $start_time = gmdate("Hi", $event['starttime_user']); + $end_time = gmdate("Hi", $event['endtime_user']); + + $event['repeats'] = my_unserialize($event['repeats']); + + // Event only runs over one day + if($start_day == $end_day && $event['repeats']['repeats'] == 0) + { + $time_period = gmdate($mybb->settings['dateformat'], $event['starttime_user']); + // Event runs all day + if($start_time != 0000 && $end_time != 2359) + { + $time_period .= $lang->comma.gmdate($mybb->settings['timeformat'], $event['starttime_user'])." - ".gmdate($mybb->settings['timeformat'], $event['endtime_user']); + } + else + { + $time_period .= $lang->comma.$lang->all_day; + } + } + else + { + $time_period = gmdate($mybb->settings['dateformat'], $event['starttime_user']).", ".gmdate($mybb->settings['timeformat'], $event['starttime_user']); + $time_period .= " - "; + $time_period .= gmdate($mybb->settings['dateformat'], $event['endtime_user']).", ".gmdate($mybb->settings['timeformat'], $event['endtime_user']); + } + } + else + { + $time_period = gmdate($mybb->settings['dateformat'], $event['starttime_user']); + } + + $repeats = fetch_friendly_repetition($event); + if($repeats) + { + eval("\$repeats = \"".$templates->get("calendar_repeats")."\";"); + } + + $event_class = ''; + if($calendar_permissions['canmoderateevents'] == 1 || ($mybb->user['uid'] > 0 && $mybb->user['uid'] == $event['uid'])) + { + eval("\$edit_event = \"".$templates->get("calendar_event_editbutton")."\";"); + if($calendar_permissions['canmoderateevents'] == 1) + { + if($event['visible'] == 1) + { + $approve = $lang->unapprove_event; + $approve_value = "unapprove"; + } + else + { + $approve = $lang->approve_event; + $approve_value = "approve"; + } + eval("\$moderator_options = \"".$templates->get("calendar_event_modoptions")."\";"); + } + + if($event['visible'] == 0) + { + $event_class = " trow_shaded"; + } + } + + $month = my_date("n"); + + $yearsel = ''; + for($year_sel = my_date("Y"); $year_sel < (my_date("Y") + 5); ++$year_sel) + { + eval("\$yearsel .= \"".$templates->get("calendar_year_sel")."\";"); + } + + $addevent = ''; + if($mybb->usergroup['canaddevents'] == 1) + { + eval("\$addevent = \"".$templates->get("calendar_addeventlink")."\";"); + } + + // Now output the page + $plugins->run_hooks("calendar_event_end"); + eval("\$event = \"".$templates->get("calendar_event")."\";"); + output_page($event); +} + +// View all events on a specific day. +if($mybb->input['action'] == "dayview") +{ + // Showing a particular calendar + if($mybb->input['calendar']) + { + $query = $db->simple_select("calendars", "*", "cid='{$mybb->input['calendar']}'"); + $calendar = $db->fetch_array($query); + } + // Showing the default calendar + else + { + $query = $db->simple_select("calendars", "*", "disporder='1'"); + $calendar = $db->fetch_array($query); + } + + // Invalid calendar? + if(!$calendar) + { + error($lang->invalid_calendar); + } + + // Do we have permission to view this calendar? + $calendar_permissions = get_calendar_permissions($calendar['cid']); + if($calendar_permissions['canviewcalendar'] != 1) + { + error_no_permission(); + } + + // Incoming year? + $mybb->input['year'] = $mybb->get_input('year', 1); + if($mybb->input['year'] && $mybb->input['year'] <= my_date("Y")+5) + { + $year = $mybb->input['year']; + } + else + { + $year = my_date("Y"); + } + + // Then the month + $mybb->input['month'] = $mybb->get_input('month', 1); + if($mybb->input['month'] >= 1 && $mybb->input['month'] <= 12) + { + $month = $mybb->input['month']; + } + else + { + $month = my_date("n"); + } + + // And day? + $mybb->input['day'] = $mybb->get_input('day', 1); + if($mybb->input['day'] && $mybb->input['day'] <= gmdate("t", gmmktime(0, 0, 0, $month, 1, $year))) + { + $day = $mybb->input['day']; + } + else + { + $day = my_date("j"); + } + + add_breadcrumb(htmlspecialchars_uni($calendar['name']), get_calendar_link($calendar['cid'])); + add_breadcrumb("$day $monthnames[$month] $year", get_calendar_link($calendar['cid'], $year, $month, $day)); + + $plugins->run_hooks("calendar_dayview_start"); + + // Load Birthdays for this day + $birthday_list = $birthdays = ''; + if($calendar['showbirthdays']) + { + $birthdays2 = get_birthdays($month, $day); + $bdayhidden = 0; + if(is_array($birthdays2)) + { + foreach($birthdays2 as $birthday) + { + if($birthday['birthdayprivacy'] == 'all') + { + $bday = explode("-", $birthday['birthday']); + if($bday[2] && $bday[2] < $year) + { + $age = $year - $bday[2]; + $age = " (".$lang->sprintf($lang->years_old, $age).")"; + } + else + { + $age = ''; + } + + $birthday['username'] = format_name($birthday['username'], $birthday['usergroup'], $birthday['displaygroup']); + $birthday['profilelink'] = build_profile_link($birthday['username'], $birthday['uid']); + eval("\$birthday_list .= \"".$templates->get("calendar_dayview_birthdays_bday", 1, 0)."\";"); + $comma = $lang->comma; + } + else + { + ++$bdayhidden; + } + } + } + if($bdayhidden > 0) + { + if($birthday_list) + { + $birthday_list .= " - "; + } + $birthday_list .= "{$bdayhidden} {$lang->birthdayhidden}"; + } + if($birthday_list) + { + $bdaydate = my_date($mybb->settings['dateformat'], gmmktime(0, 0, 0, $month, $day, $year), 0, 0); + $lang->birthdays_on_day = $lang->sprintf($lang->birthdays_on_day, $bdaydate); + eval("\$birthdays = \"".$templates->get("calendar_dayview_birthdays", 1, 0)."\";"); + } + } + + // So now we fetch events for this month + $start_timestamp = gmmktime(0, 0, 0, $month, $day, $year); + $end_timestamp = gmmktime(23, 59, 59, $month, $day, $year); + + $events_cache = get_events($calendar, $start_timestamp, $end_timestamp, $calendar_permissions['canmoderateevents']); + + $events = ''; + if(isset($events_cache["$day-$month-$year"]) && is_array($events_cache["$day-$month-$year"])) + { + foreach($events_cache["$day-$month-$year"] as $event) + { + $event['name'] = htmlspecialchars_uni($event['name']); + + $event_parser_options = array( + "allow_html" => $calendar['allowhtml'], + "allow_mycode" => $calendar['allowmycode'], + "allow_smilies" => $calendar['allowsmilies'], + "allow_imgcode" => $calendar['allowimgcode'], + "allow_videocode" => $calendar['allowvideocode'] + ); + + if($mybb->user['showimages'] != 1 && $mybb->user['uid'] != 0 || $mybb->settings['guestimages'] != 1 && $mybb->user['uid'] == 0) + { + $event_parser_options['allow_imgcode'] = 0; + } + + if($mybb->user['showvideos'] != 1 && $mybb->user['uid'] != 0 || $mybb->settings['guestvideos'] != 1 && $mybb->user['uid'] == 0) + { + $event_parser_options['allow_videocode'] = 0; + } + + $event['description'] = $parser->parse_message($event['description'], $event_parser_options); + + // Get the usergroup + if($event['username']) + { + if(!$event['displaygroup']) + { + $event['displaygroup'] = $event['usergroup']; + } + $user_usergroup = $groupscache[$event['displaygroup']]; + } + else + { + $user_usergroup = $groupscache[1]; + } + + $titles_cache = $cache->read("usertitles"); + + // Event made by registered user + if($event['uid'] > 0 && $event['username']) + { + $event['profilelink'] = build_profile_link(format_name($event['username'], $event['usergroup'], $event['displaygroup']), $event['uid']); + + $hascustomtitle = 0; + if(trim($event['usertitle']) != "") + { + $hascustomtitle = 1; + } + + if($user_usergroup['usertitle'] != "" && !$hascustomtitle) + { + $event['usertitle'] = $user_usergroup['usertitle']; + } + elseif(is_array($titles_cache) && !$user_usergroup['usertitle']) + { + reset($titles_cache); + foreach($titles_cache as $key => $title) + { + if($event['postnum'] >= $key) + { + if(!$hascustomtitle) + { + $event['usertitle'] = $title['title']; + } + $event['stars'] = $title['stars']; + $event['starimage'] = $title['starimage']; + break; + } + } + } + + if($user_usergroup['stars']) + { + $event['stars'] = $user_usergroup['stars']; + } + + if(empty($event['starimage'])) + { + $event['starimage'] = $user_usergroup['starimage']; + } + + $event['userstars'] = ''; + for($i = 0; $i < $event['stars']; ++$i) + { + eval("\$event['userstars'] .= \"".$templates->get("calendar_event_userstar", 1, 0)."\";"); + } + + if($event['userstars'] && $event['starimage'] && $event['stars']) + { + $event['userstars'] .= "
    "; + } + } + // Created by a guest or an unknown user + else + { + if(!$event['username']) + { + $event['username'] = $lang->guest; + } + + $event['username'] = $event['username']; + $event['profilelink'] = format_name($event['username'], 1); + + if($user_usergroup['usertitle']) + { + $event['usertitle'] = $user_usergroup['usertitle']; + } + else + { + $event['usertitle'] = $lang->guest; + } + $event['userstars'] = ''; + } + + $event['usertitle'] = htmlspecialchars_uni($event['usertitle']); + + if($event['ignoretimezone'] == 0) + { + $offset = $event['timezone']; + } + else + { + $offset = $mybb->user['timezone']; + } + + $event['starttime_user'] = $event['starttime']+$offset*3600; + + // Events over more than one day + $time_period = ''; + if($event['endtime'] > 0 && $event['endtime'] != $event['starttime']) + { + $event['endtime_user'] = $event['endtime']+$offset*3600; + $start_day = gmmktime(0, 0, 0, gmdate("n", $event['starttime_user']), gmdate("j", $event['starttime_user']), gmdate("Y", $event['starttime_user'])); + $end_day = gmmktime(0, 0, 0, gmdate("n", $event['endtime_user']), gmdate("j", $event['endtime_user']), gmdate("Y", $event['endtime_user'])); + $start_time = gmdate("Hi", $event['starttime_user']); + $end_time = gmdate("Hi", $event['endtime_user']); + + // Event only runs over one day + if($start_day == $end_day && $event['repeats']['repeats'] == 0) + { + $time_period = gmdate($mybb->settings['dateformat'], $event['starttime_user']); + // Event runs all day + if($start_time != 0000 && $end_time != 2359) + { + $time_period .= $lang->comma.gmdate($mybb->settings['timeformat'], $event['starttime_user'])." - ".gmdate($mybb->settings['timeformat'], $event['endtime_user']); + } + else + { + $time_period .= $lang->comma.$lang->all_day; + } + } + else + { + $time_period = gmdate($mybb->settings['dateformat'], $event['starttime_user']).", ".gmdate($mybb->settings['timeformat'], $event['starttime_user']); + $time_period .= " - "; + $time_period .= gmdate($mybb->settings['dateformat'], $event['endtime_user']).", ".gmdate($mybb->settings['timeformat'], $event['endtime_user']); + } + } + else + { + $time_period = gmdate($mybb->settings['dateformat'], $event['starttime_user']); + } + + $repeats = fetch_friendly_repetition($event); + if($repeats) + { + eval("\$repeats = \"".$templates->get("calendar_repeats")."\";"); + } + + $edit_event = $moderator_options = $event_class = ""; + if($calendar_permissions['canmoderateevents'] == 1 || ($mybb->user['uid'] > 0 && $mybb->user['uid'] == $event['uid'])) + { + eval("\$edit_event = \"".$templates->get("calendar_event_editbutton")."\";"); + if($calendar_permissions['canmoderateevents'] == 1) + { + if($event['visible'] == 1) + { + $approve = $lang->unapprove_event; + $approve_value = "unapprove"; + } + else + { + $approve = $lang->approve_event; + $approve_value = "approve"; + } + eval("\$moderator_options = \"".$templates->get("calendar_event_modoptions")."\";"); + } + if($event['visible'] == 0) + { + $event_class = " trow_shaded"; + } + } + eval("\$events .= \"".$templates->get("calendar_dayview_event")."\";"); + } + } + + $yearsel = ''; + for($year_sel = my_date("Y"); $year_sel < (my_date("Y") + 5); ++$year_sel) + { + eval("\$yearsel .= \"".$templates->get("calendar_year_sel")."\";"); + } + + $addevent = ''; + if($mybb->usergroup['canaddevents'] == 1) + { + eval("\$addevent = \"".$templates->get("calendar_addeventlink")."\";"); + } + + if(!$events) + { + $lang->no_events = $lang->sprintf($lang->no_events, $calendar['cid'], $day, $month, $year); + eval("\$events = \"".$templates->get("calendar_dayview_noevents")."\";"); + } + + // Now output the page + $plugins->run_hooks("calendar_dayview_end"); + + eval("\$day_view = \"".$templates->get("calendar_dayview")."\";"); + output_page($day_view); +} + +// View all events for a specific week +if($mybb->input['action'] == "weekview") +{ + // Showing a particular calendar + if($mybb->input['calendar']) + { + $query = $db->simple_select("calendars", "*", "cid='{$mybb->input['calendar']}'"); + $calendar = $db->fetch_array($query); + } + // Showing the default calendar + else + { + $query = $db->simple_select("calendars", "*", "disporder='1'"); + $calendar = $db->fetch_array($query); + } + + // Invalid calendar? + if(!$calendar) + { + error($lang->invalid_calendar); + } + + // Do we have permission to view this calendar? + $calendar_permissions = get_calendar_permissions($calendar['cid']); + if($calendar_permissions['canviewcalendar'] != 1) + { + error_no_permission(); + } + + $weekdays = fetch_weekday_structure($calendar['startofweek']); + + $yearsel = ''; + for($year_sel = my_date("Y"); $year_sel < (my_date("Y") + 5); ++$year_sel) + { + eval("\$yearsel .= \"".$templates->get("calendar_year_sel")."\";"); + } + + // No incoming week, show THIS week + if(empty($mybb->input['week'])) + { + list($day, $month, $year) = explode("-", my_date("j-n-Y")); + $php_weekday = gmdate("w", gmmktime(0, 0, 0, $month, $day, $year)); + $my_weekday = array_search($php_weekday, $weekdays); + // So now we have the start day of this week to show + $start_day = $day-$my_weekday; + $mybb->input['week'] = gmmktime(0, 0, 0, $month, $start_day, $year); + } + else + { + $mybb->input['week'] = (int)str_replace("n", "-", $mybb->get_input('week')); + // No negative years please ;) + if($mybb->input['week'] < -62167219200) + { + $mybb->input['week'] = -62167219200; + } + } + + // This is where we've come from and where we're headed + $week_from = explode("-", gmdate("j-n-Y", $mybb->input['week'])); + $week_from_one = $week_from[1]; + $friendly_week_from = gmdate($mybb->settings['dateformat'], $mybb->input['week']); + $week_to_stamp = gmmktime(0, 0, 0, $week_from[1], $week_from[0]+6, $week_from[2]); + $week_to = explode("-", gmdate("j-n-Y-t", $week_to_stamp)); + $friendly_week_to = gmdate($mybb->settings['dateformat'], $week_to_stamp); + + add_breadcrumb(htmlspecialchars_uni($calendar['name']), get_calendar_link($calendar['cid'])); + add_breadcrumb("{$monthnames[$week_from[1]]} {$week_from[2]}", get_calendar_link($calendar['cid'], $week_from[2], $week_from[1])); + add_breadcrumb($lang->weekly_overview); + + $plugins->run_hooks("calendar_weekview_start"); + + // Establish if we have a month ending in this week + if($week_from[1] != $week_to[1]) + { + $different_months = true; + $week_months = array(array($week_from[1], $week_from[2]), array($week_to[1], $week_to[2])); + $bday_months = array($week_from[1], $week_to[1]); + } + else + { + $week_months = array(array($week_from[1], $week_from[2])); + $bday_months = array($week_from[1]); + } + + // Load Birthdays for this month + if($calendar['showbirthdays'] == 1) + { + $birthdays = get_birthdays($bday_months); + } + + // We load events for the entire month date range - for our mini calendars too + $events_from = gmmktime(0, 0, 0, $week_from[1], 1, $week_from[2]); + $events_to = gmmktime(0, 0, 0, $week_to[1], $week_to[3], $week_to[2]); + + $events_cache = get_events($calendar, $events_from, $events_to, $calendar_permissions['canmoderateevents']); + + $today = my_date("dnY"); + + $next_week = $mybb->input['week'] + 604800; + $next_link = get_calendar_week_link($calendar['cid'], $next_week); + $prev_week = $mybb->input['week'] - 604800; + $prev_link = get_calendar_week_link($calendar['cid'], $prev_week); + + $weekday_date = $mybb->input['week']; + + while($weekday_date <= $week_to_stamp) + { + $weekday = gmdate("w", $weekday_date); + $weekday_name = fetch_weekday_name($weekday); + $weekday_month = gmdate("n", $weekday_date); + $weekday_year = gmdate("Y", $weekday_date); + $weekday_day = gmdate("j", $weekday_date); + + // Special shading for today + $day_shaded = ''; + if(gmdate("dnY", $weekday_date) == $today) + { + $day_shaded = ' trow_shaded'; + } + + $day_events = ''; + + // Any events on this specific day? + if(is_array($events_cache) && array_key_exists("{$weekday_day}-{$weekday_month}-{$weekday_year}", $events_cache)) + { + foreach($events_cache["$weekday_day-$weekday_month-$weekday_year"] as $event) + { + $event['eventlink'] = get_event_link($event['eid']); + $event['name'] = htmlspecialchars_uni($event['name']); + $event['fullname'] = $event['name']; + if(my_strlen($event['name']) > 50) + { + $event['name'] = my_substr($event['name'], 0, 50) . "..."; + } + // Events over more than one day + $time_period = ''; + if($event['endtime'] > 0 && $event['endtime'] != $event['starttime']) + { + $start_day = gmmktime(0, 0, 0, gmdate("n", $event['starttime_user']), gmdate("j", $event['starttime_user']), gmdate("Y", $event['starttime_user'])); + $end_day = gmmktime(0, 0, 0, gmdate("n", $event['endtime_user']), gmdate("j", $event['endtime_user']), gmdate("Y", $event['endtime_user'])); + $start_time = gmdate("Hi", $event['starttime_user']); + $end_time = gmdate("Hi", $event['endtime_user']); + // Event only runs over one day + if($start_day == $end_day || $event['repeats'] > 0) + { + // Event runs all day + if($start_time == 0000 && $end_time == 2359) + { + $time_period = $lang->all_day; + } + else + { + $time_period = gmdate($mybb->settings['timeformat'], $event['starttime_user'])." - ".gmdate($mybb->settings['timeformat'], $event['endtime_user']); + } + } + // Event starts on this day + else if($start_day == $weekday_date) + { + // Event runs all day + if($start_time == 0000) + { + $time_period = $lang->all_day; + } + else + { + $time_period = $lang->starts.gmdate($mybb->settings['timeformat'], $event['starttime_user']); + } + } + // Event finishes on this day + else if($end_day == $weekday_date) + { + // Event runs all day + if($end_time == 2359) + { + $time_period = $lang->all_day; + } + else + { + $time_period = $lang->finishes.gmdate($mybb->settings['timeformat'], $event['endtime_user']); + } + } + // Event is in the middle + else + { + $time_period = $lang->all_day; + } + } + $event_time = ''; + if($time_period) + { + eval("\$event_time = \"".$templates->get("calendar_weekview_day_event_time")."\";"); + } + if($event['private'] == 1) + { + $event_class = " private_event"; + } + else + { + $event_class = " public_event"; + } + if($event['visible'] == 0) + { + $event_class .= " trow_shaded"; + } + eval("\$day_events .= \"".$templates->get("calendar_weekview_day_event")."\";"); + } + } + + // Birthdays on this day? + $day_birthdays = $calendar_link = $birthday_lang = ''; + if($calendar['showbirthdays'] && is_array($birthdays) && array_key_exists("{$weekday_day}-{$weekday_month}", $birthdays)) + { + $bday_count = count($birthdays["$weekday_day-$weekday_month"]); + if($bday_count > 1) + { + $birthday_lang = $lang->birthdays; + } + else + { + $birthday_lang = $lang->birthday; + } + + $calendar_link = get_calendar_link($calendar['cid'], $weekday_year, $weekday_month, $weekday_day); + eval("\$day_birthdays = \"".$templates->get("calendar_weekview_day_birthdays")."\";"); + } + + $day_link = get_calendar_link($calendar['cid'], $weekday_year, $weekday_month, $weekday_day); + if(!isset($day_bits[$weekday_month])) + { + $day_bits[$weekday_month] = ''; + } + eval("\$day_bits[$weekday_month] .= \"".$templates->get("calendar_weekview_day")."\";"); + $day_events = $day_birthdays = ""; + $weekday_date = gmmktime(0, 0, 0, $weekday_month, $weekday_day+1, $weekday_year); + } + + // Now we build our month headers + $mini_calendars = $weekday_bits = ''; + foreach($week_months as $month) + { + $weekday_month = $monthnames[$month[0]]; + $weekday_year = $month[1]; + + // Fetch mini calendar for each month in this week + $mini_calendars .= build_mini_calendar($calendar, $month[0], $weekday_year, $events_cache)."
    "; + + // Fetch out the days for this month + $days = $day_bits[$month[0]]; + + eval("\$weekday_bits .= \"".$templates->get("calendar_weekview_month")."\";"); + } + + $addevent = ''; + if($mybb->usergroup['canaddevents'] == 1) + { + eval("\$addevent = \"".$templates->get("calendar_addeventlink")."\";"); + } + + // Now output the page + $plugins->run_hooks("calendar_weekview_end"); + + eval("\$weekview = \"".$templates->get("calendar_weekview")."\";"); + output_page($weekview); +} + +// Showing a calendar +if(!$mybb->input['action']) +{ + // Showing a particular calendar + if($mybb->input['calendar']) + { + $query = $db->simple_select("calendars", "*", "cid='{$mybb->input['calendar']}'"); + $calendar = $db->fetch_array($query); + } + // Showing the default calendar + else + { + $query = $db->simple_select("calendars", "*", "", array('order_by' => 'disporder', 'limit' => 1)); + $calendar = $db->fetch_array($query); + } + + // Invalid calendar? + if(!$calendar['cid']) + { + error($lang->invalid_calendar); + } + + // Do we have permission to view this calendar? + $calendar_permissions = get_calendar_permissions($calendar['cid']); + + if($calendar_permissions['canviewcalendar'] != 1) + { + error_no_permission(); + } + + $plugins->run_hooks("calendar_main_view"); + + // Incoming year? + $mybb->input['year'] = $mybb->get_input('year', 1); + if($mybb->input['year'] && $mybb->input['year'] <= my_date("Y")+5) + { + $year = $mybb->input['year']; + } + else + { + $year = my_date("Y"); + } + + // Then the month + $mybb->input['month'] = $mybb->get_input('month', 1); + if($mybb->input['month'] >= 1 && $mybb->input['month'] <= 12) + { + $month = $mybb->input['month']; + } + else + { + $month = my_date("n"); + } + + add_breadcrumb(htmlspecialchars_uni($calendar['name']), get_calendar_link($calendar['cid'])); + add_breadcrumb("$monthnames[$month] $year", get_calendar_link($calendar['cid'], $year, $month)); + + $next_month = get_next_month($month, $year); + $prev_month = get_prev_month($month, $year); + + $prev_link = get_calendar_link($calendar['cid'], $prev_month['year'], $prev_month['month']); + $next_link = get_calendar_link($calendar['cid'], $next_month['year'], $next_month['month']); + + // Start constructing the calendar + + $weekdays = fetch_weekday_structure($calendar['startofweek']); + + $month_start_weekday = gmdate("w", gmmktime(0, 0, 0, $month, $calendar['startofweek']+1, $year)); + + $prev_month_days = gmdate("t", gmmktime(0, 0, 0, $prev_month['month'], 1, $prev_month['year'])); + + // This is if we have days in the previous month to show + if($month_start_weekday != $weekdays[0] || $calendar['startofweek'] != 0) + { + $prev_days = $day = gmdate("t", gmmktime(0, 0, 0, $prev_month['month'], 1, $prev_month['year'])); + $day -= array_search(($month_start_weekday), $weekdays); + $day += $calendar['startofweek']+1; + if($day > $prev_month_days+1) + { + // Go one week back + $day -= 7; + } + $calendar_month = $prev_month['month']; + $calendar_year = $prev_month['year']; + } + else + { + $day = $calendar['startofweek']+1; + $calendar_month = $month; + $calendar_year = $year; + } + + // So now we fetch events for this month (nb, cache events for past month, current month and next month for mini calendars too) + $start_timestamp = gmmktime(0, 0, 0, $calendar_month, $day, $calendar_year); + $num_days = gmdate("t", gmmktime(0, 0, 0, $month, 1, $year)); + + $month_end_weekday = gmdate("w", gmmktime(0, 0, 0, $month, $num_days, $year)); + $next_days = 6-$month_end_weekday+$calendar['startofweek']; + + // More than a week? Go one week back + if($next_days >= 7) + { + $next_days -= 7; + } + if($next_days > 0) + { + $end_timestamp = gmmktime(23, 59, 59, $next_month['month'], $next_days, $next_month['year']); + } + else + { + // We don't need days from the next month + $end_timestamp = gmmktime(23, 59, 59, $month, $num_days, $year); + } + + $events_cache = get_events($calendar, $start_timestamp, $end_timestamp, $calendar_permissions['canmoderateevents']); + + // Fetch birthdays + if($calendar['showbirthdays']) + { + $bday_months = array($month, $prev_month['month'], $next_month['month']); + $birthdays = get_birthdays($bday_months); + } + + $today = my_date("dnY"); + $weekday_headers = ''; + + // Build weekday headers + foreach($weekdays as $weekday) + { + $weekday_name = fetch_weekday_name($weekday); + eval("\$weekday_headers .= \"".$templates->get("calendar_weekdayheader")."\";"); + } + + $in_month = 0; + $day_bits = $calendar_rows = ''; + for($row = 0; $row < 6; ++$row) // Iterate weeks (each week gets a row) + { + foreach($weekdays as $weekday_id => $weekday) + { + // Current month always starts on 1st row + if($row == 0 && $day == $calendar['startofweek']+1) + { + $in_month = 1; + $calendar_month = $month; + $calendar_year = $year; + } + else if($calendar_month == $prev_month['month'] && $day > $prev_month_days) + { + $day = 1; + $in_month = 1; + $calendar_month = $month; + $calendar_year = $year; + } + else if($day > $num_days && $calendar_month != $prev_month['month']) + { + $in_month = 0; + $calendar_month = $next_month['month']; + $calendar_year = $next_month['year']; + $day = 1; + if($calendar_month == $month) + { + $in_month = 1; + } + } + + if($weekday_id == 0) + { + $week_stamp = gmmktime(0, 0, 0, $calendar_month, $day, $calendar_year); + $week_link = get_calendar_week_link($calendar['cid'], $week_stamp); + } + + if($weekday_id == 0 && $calendar_month == $next_month['month']) + { + break; + } + + $day_events = ''; + + // Any events on this specific day? + if(is_array($events_cache) && array_key_exists("{$day}-{$calendar_month}-{$calendar_year}", $events_cache)) + { + $total_events = count($events_cache["$day-$calendar_month-$calendar_year"]); + if($total_events > $calendar['eventlimit'] && $calendar['eventlimit'] != 0) + { + if($total_events > 1) + { + $day_events = "\n"; + } + else + { + $day_events = "\n"; + } + } + else + { + foreach($events_cache["$day-$calendar_month-$calendar_year"] as $event) + { + $event['eventlink'] = get_event_link($event['eid']); + $event['fullname'] = htmlspecialchars_uni($event['name']); + if(my_strlen($event['name']) > 15) + { + $event['name'] = my_substr($event['name'], 0, 15) . "..."; + } + $event['name'] = htmlspecialchars_uni($event['name']); + if($event['private'] == 1) + { + $event_class = " private_event"; + } + else + { + $event_class = " public_event"; + } + if($event['visible'] == 0) + { + $event_class .= " trow_shaded"; + } + eval("\$day_events .= \"".$templates->get("calendar_eventbit")."\";"); + } + } + } + + // Birthdays on this day? + $day_birthdays = $birthday_lang = ''; + if($calendar['showbirthdays'] && is_array($birthdays) && array_key_exists("$day-$calendar_month", $birthdays)) + { + $bday_count = count($birthdays["$day-$calendar_month"]); + if($bday_count > 1) + { + $birthday_lang = $lang->birthdays; + } + else + { + $birthday_lang = $lang->birthday; + } + + $calendar['link'] = get_calendar_link($calendar['cid'], $calendar_year, $calendar_month, $day); + eval("\$day_birthdays = \"".$templates->get("calendar_weekrow_day_birthdays")."\";"); + } + + $day_link = get_calendar_link($calendar['cid'], $calendar_year, $calendar_month, $day); + + // Is the current day + if($day.$calendar_month.$year == $today && $month == $calendar_month) + { + $day_class = "trow_sep"; + } + // Not in this month + else if($in_month == 0) + { + $day_class = "trow1"; + } + // Just a normal day in this month + else + { + $day_class = "trow2"; + } + eval("\$day_bits .= \"".$templates->get("calendar_weekrow_day")."\";"); + $day_birthdays = $day_events = ""; + ++$day; + } + if($day_bits) + { + eval("\$calendar_rows .= \"".$templates->get("calendar_weekrow")."\";"); + } + $day_bits = ""; + } + + $yearsel = ''; + for($year_sel = my_date("Y"); $year_sel < (my_date("Y") + 5); ++$year_sel) + { + eval("\$yearsel .= \"".$templates->get("calendar_year_sel")."\";"); + } + + $addevent = ''; + if($mybb->usergroup['canaddevents'] == 1) + { + eval("\$addevent = \"".$templates->get("calendar_addeventlink")."\";"); + } + + $plugins->run_hooks("calendar_end"); + + eval("\$calendar = \"".$templates->get("calendar")."\";"); + output_page($calendar); +} diff --git a/Upload/captcha.php b/Upload/captcha.php new file mode 100644 index 0000000..d53f570 --- /dev/null +++ b/Upload/captcha.php @@ -0,0 +1,312 @@ +input['imagehash'] = $mybb->get_input('imagehash'); +if($mybb->input['imagehash'] == "test") +{ + $imagestring = "MyBB"; +} +elseif($mybb->input['imagehash']) +{ + $query = $db->simple_select("captcha", "*", "imagehash='".$db->escape_string($mybb->get_input('imagehash'))."' AND used=0", array("limit" => 1)); + $regimage = $db->fetch_array($query); + if(!$regimage) + { + exit; + } + // Mark captcha as used + $db->update_query('captcha', array('used' => 1), "imagehash='".$db->escape_string($regimage['imagehash'])."'"); + $imagestring = $regimage['imagestring']; +} +else +{ + exit; +} + +$ttf_fonts = array(); + +// We have support for true-type fonts (FreeType 2) +if(function_exists("imagefttext")) +{ + // Get a list of the files in the 'catpcha_fonts' directory + $ttfdir = @opendir(MYBB_ROOT."inc/captcha_fonts"); + if($ttfdir !== false) + { + while(($file = readdir($ttfdir)) !== false) + { + // If this file is a ttf file, add it to the list + if(is_file(MYBB_ROOT."inc/captcha_fonts/".$file) && get_extension($file) == "ttf") + { + $ttf_fonts[] = MYBB_ROOT."inc/captcha_fonts/".$file; + } + } + closedir($ttfdir); + } +} + +// Have one or more TTF fonts in our array, we can use TTF captha's +if(count($ttf_fonts) > 0) +{ + $use_ttf = 1; +} +else +{ + $use_ttf = 0; +} + +// Check for GD >= 2, create base image +if(gd_version() >= 2) +{ + $im = imagecreatetruecolor($img_width, $img_height); +} +else +{ + $im = imagecreate($img_width, $img_height); +} + +// No GD support, die. +if(!$im) +{ + die("No GD support."); +} + +// Fill the background with white +$bg_color = imagecolorallocate($im, 255, 255, 255); +imagefill($im, 0, 0, $bg_color); + +// Draw random circles, squares or lines? +$to_draw = my_rand(0, 2); +if($to_draw == 1) +{ + draw_circles($im); +} +else if($to_draw == 2) +{ + draw_squares($im); +} +else +{ + draw_lines($im); +} + +// Draw dots on the image +draw_dots($im); + +// Write the image string to the image +draw_string($im, $imagestring); + +// Draw a nice border around the image +$border_color = imagecolorallocate($im, 0, 0, 0); +imagerectangle($im, 0, 0, $img_width-1, $img_height-1, $border_color); + +// Output the image +header("Content-type: image/png"); +imagepng($im); +imagedestroy($im); + +/** + * Draws a random number of lines on the image. + * + * @param resource The image. + */ +function draw_lines(&$im) +{ + global $img_width, $img_height; + + for($i = 10; $i < $img_width; $i += 10) + { + $color = imagecolorallocate($im, my_rand(150, 255), my_rand(150, 255), my_rand(150, 255)); + imageline($im, $i, 0, $i, $img_height, $color); + } + for($i = 10; $i < $img_height; $i += 10) + { + $color = imagecolorallocate($im, my_rand(150, 255), my_rand(150, 255), my_rand(150, 255)); + imageline($im, 0, $i, $img_width, $i, $color); + } +} + +/** + * Draws a random number of circles on the image. + * + * @param resource The image. + */ +function draw_circles(&$im) +{ + global $img_width, $img_height; + + $circles = $img_width*$img_height / 100; + for($i = 0; $i <= $circles; ++$i) + { + $color = imagecolorallocate($im, my_rand(180, 255), my_rand(180, 255), my_rand(180, 255)); + $pos_x = my_rand(1, $img_width); + $pos_y = my_rand(1, $img_height); + $circ_width = ceil(my_rand(1, $img_width)/2); + $circ_height = my_rand(1, $img_height); + imagearc($im, $pos_x, $pos_y, $circ_width, $circ_height, 0, my_rand(200, 360), $color); + } +} + +/** + * Draws a random number of dots on the image. + * + * @param resource The image. + */ +function draw_dots(&$im) +{ + global $img_width, $img_height; + + $dot_count = $img_width*$img_height/5; + for($i = 0; $i <= $dot_count; ++$i) + { + $color = imagecolorallocate($im, my_rand(200, 255), my_rand(200, 255), my_rand(200, 255)); + imagesetpixel($im, my_rand(0, $img_width), my_rand(0, $img_height), $color); + } +} + +/** + * Draws a random number of squares on the image. + * + * @param resource The image. + */ +function draw_squares(&$im) +{ + global $img_width, $img_height; + + $square_count = 30; + for($i = 0; $i <= $square_count; ++$i) + { + $color = imagecolorallocate($im, my_rand(150, 255), my_rand(150, 255), my_rand(150, 255)); + $pos_x = my_rand(1, $img_width); + $pos_y = my_rand(1, $img_height); + $sq_width = $sq_height = my_rand(10, 20); + $pos_x2 = $pos_x + $sq_height; + $pos_y2 = $pos_y + $sq_width; + imagefilledrectangle($im, $pos_x, $pos_y, $pos_x2, $pos_y2, $color); + } +} + +/** + * Writes text to the image. + * + * @param resource The image. + * @param string The string to be written + */ +function draw_string(&$im, $string) +{ + global $use_ttf, $min_size, $max_size, $min_angle, $max_angle, $ttf_fonts, $img_height, $img_width; + + if(empty($string)) + { + return false; + } + + $spacing = $img_width / my_strlen($string); + $string_length = my_strlen($string); + for($i = 0; $i < $string_length; ++$i) + { + // Using TTF fonts + if($use_ttf) + { + // Select a random font size + $font_size = my_rand($min_size, $max_size); + + // Select a random font + $font = array_rand($ttf_fonts); + $font = $ttf_fonts[$font]; + + // Select a random rotation + $rotation = my_rand($min_angle, $max_angle); + + // Set the colour + $r = my_rand(0, 200); + $g = my_rand(0, 200); + $b = my_rand(0, 200); + $color = imagecolorallocate($im, $r, $g, $b); + + // Fetch the dimensions of the character being added + $dimensions = imageftbbox($font_size, $rotation, $font, $string[$i], array()); + $string_width = $dimensions[2] - $dimensions[0]; + $string_height = $dimensions[3] - $dimensions[5]; + + // Calculate character offsets + //$pos_x = $pos_x + $string_width + ($string_width/4); + $pos_x = $spacing / 4 + $i * $spacing; + $pos_y = ceil(($img_height-$string_height/2)); + + // Draw a shadow + $shadow_x = my_rand(-3, 3) + $pos_x; + $shadow_y = my_rand(-3, 3) + $pos_y; + $shadow_color = imagecolorallocate($im, $r+20, $g+20, $b+20); + imagefttext($im, $font_size, $rotation, $shadow_x, $shadow_y, $shadow_color, $font, $string[$i], array()); + + // Write the character to the image + imagefttext($im, $font_size, $rotation, $pos_x, $pos_y, $color, $font, $string[$i], array()); + } + else + { + // Get width/height of the character + $string_width = imagefontwidth(5); + $string_height = imagefontheight(5); + + // Calculate character offsets + $pos_x = $spacing / 4 + $i * $spacing; + $pos_y = $img_height / 2 - $string_height -10 + my_rand(-3, 3); + + // Create a temporary image for this character + if(gd_version() >= 2) + { + $temp_im = imagecreatetruecolor(15, 20); + } + else + { + $temp_im = imagecreate(15, 20); + } + $bg_color = imagecolorallocate($temp_im, 255, 255, 255); + imagefill($temp_im, 0, 0, $bg_color); + imagecolortransparent($temp_im, $bg_color); + + // Set the colour + $r = my_rand(0, 200); + $g = my_rand(0, 200); + $b = my_rand(0, 200); + $color = imagecolorallocate($temp_im, $r, $g, $b); + + // Draw a shadow + $shadow_x = my_rand(-1, 1); + $shadow_y = my_rand(-1, 1); + $shadow_color = imagecolorallocate($temp_im, $r+50, $g+50, $b+50); + imagestring($temp_im, 5, 1+$shadow_x, 1+$shadow_y, $string[$i], $shadow_color); + + imagestring($temp_im, 5, 1, 1, $string[$i], $color); + + // Copy to main image + imagecopyresized($im, $temp_im, $pos_x, $pos_y, 0, 0, 40, 55, 15, 20); + imagedestroy($temp_im); + } + } +} + diff --git a/Upload/contact.php b/Upload/contact.php new file mode 100644 index 0000000..6bf53f2 --- /dev/null +++ b/Upload/contact.php @@ -0,0 +1,284 @@ +load("contact"); + +$plugins->run_hooks('contact_start'); + +// Make navigation +add_breadcrumb($lang->contact, "contact.php"); + +if($mybb->settings['contact'] != 1 || (!$mybb->user['uid'] && $mybb->settings['contact_guests'] == 1)) +{ + error_no_permission(); +} + +// Check group limits +if($mybb->usergroup['maxemails'] > 0) +{ + if($mybb->user['uid'] > 0) + { + $user_check = "fromuid='{$mybb->user['uid']}'"; + } + else + { + $user_check = "ipaddress=".$db->escape_binary($session->packedip); + } + + $query = $db->simple_select("maillogs", "COUNT(*) AS sent_count", "{$user_check} AND dateline >= '".(TIME_NOW - (60*60*24))."'"); + $sent_count = $db->fetch_field($query, "sent_count"); + if($sent_count >= $mybb->usergroup['maxemails']) + { + $lang->error_max_emails_day = $lang->sprintf($lang->error_max_emails_day, $mybb->usergroup['maxemails']); + error($lang->error_max_emails_day); + } +} + +// Check email flood control +if($mybb->usergroup['emailfloodtime'] > 0) +{ + if($mybb->user['uid'] > 0) + { + $user_check = "fromuid='{$mybb->user['uid']}'"; + } + else + { + $user_check = "ipaddress=".$db->escape_binary($session->packedip); + } + + $timecut = TIME_NOW-$mybb->usergroup['emailfloodtime']*60; + + $query = $db->simple_select("maillogs", "mid, dateline", "{$user_check} AND dateline > '{$timecut}'", array('order_by' => "dateline", 'order_dir' => "DESC")); + $last_email = $db->fetch_array($query); + + // Users last email was within the flood time, show the error + if($last_email['mid']) + { + $remaining_time = ($mybb->usergroup['emailfloodtime']*60)-(TIME_NOW-$last_email['dateline']); + + if($remaining_time == 1) + { + $lang->error_emailflooding = $lang->sprintf($lang->error_emailflooding_1_second, $mybb->usergroup['emailfloodtime']); + } + elseif($remaining_time < 60) + { + $lang->error_emailflooding = $lang->sprintf($lang->error_emailflooding_seconds, $mybb->usergroup['emailfloodtime'], $remaining_time); + } + elseif($remaining_time > 60 && $remaining_time < 120) + { + $lang->error_emailflooding = $lang->sprintf($lang->error_emailflooding_1_minute, $mybb->usergroup['emailfloodtime']); + } + else + { + $remaining_time_minutes = ceil($remaining_time/60); + $lang->error_emailflooding = $lang->sprintf($lang->error_emailflooding_minutes, $mybb->usergroup['emailfloodtime'], $remaining_time_minutes); + } + + error($lang->error_emailflooding); + } +} + +$errors = array(); + +$mybb->input['message'] = trim_blank_chrs($mybb->get_input('message')); +$mybb->input['subject'] = trim_blank_chrs($mybb->get_input('subject')); +$mybb->input['email'] = trim_blank_chrs($mybb->get_input('email')); + +if($mybb->request_method == "post") +{ + // Verify incoming POST request + verify_post_check($mybb->get_input('my_post_key')); + + $plugins->run_hooks('contact_do_start'); + + // Validate input + if(empty($mybb->input['subject'])) + { + $errors[] = $lang->contact_no_subject; + } + + if(strlen($mybb->input['subject']) > $mybb->settings['contact_maxsubjectlength'] && $mybb->settings['contact_maxsubjectlength'] > 0) + { + $errors[] = $lang->sprintf($lang->subject_too_long, $mybb->settings['contact_maxsubjectlength'], strlen($mybb->input['subject'])); + } + + if(empty($mybb->input['message'])) + { + $errors[] = $lang->contact_no_message; + } + + if(strlen($mybb->input['message']) > $mybb->settings['contact_maxmessagelength'] && $mybb->settings['contact_maxmessagelength'] > 0) + { + $errors[] = $lang->sprintf($lang->message_too_long, $mybb->settings['contact_maxmessagelength'], strlen($mybb->input['message'])); + } + + if(strlen($mybb->input['message']) < $mybb->settings['contact_minmessagelength'] && $mybb->settings['contact_minmessagelength'] > 0) + { + $errors[] = $lang->sprintf($lang->message_too_short, $mybb->settings['contact_minmessagelength'], strlen($mybb->input['message'])); + } + + if(empty($mybb->input['email'])) + { + $errors[] = $lang->contact_no_email; + } + else + { + // Validate email + if(!validate_email_format($mybb->input['email'])) + { + $errors[] = $lang->contact_no_email; + } + } + + // Should we have a CAPTCHA? Perhaps yes... + if($mybb->settings['captchaimage']) + { + $captcha = new captcha; + + if($captcha->validate_captcha() == false) + { + // CAPTCHA validation failed + foreach($captcha->get_errors() as $error) + { + $errors[] = $error; + } + } + } + + if(!$mybb->user['uid'] && $mybb->settings['stopforumspam_on_contact']) + { + require_once MYBB_ROOT . '/inc/class_stopforumspamchecker.php'; + + $stop_forum_spam_checker = new StopForumSpamChecker( + $plugins, + $mybb->settings['stopforumspam_min_weighting_before_spam'], + $mybb->settings['stopforumspam_check_usernames'], + $mybb->settings['stopforumspam_check_emails'], + $mybb->settings['stopforumspam_check_ips'], + $mybb->settings['stopforumspam_log_blocks'] + ); + + try { + if($stop_forum_spam_checker->is_user_a_spammer('', $mybb->input['email'], get_ip())) + { + $errors[] = $lang->error_stop_forum_spam_spammer; + } + } + catch (Exception $e) + { + if($mybb->settings['stopforumspam_block_on_error']) + { + $errors[] = $lang->error_stop_forum_spam_fetching; + } + } + } + + if(empty($errors)) + { + if($mybb->settings['contact_badwords'] == 1) + { + // Load the post parser + require_once MYBB_ROOT."inc/class_parser.php"; + $parser = new postParser; + + $parser_options = array( + 'filter_badwords' => 1 + ); + + $mybb->input['subject'] = $parser->parse_message($mybb->input['subject'], $parser_options); + $mybb->input['message'] = $parser->parse_message($mybb->input['message'], $parser_options); + } + + $user = $lang->na; + if($mybb->user['uid']) + { + $user = $mybb->user['username'].' - '.$mybb->settings['bburl'].'/'.get_profile_link($mybb->user['uid']); + } + + $subject = $lang->sprintf($lang->email_contact_subject, $mybb->input['subject']); + $message = $lang->sprintf($lang->email_contact, $mybb->input['email'], $user, $session->ipaddress, $mybb->input['message']); + + // Email the administrator + my_mail($mybb->settings['adminemail'], $subject, $message, $mybb->input['email']); + + $plugins->run_hooks('contact_do_end'); + + if($mybb->settings['mail_logging'] > 0) + { + // Log the message + $log_entry = array( + "subject" => $db->escape_string($subject), + "message" => $db->escape_string($message), + "dateline" => TIME_NOW, + "fromuid" => $mybb->user['uid'], + "fromemail" => $db->escape_string($mybb->input['email']), + "touid" => 0, + "toemail" => $db->escape_string($mybb->settings['adminemail']), + "tid" => 0, + "ipaddress" => $db->escape_binary($session->packedip), + "type" => 3 + ); + $db->insert_query("maillogs", $log_entry); + } + + // Redirect + redirect('contact.php', $lang->contact_success_message); + } + else + { + $errors = inline_error($errors); + } +} + +if(empty($errors)) +{ + $errors = ''; +} + +// Generate CAPTCHA? +if($mybb->settings['captchaimage']) +{ + $post_captcha = new captcha(true, "post_captcha"); + + if($post_captcha->html) + { + $captcha = $post_captcha->html; + } +} +else +{ + $captcha = ''; +} + +$mybb->input['subject'] = htmlspecialchars_uni($mybb->input['subject']); +$mybb->input['message'] = htmlspecialchars_uni($mybb->input['message']); + +if($mybb->user['uid'] && !$mybb->get_input('email')) +{ + $mybb->input['email'] = htmlspecialchars_uni($mybb->user['email']); +} +else +{ + $mybb->input['email'] = htmlspecialchars_uni($mybb->get_input('email')); +} + +$plugins->run_hooks('contact_end'); + +eval("\$page = \"".$templates->get("contact")."\";"); +output_page($page); diff --git a/Upload/css.php b/Upload/css.php new file mode 100644 index 0000000..923dd53 --- /dev/null +++ b/Upload/css.php @@ -0,0 +1,40 @@ +get_input('stylesheet', 1); + +if($stylesheet) +{ + $options = array( + "limit" => 1 + ); + $query = $db->simple_select("themestylesheets", "stylesheet", "sid=".$stylesheet, $options); + $stylesheet = $db->fetch_field($query, "stylesheet"); + + $plugins->run_hooks("css_start"); + + if(!empty($mybb->settings['minifycss'])) + { + $stylesheet = minify_stylesheet($stylesheet); + } + + $plugins->run_hooks("css_end"); + + header("Content-type: text/css"); + echo $stylesheet; +} +exit; diff --git a/Upload/editpost.php b/Upload/editpost.php new file mode 100644 index 0000000..a1597f5 --- /dev/null +++ b/Upload/editpost.php @@ -0,0 +1,920 @@ +load("editpost"); + +$plugins->run_hooks("editpost_start"); + +// No permission for guests +if(!$mybb->user['uid']) +{ + error_no_permission(); +} + +// Get post info +$pid = $mybb->get_input('pid', 1); + +// if we already have the post information... +if(isset($style) && $style['pid'] == $pid && $style['type'] != 'f') +{ + $post = &$style; +} +else +{ + $post = get_post($pid); +} + +if(!$post) +{ + error($lang->error_invalidpost); +} + +// Get thread info +$tid = $post['tid']; +$thread = get_thread($tid); + +if(!$thread) +{ + error($lang->error_invalidthread); +} + +$thread['subject'] = htmlspecialchars_uni($thread['subject']); + +// Get forum info +$fid = $post['fid']; +$forum = get_forum($fid); + +if($thread['visible'] == 0 && !is_moderator($fid, "canviewunapprove") || $thread['visible'] == -1 && !is_moderator($fid, "canviewdeleted") || ($thread['visible'] < -1 && $thread['uid'] != $mybb->user['uid'])) +{ + error($lang->error_invalidthread); +} +if(!$forum || $forum['type'] != "f") +{ + error($lang->error_closedinvalidforum); +} +if(($forum['open'] == 0 && !is_moderator($fid, "caneditposts")) || $mybb->user['suspendposting'] == 1) +{ + error_no_permission(); +} + +// Add prefix to breadcrumb +$breadcrumbprefix = ''; +if($thread['prefix']) +{ + $threadprefixes = build_prefixes(); + if(!empty($threadprefixes[$thread['prefix']])) + { + $breadcrumbprefix = $threadprefixes[$thread['prefix']]['displaystyle'].' '; + } +} + +// Make navigation +build_forum_breadcrumb($fid); +add_breadcrumb($breadcrumbprefix.$thread['subject'], get_thread_link($thread['tid'])); +add_breadcrumb($lang->nav_editpost); + +$forumpermissions = forum_permissions($fid); + +if($mybb->settings['bbcodeinserter'] != 0 && $forum['allowmycode'] != 0 && $mybb->user['showcodebuttons'] != 0) +{ + $codebuttons = build_mycode_inserter("message", $mybb->settings['smilieinserter']); +} +if($mybb->settings['smilieinserter'] != 0) +{ + $smilieinserter = build_clickable_smilies(); +} + +$mybb->input['action'] = $mybb->get_input('action'); +if(!$mybb->input['action'] || isset($mybb->input['previewpost'])) +{ + $mybb->input['action'] = "editpost"; +} + +if($mybb->input['action'] == "deletepost" && $mybb->request_method == "post") +{ + if(!is_moderator($fid, "candeleteposts")) + { + if($thread['closed'] == 1) + { + error($lang->redirect_threadclosed); + } + if($forumpermissions['candeleteposts'] == 0) + { + error_no_permission(); + } + if($mybb->user['uid'] != $post['uid']) + { + error_no_permission(); + } + // User can't delete unapproved post + if($post['visible'] == 0) + { + error_no_permission(); + } + } + if($post['visible'] == -1 && $mybb->settings['soft_delete'] == 1) + { + error($lang->error_already_deleted); + } +} +elseif($mybb->input['action'] == "restorepost" && $mybb->request_method == "post") +{ + if(!is_moderator($fid) || $post['visible'] != -1 || $mybb->settings['soft_delete'] == 0) + { + error_no_permission(); + } +} +else +{ + if(!is_moderator($fid, "caneditposts")) + { + if($thread['closed'] == 1) + { + error($lang->redirect_threadclosed); + } + if($forumpermissions['caneditposts'] == 0) + { + error_no_permission(); + } + if($mybb->user['uid'] != $post['uid']) + { + error_no_permission(); + } + // Edit time limit + $time = TIME_NOW; + if($mybb->usergroup['edittimelimit'] != 0 && $post['dateline'] < ($time-($mybb->usergroup['edittimelimit']*60))) + { + $lang->edit_time_limit = $lang->sprintf($lang->edit_time_limit, $mybb->usergroup['edittimelimit']); + error($lang->edit_time_limit); + } + // User can't edit unapproved post + if($post['visible'] == 0 || $post['visible'] == -1) + { + error_no_permission(); + } + } +} + +// Check if this forum is password protected and we have a valid password +check_forum_password($forum['fid']); + +if((empty($_POST) && empty($_FILES)) && $mybb->get_input('processed', 1) == '1') +{ + error($lang->error_cannot_upload_php_post); +} + +$attacherror = ''; +if($mybb->settings['enableattachments'] == 1 && !$mybb->get_input('attachmentaid', 1) && ($mybb->get_input('newattachment') || $mybb->get_input('updateattachment') || ($mybb->input['action'] == "do_editpost" && isset($mybb->input['submit']) && $_FILES['attachment']))) +{ + // Verify incoming POST request + verify_post_check($mybb->get_input('my_post_key')); + + // If there's an attachment, check it and upload it + if($_FILES['attachment']['size'] > 0 && $forumpermissions['canpostattachments'] != 0) + { + $query = $db->simple_select("attachments", "aid", "filename='".$db->escape_string($_FILES['attachment']['name'])."' AND pid='{$pid}'"); + $updateattach = $db->fetch_field($query, "aid"); + + $update_attachment = false; + if($updateattach > 0 && $mybb->get_input('updateattachment') && ($mybb->usergroup['caneditattachments'] || $forumpermissions['caneditattachments'])) + { + $update_attachment = true; + } + $attachedfile = upload_attachment($_FILES['attachment'], $update_attachment); + } + if(!empty($attachedfile['error'])) + { + eval("\$attacherror = \"".$templates->get("error_attacherror")."\";"); + $mybb->input['action'] = "editpost"; + } + if(!isset($mybb->input['submit'])) + { + $mybb->input['action'] = "editpost"; + } +} + +if($mybb->settings['enableattachments'] == 1 && $mybb->get_input('attachmentaid', 1) && isset($mybb->input['attachmentact']) && $mybb->input['action'] == "do_editpost" && $mybb->request_method == "post") // Lets remove/approve/unapprove the attachment +{ + // Verify incoming POST request + verify_post_check($mybb->get_input('my_post_key')); + + $mybb->input['attachmentaid'] = $mybb->get_input('attachmentaid', 1); + if($mybb->input['attachmentact'] == "remove") + { + remove_attachment($pid, "", $mybb->input['attachmentaid']); + } + elseif($mybb->get_input('attachmentact') == "approve" && is_moderator($fid, 'canapproveunapproveattachs')) + { + $update_sql = array("visible" => 1); + $db->update_query("attachments", $update_sql, "aid='{$mybb->input['attachmentaid']}'"); + update_thread_counters($post['tid'], array('attachmentcount' => "+1")); + } + elseif($mybb->get_input('attachmentact') == "unapprove" && is_moderator($fid, 'canapproveunapproveattachs')) + { + $update_sql = array("visible" => 0); + $db->update_query("attachments", $update_sql, "aid='{$mybb->input['attachmentaid']}'"); + update_thread_counters($post['tid'], array('attachmentcount' => "-1")); + } + if(!isset($mybb->input['submit'])) + { + $mybb->input['action'] = "editpost"; + } +} + +if($mybb->input['action'] == "deletepost" && $mybb->request_method == "post") +{ + // Verify incoming POST request + verify_post_check($mybb->get_input('my_post_key')); + + $plugins->run_hooks("editpost_deletepost"); + + if($mybb->get_input('delete', 1) == 1) + { + $query = $db->simple_select("posts", "pid", "tid='{$tid}'", array("limit" => 1, "order_by" => "dateline", "order_dir" => "asc")); + $firstcheck = $db->fetch_array($query); + if($firstcheck['pid'] == $pid) + { + $firstpost = 1; + } + else + { + $firstpost = 0; + } + + $modlogdata['fid'] = $fid; + $modlogdata['tid'] = $tid; + if($firstpost) + { + if($forumpermissions['candeletethreads'] == 1 || is_moderator($fid, "candeletethreads")) + { + require_once MYBB_ROOT."inc/class_moderation.php"; + $moderation = new Moderation; + + if($mybb->settings['soft_delete'] == 1) + { + $modlogdata['pid'] = $pid; + + $moderation->soft_delete_threads(array($tid)); + log_moderator_action($modlogdata, $lang->thread_soft_deleted); + } + else + { + $moderation->delete_thread($tid); + mark_reports($tid, "thread"); + log_moderator_action($modlogdata, $lang->thread_deleted); + } + + if($mybb->input['ajax'] == 1) + { + header("Content-type: application/json; charset={$lang->settings['charset']}"); + if($mybb->settings['soft_delete'] == 1 && is_moderator($fid)) + { + echo json_encode(array("data" => '1')); + } + else + { + echo json_encode(array("data" => '3', "url" => get_forum_link($fid))); + } + } + else + { + redirect(get_forum_link($fid), $lang->redirect_threaddeleted); + } + } + else + { + error_no_permission(); + } + } + else + { + if($forumpermissions['candeleteposts'] == 1 || is_moderator($fid, "candeleteposts")) + { + // Select the first post before this + require_once MYBB_ROOT."inc/class_moderation.php"; + $moderation = new Moderation; + + if($mybb->settings['soft_delete'] == 1) + { + $modlogdata['pid'] = $pid; + + $moderation->soft_delete_posts(array($pid)); + log_moderator_action($modlogdata, $lang->post_soft_deleted); + } + else + { + $moderation->delete_post($pid); + mark_reports($pid, "post"); + log_moderator_action($modlogdata, $lang->post_deleted); + } + + $query = $db->simple_select("posts", "pid", "tid='{$tid}' AND dateline <= '{$post['dateline']}'", array("limit" => 1, "order_by" => "dateline", "order_dir" => "desc")); + $next_post = $db->fetch_array($query); + if($next_post['pid']) + { + $redirect = get_post_link($next_post['pid'], $tid)."#pid{$next_post['pid']}"; + } + else + { + $redirect = get_thread_link($tid); + } + + if($mybb->input['ajax'] == 1) + { + header("Content-type: application/json; charset={$lang->settings['charset']}"); + if($mybb->settings['soft_delete'] == 1 && is_moderator($fid)) + { + echo json_encode(array("data" => '1')); + } + else + { + echo json_encode(array("data" => '2')); + } + } + else + { + redirect($redirect, $lang->redirect_postdeleted); + } + } + else + { + error_no_permission(); + } + } + } + else + { + error($lang->redirect_nodelete); + } +} + +if($mybb->input['action'] == "restorepost" && $mybb->request_method == "post") +{ + // Verify incoming POST request + verify_post_check($mybb->get_input('my_post_key')); + + $plugins->run_hooks("editpost_restorepost"); + + if($mybb->get_input('restore', 1) == 1) + { + $query = $db->simple_select("posts", "pid", "tid='{$tid}'", array("limit" => 1, "order_by" => "dateline", "order_dir" => "asc")); + $firstcheck = $db->fetch_array($query); + if($firstcheck['pid'] == $pid) + { + $firstpost = 1; + } + else + { + $firstpost = 0; + } + + $modlogdata['fid'] = $fid; + $modlogdata['tid'] = $tid; + $modlogdata['pid'] = $pid; + if($firstpost) + { + if(is_moderator($fid)) + { + require_once MYBB_ROOT."inc/class_moderation.php"; + $moderation = new Moderation; + $moderation->restore_threads(array($tid)); + log_moderator_action($modlogdata, $lang->thread_restored); + if($mybb->input['ajax'] == 1) + { + header("Content-type: application/json; charset={$lang->settings['charset']}"); + echo json_encode(array("data" => '1')); + } + else + { + redirect(get_forum_link($fid), $lang->redirect_threadrestored); + } + } + else + { + error_no_permission(); + } + } + else + { + if(is_moderator($fid)) + { + // Select the first post before this + require_once MYBB_ROOT."inc/class_moderation.php"; + $moderation = new Moderation; + $moderation->restore_posts(array($pid)); + log_moderator_action($modlogdata, $lang->post_restored); + $redirect = get_post_link($pid, $tid)."#pid{$pid}"; + + if($mybb->input['ajax'] == 1) + { + header("Content-type: application/json; charset={$lang->settings['charset']}"); + echo json_encode(array("data" => '1')); + } + else + { + redirect($redirect, $lang->redirect_postrestored); + } + } + else + { + error_no_permission(); + } + } + } + else + { + error($lang->redirect_norestore); + } +} + +if($mybb->input['action'] == "do_editpost" && $mybb->request_method == "post") +{ + // Verify incoming POST request + verify_post_check($mybb->get_input('my_post_key')); + + $plugins->run_hooks("editpost_do_editpost_start"); + + // Set up posthandler. + require_once MYBB_ROOT."inc/datahandlers/post.php"; + $posthandler = new PostDataHandler("update"); + $posthandler->action = "post"; + + // Set the post data that came from the input to the $post array. + $post = array( + "pid" => $mybb->input['pid'], + "prefix" => $mybb->get_input('threadprefix', 1), + "subject" => $mybb->get_input('subject'), + "icon" => $mybb->get_input('icon', 1), + "uid" => $post['uid'], + "username" => $post['username'], + "edit_uid" => $mybb->user['uid'], + "message" => $mybb->get_input('message'), + "editreason" => $mybb->get_input('editreason'), + ); + + $postoptions = $mybb->get_input('postoptions', 2); + if(!isset($postoptions['signature'])) + { + $postoptions['signature'] = 0; + } + if(!isset($postoptions['subscriptionmethod'])) + { + $postoptions['subscriptionmethod'] = 0; + } + if(!isset($postoptions['disablesmilies'])) + { + $postoptions['disablesmilies'] = 0; + } + + // Set up the post options from the input. + $post['options'] = array( + "signature" => $postoptions['signature'], + "subscriptionmethod" => $postoptions['subscriptionmethod'], + "disablesmilies" => $postoptions['disablesmilies'] + ); + + $posthandler->set_data($post); + + // Now let the post handler do all the hard work. + if(!$posthandler->validate_post()) + { + $post_errors = $posthandler->get_friendly_errors(); + $post_errors = inline_error($post_errors); + $mybb->input['action'] = "editpost"; + } + // No errors were found, we can call the update method. + else + { + $postinfo = $posthandler->update_post(); + $visible = $postinfo['visible']; + $first_post = $postinfo['first_post']; + + // Help keep our attachments table clean. + $db->delete_query("attachments", "filename='' OR filesize<1"); + + // Did the user choose to post a poll? Redirect them to the poll posting page. + if($mybb->get_input('postpoll', 1) && $forumpermissions['canpostpolls']) + { + $url = "polls.php?action=newpoll&tid=$tid&polloptions=".$mybb->get_input('numpolloptions', 1); + $lang->redirect_postedited = $lang->redirect_postedited_poll; + } + else if($visible == 0 && $first_post && !is_moderator($fid, "canviewunapprove", $mybb->user['uid'])) + { + // Moderated post + $lang->redirect_postedited .= $lang->redirect_thread_moderation; + $url = get_forum_link($fid); + } + else if($visible == 0 && !is_moderator($fid, "canviewunapprove", $mybb->user['uid'])) + { + $lang->redirect_postedited .= $lang->redirect_post_moderation; + $url = get_thread_link($tid); + } + // Otherwise, send them back to their post + else + { + $lang->redirect_postedited .= $lang->redirect_postedited_redirect; + $url = get_post_link($pid, $tid)."#pid{$pid}"; + } + $plugins->run_hooks("editpost_do_editpost_end"); + + redirect($url, $lang->redirect_postedited); + } +} + +if(!$mybb->input['action'] || $mybb->input['action'] == "editpost") +{ + $plugins->run_hooks("editpost_action_start"); + + if(!isset($mybb->input['previewpost'])) + { + $icon = $post['icon']; + } + + if($forum['allowpicons'] != 0) + { + $posticons = get_post_icons(); + } + + eval("\$loginbox = \"".$templates->get("changeuserbox")."\";"); + + $deletebox = ''; + // Can we delete posts? + if($post['visible'] != -1 && (is_moderator($fid, "candeleteposts") || $forumpermissions['candeleteposts'] == 1 && $mybb->user['uid'] == $post['uid'])) + { + eval("\$deletebox = \"".$templates->get("editpost_delete")."\";"); + } + + $bgcolor = "trow1"; + if($mybb->settings['enableattachments'] != 0 && $forumpermissions['canpostattachments'] != 0) + { // Get a listing of the current attachments, if there are any + $attachcount = 0; + $query = $db->simple_select("attachments", "*", "pid='{$pid}'"); + $attachments = ''; + while($attachment = $db->fetch_array($query)) + { + $attachment['size'] = get_friendly_size($attachment['filesize']); + $attachment['icon'] = get_attachment_icon(get_extension($attachment['filename'])); + $attachment['filename'] = htmlspecialchars_uni($attachment['filename']); + + if($mybb->settings['bbcodeinserter'] != 0 && $forum['allowmycode'] != 0 && $mybb->user['showcodebuttons'] != 0) + { + eval("\$postinsert = \"".$templates->get("post_attachments_attachment_postinsert")."\";"); + } + // Moderating options + $attach_mod_options = ''; + if(is_moderator($fid)) + { + if($attachment['visible'] == 1) + { + eval("\$attach_mod_options = \"".$templates->get("post_attachments_attachment_mod_unapprove")."\";"); + } + else + { + eval("\$attach_mod_options = \"".$templates->get("post_attachments_attachment_mod_approve")."\";"); + } + } + + // Remove Attachment + eval("\$attach_rem_options = \"".$templates->get("post_attachments_attachment_remove")."\";"); + + if($attachment['visible'] != 1) + { + eval("\$attachments .= \"".$templates->get("post_attachments_attachment_unapproved")."\";"); + } + else + { + eval("\$attachments .= \"".$templates->get("post_attachments_attachment")."\";"); + } + $attachcount++; + } + $query = $db->simple_select("attachments", "SUM(filesize) AS ausage", "uid='".$mybb->user['uid']."'"); + $usage = $db->fetch_array($query); + if($usage['ausage'] > ($mybb->usergroup['attachquota']*1024) && $mybb->usergroup['attachquota'] != 0) + { + $noshowattach = 1; + } + else + { + $noshowattach = 0; + } + if($mybb->usergroup['attachquota'] == 0) + { + $friendlyquota = $lang->unlimited; + } + else + { + $friendlyquota = get_friendly_size($mybb->usergroup['attachquota']*1024); + } + $friendlyusage = get_friendly_size($usage['ausage']); + $lang->attach_quota = $lang->sprintf($lang->attach_quota, $friendlyusage, $friendlyquota); + if($mybb->settings['maxattachments'] == 0 || ($mybb->settings['maxattachments'] != 0 && $attachcount < $mybb->settings['maxattachments']) && !$noshowattach) + { + eval("\$attach_add_options = \"".$templates->get("post_attachments_add")."\";"); + } + + if(($mybb->usergroup['caneditattachments'] || $forumpermissions['caneditattachments']) && $attachcount > 0) + { + eval("\$attach_update_options = \"".$templates->get("post_attachments_update")."\";"); + } + + if($attach_add_options || $attach_update_options) + { + eval("\$newattach = \"".$templates->get("post_attachments_new")."\";"); + } + eval("\$attachbox = \"".$templates->get("post_attachments")."\";"); + } + if(!$mybb->get_input('attachmentaid', 1) && !$mybb->get_input('newattachment') && !$mybb->get_input('updateattachment') && !isset($mybb->input['previewpost'])) + { + $message = $post['message']; + $subject = $post['subject']; + $reason = htmlspecialchars_uni($post['editreason']); + } + else + { + $message = $mybb->get_input('message'); + $subject = $mybb->get_input('subject'); + $reason = htmlspecialchars_uni($mybb->get_input('editreason')); + } + + if(!isset($post_errors)) + { + $post_errors = ''; + } + + $postoptions_subscriptionmethod_dont = $postoptions_subscriptionmethod_none = $postoptions_subscriptionmethod_email = $postoptions_subscriptionmethod_pm = ''; + $postoptionschecked = array('signature' => '', 'disablesmilies' => ''); + + if(isset($mybb->input['previewpost']) || $post_errors) + { + // Set up posthandler. + require_once MYBB_ROOT."inc/datahandlers/post.php"; + $posthandler = new PostDataHandler("update"); + $posthandler->action = "post"; + + // Set the post data that came from the input to the $post array. + $post = array( + "pid" => $mybb->input['pid'], + "prefix" => $mybb->get_input('threadprefix', 1), + "subject" => $mybb->get_input('subject'), + "icon" => $mybb->get_input('icon', 1), + "uid" => $post['uid'], + "edit_uid" => $mybb->user['uid'], + "message" => $mybb->get_input('message'), + ); + + $postoptions = $mybb->get_input('postoptions', 2); + if(!isset($postoptions['signature'])) + { + $postoptions['signature'] = 0; + } + if(!isset($postoptions['emailnotify'])) + { + $postoptions['emailnotify'] = 0; + } + if(!isset($postoptions['disablesmilies'])) + { + $postoptions['disablesmilies'] = 0; + } + + // Set up the post options from the input. + $post['options'] = array( + "signature" => $postoptions['signature'], + "emailnotify" => $postoptions['emailnotify'], + "disablesmilies" => $postoptions['disablesmilies'] + ); + + $posthandler->set_data($post); + + // Now let the post handler do all the hard work. + if(!$posthandler->validate_post()) + { + $post_errors = $posthandler->get_friendly_errors(); + $post_errors = inline_error($post_errors); + $mybb->input['action'] = "editpost"; + $mybb->input['previewpost'] = 0; + } + else + { + $previewmessage = $message; + $previewsubject = $subject; + $message = htmlspecialchars_uni($message); + $subject = htmlspecialchars_uni($subject); + + $postoptions = $mybb->get_input('postoptions', 2); + + if(isset($postoptions['signature']) && $postoptions['signature'] == 1) + { + $postoptionschecked['signature'] = " checked=\"checked\""; + } + + if(isset($postoptions['subscriptionmethod']) && $postoptions['subscriptionmethod'] == "none") + { + $postoptions_subscriptionmethod_none = "checked=\"checked\""; + } + else if(isset($postoptions['subscriptionmethod']) && $postoptions['subscriptionmethod'] == "email") + { + $postoptions_subscriptionmethod_email = "checked=\"checked\""; + } + else if(isset($postoptions['subscriptionmethod']) && $postoptions['subscriptionmethod'] == "pm") + { + $postoptions_subscriptionmethod_pm = "checked=\"checked\""; + } + else + { + $postoptions_subscriptionmethod_dont = "checked=\"checked\""; + } + + if(isset($postoptions['disablesmilies']) && $postoptions['disablesmilies'] == 1) + { + $postoptionschecked['disablesmilies'] = " checked=\"checked\""; + } + } + } + + if(isset($mybb->input['previewpost'])) + { + if(!$post['uid']) + { + $query = $db->simple_select('posts', 'username, dateline', "pid='{$pid}'"); + $postinfo = $db->fetch_array($query); + } + else + { + // Figure out the poster's other information. + $query = $db->query(" + SELECT u.*, f.*, p.dateline + FROM ".TABLE_PREFIX."users u + LEFT JOIN ".TABLE_PREFIX."userfields f ON (f.ufid=u.uid) + LEFT JOIN ".TABLE_PREFIX."posts p ON (p.uid=u.uid) + WHERE u.uid='{$post['uid']}' AND p.pid='{$pid}' + LIMIT 1 + "); + $postinfo = $db->fetch_array($query); + $postinfo['userusername'] = $postinfo['username']; + } + + $query = $db->simple_select("attachments", "*", "pid='{$pid}'"); + while($attachment = $db->fetch_array($query)) + { + $attachcache[0][$attachment['aid']] = $attachment; + } + + if(!isset($postoptions['disablesmilies'])) + { + $postoptions['disablesmilies'] = 0; + } + + // Set the values of the post info array. + $postinfo['message'] = $previewmessage; + $postinfo['subject'] = $previewsubject; + $postinfo['icon'] = $icon; + $postinfo['smilieoff'] = $postoptions['disablesmilies']; + + $postbit = build_postbit($postinfo, 1); + eval("\$preview = \"".$templates->get("previewpost")."\";"); + } + else if(!$post_errors) + { + $message = htmlspecialchars_uni($message); + $subject = htmlspecialchars_uni($subject); + + $preview = ''; + + if($post['includesig'] != 0) + { + $postoptionschecked['signature'] = " checked=\"checked\""; + } + + if($post['smilieoff'] == 1) + { + $postoptionschecked['disablesmilies'] = " checked=\"checked\""; + } + + $query = $db->simple_select("threadsubscriptions", "notification", "tid='{$tid}' AND uid='{$mybb->user['uid']}'"); + if($db->num_rows($query) > 0) + { + $notification = $db->fetch_field($query, 'notification'); + + if($notification == 0) + { + $postoptions_subscriptionmethod_none = "checked=\"checked\""; + } + else if($notification == 1) + { + $postoptions_subscriptionmethod_email = "checked=\"checked\""; + } + else if($notification == 2) + { + $postoptions_subscriptionmethod_pm = "checked=\"checked\""; + } + else + { + $postoptions_subscriptionmethod_dont = "checked=\"checked\""; + } + } + } + + // Generate thread prefix selector if this is the first post of the thread + if($thread['firstpost'] == $pid) + { + if(!$mybb->get_input('threadprefix', 1)) + { + $mybb->input['threadprefix'] = $thread['prefix']; + } + + $prefixselect = build_prefix_select($forum['fid'], $mybb->get_input('threadprefix', 1)); + } + else + { + $prefixselect = ""; + } + + $editreason = ''; + if($mybb->settings['alloweditreason'] == 1) + { + eval("\$editreason = \"".$templates->get("editpost_reason")."\";"); + $bgcolor = "trow2"; + $bgcolor2 = "trow1"; + } + else + { + $bgcolor = "trow1"; + $bgcolor2 = "trow2"; + } + + // Fetch subscription select box + eval("\$subscriptionmethod = \"".$templates->get("post_subscription_method")."\";"); + + $query = $db->simple_select("posts", "*", "tid='{$tid}'", array("limit" => 1, "order_by" => "dateline", "order_dir" => "asc")); + $firstcheck = $db->fetch_array($query); + + $time = TIME_NOW; + if($firstcheck['pid'] == $pid && $forumpermissions['canpostpolls'] != 0 && $thread['poll'] < 1 && (is_moderator($fid, "canmanagepolls") || $thread['dateline'] > ($time-($mybb->settings['polltimelimit']*60*60)) || $mybb->settings['polltimelimit'] == 0)) + { + $lang->max_options = $lang->sprintf($lang->max_options, $mybb->settings['maxpolloptions']); + $numpolloptions = "2"; + $postpollchecked = ''; + eval("\$pollbox = \"".$templates->get("newthread_postpoll")."\";"); + } + else + { + $pollbox = ''; + } + + // Can we disable smilies or are they disabled already? + $disablesmilies = ''; + if($forum['allowsmilies'] != 0) + { + eval("\$disablesmilies = \"".$templates->get("editpost_disablesmilies")."\";"); + } + else + { + eval("\$disablesmilies = \"".$templates->get("editpost_disablesmilies_hidden")."\";"); + } + + $moderation_notice = ''; + if(!is_moderator($forum['fid'], "canapproveunapproveattachs")) + { + if($forumpermissions['modattachments'] == 1 && $forumpermissions['canpostattachments'] != 0) + { + $moderation_text = $lang->moderation_forum_attachments; + eval('$moderation_notice = "'.$templates->get('global_moderation_notice').'";'); + } + } + + if(!is_moderator($forum['fid'], "canapproveunapproveposts")) + { + if($forumpermissions['mod_edit_posts'] == 1) + { + $moderation_text = $lang->moderation_forum_edits; + eval('$moderation_notice = "'.$templates->get('global_moderation_notice').'";'); + } + } + + $plugins->run_hooks("editpost_end"); + + $forum['name'] = strip_tags($forum['name']); + + eval("\$editpost = \"".$templates->get("editpost")."\";"); + output_page($editpost); +} diff --git a/Upload/forumdisplay.php b/Upload/forumdisplay.php new file mode 100644 index 0000000..79fa7ca --- /dev/null +++ b/Upload/forumdisplay.php @@ -0,0 +1,1480 @@ + '', 'subject' => '', 'starter' => '', 'started' => '', 'replies' => '', 'views' => '', 'lastpost' => ''); +$ordersel = array('asc' => '', 'desc' => ''); +$datecutsel = array(1 => '', 5 => '', 10 => '', 20 => '', 50 => '', 75 => '', 100 => '', 365 => '', 9999 => ''); +$rules = ''; + +// Load global language phrases +$lang->load("forumdisplay"); + +$plugins->run_hooks("forumdisplay_start"); + +$fid = $mybb->get_input('fid', 1); +if($fid < 0) +{ + switch($fid) + { + case "-1": + $location = "index.php"; + break; + case "-2": + $location = "search.php"; + break; + case "-3": + $location = "usercp.php"; + break; + case "-4": + $location = "private.php"; + break; + case "-5": + $location = "online.php"; + break; + } + if($location) + { + header("Location: ".$location); + exit; + } +} + +// Get forum info +$foruminfo = get_forum($fid); +if(!$foruminfo) +{ + error($lang->error_invalidforum); +} + +$archive_url = build_archive_link("forum", $fid); + +$currentitem = $fid; +build_forum_breadcrumb($fid); +$parentlist = $foruminfo['parentlist']; + +// To validate, turn & to & but support unicode +$foruminfo['name'] = preg_replace("#&(?!\#[0-9]+;)#si", "&", $foruminfo['name']); + +$forumpermissions = forum_permissions(); +$fpermissions = $forumpermissions[$fid]; + +if($fpermissions['canview'] != 1) +{ + error_no_permission(); +} + +if($mybb->user['uid'] == 0) +{ + // Cookie'd forum read time + $forumsread = array(); + if(isset($mybb->cookies['mybb']['forumread'])) + { + $forumsread = my_unserialize($mybb->cookies['mybb']['forumread']); + } + + if(is_array($forumsread) && empty($forumsread)) + { + if(isset($mybb->cookies['mybb']['readallforums'])) + { + $forumsread[$fid] = $mybb->cookies['mybb']['lastvisit']; + } + else + { + $forumsread = array(); + } + } + + $query = $db->simple_select("forums", "*", "active != 0", array("order_by" => "pid, disporder")); +} +else +{ + // Build a forum cache from the database + $query = $db->query(" + SELECT f.*, fr.dateline AS lastread + FROM ".TABLE_PREFIX."forums f + LEFT JOIN ".TABLE_PREFIX."forumsread fr ON (fr.fid=f.fid AND fr.uid='{$mybb->user['uid']}') + WHERE f.active != 0 + ORDER BY pid, disporder + "); +} + +while($forum = $db->fetch_array($query)) +{ + if($mybb->user['uid'] == 0 && isset($forumsread[$forum['fid']])) + { + $forum['lastread'] = $forumsread[$forum['fid']]; + } + + $fcache[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum; +} + +// Get the forum moderators if the setting is enabled. +if($mybb->settings['modlist'] != 0) +{ + $moderatorcache = $cache->read("moderators"); +} + +$bgcolor = "trow1"; +if($mybb->settings['subforumsindex'] != 0) +{ + $showdepth = 3; +} +else +{ + $showdepth = 2; +} + +$subforums = ''; +$child_forums = build_forumbits($fid, 2); +$forums = $child_forums['forum_list']; + +if($forums) +{ + $lang->sub_forums_in = $lang->sprintf($lang->sub_forums_in, $foruminfo['name']); + eval("\$subforums = \"".$templates->get("forumdisplay_subforums")."\";"); +} + +$excols = "forumdisplay"; + +// Password protected forums +check_forum_password($foruminfo['fid']); + +if($foruminfo['linkto']) +{ + header("Location: {$foruminfo['linkto']}"); + exit; +} + +// Make forum jump... +if($mybb->settings['enableforumjump'] != 0) +{ + $forumjump = build_forum_jump("", $fid, 1); +} + +if($foruminfo['type'] == "f" && $foruminfo['open'] != 0 && $fpermissions['canpostthreads'] != 0 && $mybb->user['suspendposting'] == 0) +{ + eval("\$newthread = \"".$templates->get("forumdisplay_newthread")."\";"); +} + +if($fpermissions['cansearch'] != 0 && $foruminfo['type'] == "f") +{ + eval("\$searchforum = \"".$templates->get("forumdisplay_searchforum")."\";"); +} + +// Gather forum stats +$has_announcements = $has_modtools = false; +$forum_stats = $cache->read("forumsdisplay"); + +if(is_array($forum_stats)) +{ + if(!empty($forum_stats[-1]['modtools']) || !empty($forum_stats[$fid]['modtools'])) + { + // Mod tools are specific to forums, not parents + $has_modtools = true; + } + + if(!empty($forum_stats[-1]['announcements']) || !empty($forum_stats[$fid]['announcements'])) + { + // Global or forum-specific announcements + $has_announcements = true; + } +} + +$done_moderators = array( + "users" => array(), + "groups" => array() +); + +$moderators = ''; +$parentlistexploded = explode(",", $parentlist); + +foreach($parentlistexploded as $mfid) +{ + // This forum has moderators + if(is_array($moderatorcache[$mfid])) + { + // Fetch each moderator from the cache and format it, appending it to the list + foreach($moderatorcache[$mfid] as $modtype) + { + foreach($modtype as $moderator) + { + if($moderator['isgroup']) + { + if(in_array($moderator['id'], $done_moderators['groups'])) + { + continue; + } + + $moderator['title'] = htmlspecialchars_uni($moderator['title']); + + eval("\$moderators .= \"".$templates->get("forumbit_moderators_group", 1, 0)."\";"); + $done_moderators['groups'][] = $moderator['id']; + } + else + { + if(in_array($moderator['id'], $done_moderators['users'])) + { + continue; + } + + $moderator['profilelink'] = get_profile_link($moderator['id']); + $moderator['username'] = format_name(htmlspecialchars_uni($moderator['username']), $moderator['usergroup'], $moderator['displaygroup']); + + eval("\$moderators .= \"".$templates->get("forumbit_moderators_user", 1, 0)."\";"); + $done_moderators['users'][] = $moderator['id']; + } + $comma = $lang->comma; + } + } + } + + if(!empty($forum_stats[$mfid]['announcements'])) + { + $has_announcements = true; + } +} +$comma = ''; + +// If we have a moderators list, load the template +if($moderators) +{ + eval("\$moderatedby = \"".$templates->get("forumdisplay_moderatedby")."\";"); +} +else +{ + $moderatedby = ''; +} + +// Get the users browsing this forum. +if($mybb->settings['browsingthisforum'] != 0) +{ + $timecut = TIME_NOW - $mybb->settings['wolcutoff']; + + $comma = ''; + $guestcount = 0; + $membercount = 0; + $inviscount = 0; + $onlinemembers = ''; + $doneusers = array(); + + $query = $db->query(" + SELECT s.ip, s.uid, u.username, s.time, u.invisible, u.usergroup, u.usergroup, u.displaygroup + FROM ".TABLE_PREFIX."sessions s + LEFT JOIN ".TABLE_PREFIX."users u ON (s.uid=u.uid) + WHERE s.time > '$timecut' AND location1='$fid' AND nopermission != 1 + ORDER BY u.username ASC, s.time DESC + "); + + while($user = $db->fetch_array($query)) + { + if($user['uid'] == 0) + { + ++$guestcount; + } + else + { + if(empty($doneusers[$user['uid']]) || $doneusers[$user['uid']] < $user['time']) + { + $doneusers[$user['uid']] = $user['time']; + ++$membercount; + if($user['invisible'] == 1) + { + $invisiblemark = "*"; + ++$inviscount; + } + else + { + $invisiblemark = ''; + } + + if($user['invisible'] != 1 || $mybb->usergroup['canviewwolinvis'] == 1 || $user['uid'] == $mybb->user['uid']) + { + $user['username'] = format_name($user['username'], $user['usergroup'], $user['displaygroup']); + $user['profilelink'] = build_profile_link($user['username'], $user['uid']); + eval("\$onlinemembers .= \"".$templates->get("forumdisplay_usersbrowsing_user", 1, 0)."\";"); + $comma = $lang->comma; + } + } + } + } + + $guestsonline = ''; + if($guestcount) + { + $guestsonline = $lang->sprintf($lang->users_browsing_forum_guests, $guestcount); + } + + $invisonline = ''; + if($mybb->user['invisible'] == 1) + { + // the user was counted as invisible user --> correct the inviscount + $inviscount -= 1; + } + if($inviscount && $mybb->usergroup['canviewwolinvis'] != 1) + { + $invisonline = $lang->sprintf($lang->users_browsing_forum_invis, $inviscount); + } + + + $onlinesep = ''; + if($invisonline != '' && $onlinemembers) + { + $onlinesep = $lang->comma; + } + + $onlinesep2 = ''; + if($invisonline != '' && $guestcount || $onlinemembers && $guestcount) + { + $onlinesep2 = $lang->comma; + } + + eval("\$usersbrowsing = \"".$templates->get("forumdisplay_usersbrowsing")."\";"); +} + +// Do we have any forum rules to show for this forum? +$forumrules = ''; +if($foruminfo['rulestype'] != 0 && $foruminfo['rules']) +{ + if(!$foruminfo['rulestitle']) + { + $foruminfo['rulestitle'] = $lang->sprintf($lang->forum_rules, $foruminfo['name']); + } + + $rules_parser = array( + "allow_html" => 1, + "allow_mycode" => 1, + "allow_smilies" => 1, + "allow_imgcode" => 1 + ); + + $foruminfo['rules'] = $parser->parse_message($foruminfo['rules'], $rules_parser); + if($foruminfo['rulestype'] == 1 || $foruminfo['rulestype'] == 3) + { + eval("\$rules = \"".$templates->get("forumdisplay_rules")."\";"); + } + else if($foruminfo['rulestype'] == 2) + { + eval("\$rules = \"".$templates->get("forumdisplay_rules_link")."\";"); + } +} + +$bgcolor = "trow1"; + +// Set here to fetch only approved topics (and then below for a moderator we change this). +$visibleonly = "AND visible='1'"; +$tvisibleonly = "AND t.visible='1'"; + +// Check if the active user is a moderator and get the inline moderation tools. +if(is_moderator($fid)) +{ + eval("\$inlinemodcol = \"".$templates->get("forumdisplay_inlinemoderation_col")."\";"); + $ismod = true; + $inlinecount = "0"; + $inlinemod = ''; + $inlinecookie = "inlinemod_forum".$fid; + + if(is_moderator($fid, "canviewdeleted") == true || is_moderator($fid, "canviewunapprove") == true) + { + if(is_moderator($fid, "canviewunapprove") == true && is_moderator($fid, "canviewdeleted") == false) + { + $visibleonly = "AND visible IN (0,1)"; + $tvisibleonly = "AND t.visible IN (0,1)"; + } + elseif(is_moderator($fid, "canviewdeleted") == true && is_moderator($fid, "canviewunapprove") == false) + { + $visibleonly = "AND visible IN (-1,1)"; + $tvisibleonly = "AND t.visible IN (-1,1)"; + } + else + { + $visibleonly = " AND visible IN (-1,0,1)"; + $tvisibleonly = " AND t.visible IN (-1,0,1)"; + } + } +} +else +{ + $inlinemod = $inlinemodcol = ''; + $ismod = false; +} + +if(is_moderator($fid, "caneditposts") || $fpermissions['caneditposts'] == 1) +{ + $can_edit_titles = 1; +} +else +{ + $can_edit_titles = 0; +} + +unset($rating); + +// Pick out some sorting options. +// First, the date cut for the threads. +$datecut = 9999; +if(empty($mybb->input['datecut'])) +{ + // If the user manually set a date cut, use it. + if(!empty($mybb->user['daysprune'])) + { + $datecut = $mybb->user['daysprune']; + } + else + { + // If the forum has a non-default date cut, use it. + if(!empty($foruminfo['defaultdatecut'])) + { + $datecut = $foruminfo['defaultdatecut']; + } + } +} +// If there was a manual date cut override, use it. +else +{ + $datecut = $mybb->get_input('datecut', 1); +} + +$datecutsel[(int)$datecut] = ' selected="selected"'; +if($datecut > 0 && $datecut != 9999) +{ + $checkdate = TIME_NOW - ($datecut * 86400); + $datecutsql = "AND (lastpost >= '$checkdate' OR sticky = '1')"; + $datecutsql2 = "AND (t.lastpost >= '$checkdate' OR t.sticky = '1')"; +} +else +{ + $datecutsql = ''; + $datecutsql2 = ''; +} + +// Sort by thread prefix +$tprefix = $mybb->get_input('prefix', 1); +if($tprefix > 0) +{ + $prefixsql = "AND prefix = {$tprefix}"; + $prefixsql2 = "AND t.prefix = {$tprefix}"; +} +else if($tprefix == -1) +{ + $prefixsql = "AND prefix = 0"; + $prefixsql2 = "AND t.prefix = 0"; +} +else if($tprefix == -2) +{ + $prefixsql = "AND prefix != 0"; + $prefixsql2 = "AND t.prefix != 0"; +} +else +{ + $prefixsql = $prefixsql2 = ''; +} + +// Pick the sort order. +if(!isset($mybb->input['order']) && !empty($foruminfo['defaultsortorder'])) +{ + $mybb->input['order'] = $foruminfo['defaultsortorder']; +} +else +{ + $mybb->input['order'] = $mybb->get_input('order'); +} + +$mybb->input['order'] = htmlspecialchars_uni($mybb->get_input('order')); + +switch(my_strtolower($mybb->input['order'])) +{ + case "asc": + $sortordernow = "asc"; + $ordersel['asc'] = ' selected="selected"'; + $oppsort = $lang->desc; + $oppsortnext = "desc"; + break; + default: + $sortordernow = "desc"; + $ordersel['desc'] = ' selected="selected"'; + $oppsort = $lang->asc; + $oppsortnext = "asc"; + break; +} + +// Sort by which field? +if(!isset($mybb->input['sortby']) && !empty($foruminfo['defaultsortby'])) +{ + $mybb->input['sortby'] = $foruminfo['defaultsortby']; +} +else +{ + $mybb->input['sortby'] = $mybb->get_input('sortby'); +} + +$t = 't.'; +$sortfield2 = ''; + +$sortby = htmlspecialchars_uni($mybb->input['sortby']); + +switch($mybb->input['sortby']) +{ + case "subject": + $sortfield = "subject"; + break; + case "replies": + $sortfield = "replies"; + break; + case "views": + $sortfield = "views"; + break; + case "starter": + $sortfield = "username"; + break; + case "rating": + $t = ""; + $sortfield = "averagerating"; + $sortfield2 = ", t.totalratings DESC"; + break; + case "started": + $sortfield = "dateline"; + break; + default: + $sortby = "lastpost"; + $sortfield = "lastpost"; + $mybb->input['sortby'] = "lastpost"; + break; +} + +$sortsel['rating'] = ''; // Needs to be initialized in order to speed-up things. Fixes #2031 +$sortsel[$mybb->input['sortby']] = ' selected="selected"'; + +// Pick the right string to join the sort URL +if($mybb->seo_support == true) +{ + $string = "?"; +} +else +{ + $string = "&"; +} + +// Are we viewing a specific page? +$mybb->input['page'] = $mybb->get_input('page', 1); +if($mybb->input['page'] > 1) +{ + $sorturl = get_forum_link($fid, $mybb->input['page']).$string."datecut=$datecut&prefix=$tprefix"; +} +else +{ + $sorturl = get_forum_link($fid).$string."datecut=$datecut&prefix=$tprefix"; +} + +eval("\$orderarrow['$sortby'] = \"".$templates->get("forumdisplay_orderarrow")."\";"); + +$threadcount = 0; +$useronly = $tuseronly = ""; +if(isset($fpermissions['canonlyviewownthreads']) && $fpermissions['canonlyviewownthreads'] == 1) +{ + $useronly = "AND uid={$mybb->user['uid']}"; + $tuseronly = "AND t.uid={$mybb->user['uid']}"; +} + +if($fpermissions['canviewthreads'] != 0) +{ + // How many posts are there? + if($datecut > 0 || isset($fpermissions['canonlyviewownthreads']) && $fpermissions['canonlyviewownthreads'] == 1) + { + $query = $db->simple_select("threads", "COUNT(tid) AS threads", "fid = '$fid' $useronly $visibleonly $datecutsql $prefixsql"); + $threadcount = $db->fetch_field($query, "threads"); + } + else + { + $query = $db->simple_select("forums", "threads, unapprovedthreads, deletedthreads", "fid = '{$fid}'", array('limit' => 1)); + $forum_threads = $db->fetch_array($query); + $threadcount = $forum_threads['threads']; + if($ismod == true) + { + $threadcount += $forum_threads['unapprovedthreads'] + $forum_threads['deletedthreads']; + } + + // If we have 0 threads double check there aren't any "moved" threads + if($threadcount == 0) + { + $query = $db->simple_select("threads", "COUNT(tid) AS threads", "fid = '$fid' $useronly $visibleonly", array('limit' => 1)); + $threadcount = $db->fetch_field($query, "threads"); + } + } +} + +// How many pages are there? +if(!$mybb->settings['threadsperpage'] || (int)$mybb->settings['threadsperpage'] < 1) +{ + $mybb->settings['threadsperpage'] = 20; +} + +$perpage = $mybb->settings['threadsperpage']; + +if($mybb->input['page'] > 0) +{ + $page = $mybb->input['page']; + $start = ($page-1) * $perpage; + $pages = $threadcount / $perpage; + $pages = ceil($pages); + if($page > $pages || $page <= 0) + { + $start = 0; + $page = 1; + } +} +else +{ + $start = 0; + $page = 1; +} + +$end = $start + $perpage; +$lower = $start + 1; +$upper = $end; + +if($upper > $threadcount) +{ + $upper = $threadcount; +} + +// Assemble page URL +if($mybb->input['sortby'] || $mybb->input['order'] || $mybb->input['datecut'] || $mybb->input['prefix']) // Ugly URL +{ + $page_url = str_replace("{fid}", $fid, FORUM_URL_PAGED); + + if($mybb->seo_support == true) + { + $q = "?"; + $and = ''; + } + else + { + $q = ''; + $and = "&"; + } + + if((!empty($foruminfo['defaultsortby']) && $sortby != $foruminfo['defaultsortby']) || (empty($foruminfo['defaultsortby']) && $sortby != "lastpost")) + { + $page_url .= "{$q}{$and}sortby={$sortby}"; + $q = ''; + $and = "&"; + } + + if($sortordernow != "desc") + { + $page_url .= "{$q}{$and}order={$sortordernow}"; + $q = ''; + $and = "&"; + } + + if($datecut > 0) + { + $page_url .= "{$q}{$and}datecut={$datecut}"; + $q = ''; + $and = "&"; + } + + if($tprefix != 0) + { + $page_url .= "{$q}{$and}prefix={$tprefix}"; + } +} +else +{ + $page_url = str_replace("{fid}", $fid, FORUM_URL_PAGED); +} +$multipage = multipage($threadcount, $perpage, $page, $page_url); + +if($mybb->settings['allowthreadratings'] != 0 && $foruminfo['allowtratings'] != 0 && $fpermissions['canviewthreads'] != 0) +{ + $lang->load("ratethread"); + + switch($db->type) + { + case "pgsql": + $ratingadd = "CASE WHEN t.numratings=0 THEN 0 ELSE t.totalratings/t.numratings::numeric END AS averagerating, "; + break; + default: + $ratingadd = "(t.totalratings/t.numratings) AS averagerating, "; + } + + $lpbackground = "trow2"; + eval("\$ratingcol = \"".$templates->get("forumdisplay_threadlist_rating")."\";"); + eval("\$ratingsort = \"".$templates->get("forumdisplay_threadlist_sortrating")."\";"); + $colspan = "7"; +} +else +{ + if($sortfield == "averagerating") + { + $t = "t."; + $sortfield = "lastpost"; + } + $ratingadd = ''; + $lpbackground = "trow1"; + $colspan = "6"; +} + +if($ismod) +{ + ++$colspan; +} + +// Get Announcements +$announcementlist = ''; +if($has_announcements == true) +{ + $limit = ''; + $announcements = ''; + if($mybb->settings['announcementlimit']) + { + $limit = "LIMIT 0, ".$mybb->settings['announcementlimit']; + } + + $sql = build_parent_list($fid, "fid", "OR", $parentlist); + $time = TIME_NOW; + $query = $db->query(" + SELECT a.*, u.username + FROM ".TABLE_PREFIX."announcements a + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=a.uid) + WHERE a.startdate<='$time' AND (a.enddate>='$time' OR a.enddate='0') AND ($sql OR fid='-1') + ORDER BY a.startdate DESC $limit + "); + + // See if this announcement has been read in our announcement array + $cookie = array(); + if(isset($mybb->cookies['mybb']['announcements'])) + { + $cookie = my_unserialize(stripslashes($mybb->cookies['mybb']['announcements'])); + } + + $announcementlist = ''; + $bgcolor = alt_trow(true); // Reset the trow colors + while($announcement = $db->fetch_array($query)) + { + if($announcement['startdate'] > $mybb->user['lastvisit'] && !$cookie[$announcement['aid']]) + { + $new_class = ' class="subject_new"'; + $folder = "newfolder"; + } + else + { + $new_class = ' class="subject_old"'; + $folder = "folder"; + } + + // Mmm, eat those announcement cookies if they're older than our last visit + if(isset($cookie[$announcement['aid']]) && $cookie[$announcement['aid']] < $mybb->user['lastvisit']) + { + unset($cookie[$announcement['aid']]); + } + + $announcement['announcementlink'] = get_announcement_link($announcement['aid']); + $announcement['subject'] = $parser->parse_badwords($announcement['subject']); + $announcement['subject'] = htmlspecialchars_uni($announcement['subject']); + $postdate = my_date('relative', $announcement['startdate']); + $announcement['profilelink'] = build_profile_link($announcement['username'], $announcement['uid']); + + if($mybb->settings['allowthreadratings'] != 0 && $foruminfo['allowtratings'] != 0 && $fpermissions['canviewthreads'] != 0) + { + eval("\$rating = \"".$templates->get("forumdisplay_announcement_rating")."\";"); + $lpbackground = "trow2"; + } + else + { + $rating = ''; + $lpbackground = "trow1"; + } + + if($ismod) + { + eval("\$modann = \"".$templates->get("forumdisplay_announcements_announcement_modbit")."\";"); + } + else + { + $modann = ''; + } + + $plugins->run_hooks("forumdisplay_announcement"); + eval("\$announcements .= \"".$templates->get("forumdisplay_announcements_announcement")."\";"); + $bgcolor = alt_trow(); + } + + if($announcements) + { + eval("\$announcementlist = \"".$templates->get("forumdisplay_announcements")."\";"); + $shownormalsep = true; + } + + if(empty($cookie)) + { + // Clean up cookie crumbs + my_setcookie('mybb[announcements]', 0, (TIME_NOW - (60*60*24*365))); + } + else if(!empty($cookie)) + { + my_setcookie("mybb[announcements]", addslashes(serialize($cookie)), -1); + } +} +else +{ + $announcementlist = ''; +} + +$tids = $threadcache = array(); +$icon_cache = $cache->read("posticons"); + +if($fpermissions['canviewthreads'] != 0) +{ + $plugins->run_hooks("forumdisplay_get_threads"); + + // Start Getting Threads + $query = $db->query(" + SELECT t.*, {$ratingadd}t.username AS threadusername, u.username + FROM ".TABLE_PREFIX."threads t + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid = t.uid) + WHERE t.fid='$fid' $tuseronly $tvisibleonly $datecutsql2 $prefixsql2 + ORDER BY t.sticky DESC, {$t}{$sortfield} $sortordernow $sortfield2 + LIMIT $start, $perpage + "); + + $ratings = false; + $moved_threads = array(); + while($thread = $db->fetch_array($query)) + { + $threadcache[$thread['tid']] = $thread; + + if($thread['numratings'] > 0 && $ratings == false) + { + $ratings = true; // Looks for ratings in the forum + } + + // If this is a moved thread - set the tid for participation marking and thread read marking to that of the moved thread + if(substr($thread['closed'], 0, 5) == "moved") + { + $tid = substr($thread['closed'], 6); + if(!isset($tids[$tid])) + { + $moved_threads[$tid] = $thread['tid']; + $tids[$thread['tid']] = $tid; + } + } + // Otherwise - set it to the plain thread ID + else + { + $tids[$thread['tid']] = $thread['tid']; + if(isset($moved_threads[$thread['tid']])) + { + unset($moved_threads[$thread['tid']]); + } + } + } + + if($mybb->settings['allowthreadratings'] != 0 && $foruminfo['allowtratings'] != 0 && $mybb->user['uid'] && !empty($threadcache) && $ratings == true) + { + // Check if we've rated threads on this page + // Guests get the pleasure of not being ID'd, but will be checked when they try and rate + $imp = implode(",", array_keys($threadcache)); + $query = $db->simple_select("threadratings", "tid, uid", "tid IN ({$imp}) AND uid = '{$mybb->user['uid']}'"); + + while($rating = $db->fetch_array($query)) + { + $threadcache[$rating['tid']]['rated'] = 1; + } + } +} + +// If user has moderation tools available, prepare the Select All feature +$selectall = ''; +if(is_moderator($fid) && $threadcount > $perpage) +{ + $lang->page_selected = $lang->sprintf($lang->page_selected, count($threadcache)); + $lang->select_all = $lang->sprintf($lang->select_all, (int)$threadcount); + $lang->all_selected = $lang->sprintf($lang->all_selected, (int)$threadcount); + eval("\$selectall = \"".$templates->get("forumdisplay_inlinemoderation_selectall")."\";"); +} + +if(!empty($tids)) +{ + $tids = implode(",", $tids); +} + +// Check participation by the current user in any of these threads - for 'dot' folder icons +if($mybb->settings['dotfolders'] != 0 && $mybb->user['uid'] && !empty($threadcache)) +{ + $query = $db->simple_select("posts", "tid,uid", "uid='{$mybb->user['uid']}' AND tid IN ({$tids}) {$visibleonly}"); + while($post = $db->fetch_array($query)) + { + if(!empty($moved_threads[$post['tid']])) + { + $post['tid'] = $moved_threads[$post['tid']]; + } + if($threadcache[$post['tid']]) + { + $threadcache[$post['tid']]['doticon'] = 1; + } + } +} + +// Read threads +if($mybb->user['uid'] && $mybb->settings['threadreadcut'] > 0 && !empty($threadcache)) +{ + $query = $db->simple_select("threadsread", "*", "uid='{$mybb->user['uid']}' AND tid IN ({$tids})"); + while($readthread = $db->fetch_array($query)) + { + if(!empty($moved_threads[$readthread['tid']])) + { + $readthread['tid'] = $moved_threads[$readthread['tid']]; + } + if($threadcache[$readthread['tid']]) + { + $threadcache[$readthread['tid']]['lastread'] = $readthread['dateline']; + } + } +} + +if($mybb->settings['threadreadcut'] > 0 && $mybb->user['uid']) +{ + $query = $db->simple_select("forumsread", "dateline", "fid='{$fid}' AND uid='{$mybb->user['uid']}'"); + $forum_read = $db->fetch_field($query, "dateline"); + + $read_cutoff = TIME_NOW-$mybb->settings['threadreadcut']*60*60*24; + if($forum_read == 0 || $forum_read < $read_cutoff) + { + $forum_read = $read_cutoff; + } +} +else +{ + $forum_read = my_get_array_cookie("forumread", $fid); + + if(isset($mybb->cookies['mybb']['readallforums']) && !$forum_read) + { + $forum_read = $mybb->cookies['mybb']['lastvisit']; + } +} + +$unreadpost = 0; +$threads = ''; +if(!empty($threadcache) && is_array($threadcache)) +{ + if(!$mybb->settings['maxmultipagelinks']) + { + $mybb->settings['maxmultipagelinks'] = 5; + } + + if(!$mybb->settings['postsperpage'] || (int)$mybb->settings['postsperpage'] < 1) + { + $mybb->settings['postsperpage'] = 20; + } + + foreach($threadcache as $thread) + { + $plugins->run_hooks("forumdisplay_thread"); + + $moved = explode("|", $thread['closed']); + + if($thread['visible'] == 0) + { + $bgcolor = "trow_shaded"; + } + elseif($thread['visible'] == -1) + { + $bgcolor = "trow_shaded trow_deleted"; + } + else + { + $bgcolor = alt_trow(); + } + + if($thread['sticky'] == 1) + { + $thread_type_class = " forumdisplay_sticky"; + } + else + { + $thread_type_class = " forumdisplay_regular"; + } + + $folder = ''; + $prefix = ''; + + $thread['author'] = $thread['uid']; + if(!$thread['username']) + { + $thread['username'] = $thread['threadusername']; + $thread['profilelink'] = $thread['threadusername']; + } + else + { + $thread['profilelink'] = build_profile_link($thread['username'], $thread['uid']); + } + + // If this thread has a prefix, insert a space between prefix and subject + $thread['threadprefix'] = $threadprefix = ''; + if($thread['prefix'] != 0) + { + $threadprefix = build_prefixes($thread['prefix']); + if(!empty($threadprefix)) + { + $thread['threadprefix'] = $threadprefix['displaystyle'].' '; + } + } + + $thread['subject'] = $parser->parse_badwords($thread['subject']); + $thread['subject'] = htmlspecialchars_uni($thread['subject']); + + if($thread['icon'] > 0 && $icon_cache[$thread['icon']]) + { + $icon = $icon_cache[$thread['icon']]; + $icon['path'] = str_replace("{theme}", $theme['imgdir'], $icon['path']); + $icon['path'] = htmlspecialchars_uni($icon['path']); + $icon['name'] = htmlspecialchars_uni($icon['name']); + eval("\$icon = \"".$templates->get("forumdisplay_thread_icon")."\";"); + } + else + { + $icon = " "; + } + + $prefix = ''; + if($thread['poll']) + { + $prefix = $lang->poll_prefix; + } + + if($thread['sticky'] == "1" && !isset($donestickysep)) + { + eval("\$threads .= \"".$templates->get("forumdisplay_sticky_sep")."\";"); + $shownormalsep = true; + $donestickysep = true; + } + else if($thread['sticky'] == 0 && !empty($shownormalsep)) + { + eval("\$threads .= \"".$templates->get("forumdisplay_threads_sep")."\";"); + $shownormalsep = false; + } + + $rating = ''; + if($mybb->settings['allowthreadratings'] != 0 && $foruminfo['allowtratings'] != 0) + { + if($moved[0] == "moved") + { + eval("\$rating = \"".$templates->get("forumdisplay_thread_rating_moved")."\";"); + } + else + { + $thread['averagerating'] = (float)round($thread['averagerating'], 2); + $thread['width'] = (int)round($thread['averagerating'])*20; + $thread['numratings'] = (int)$thread['numratings']; + + $not_rated = ''; + if(!isset($thread['rated']) || empty($thread['rated'])) + { + $not_rated = ' star_rating_notrated'; + } + + $ratingvotesav = $lang->sprintf($lang->rating_votes_average, $thread['numratings'], $thread['averagerating']); + eval("\$rating = \"".$templates->get("forumdisplay_thread_rating")."\";"); + } + } + + $thread['pages'] = 0; + $thread['multipage'] = ''; + $threadpages = ''; + $morelink = ''; + $thread['posts'] = $thread['replies'] + 1; + + if($thread['unapprovedposts'] > 0 && $ismod) + { + $thread['posts'] += $thread['unapprovedposts'] + $thread['deletedposts']; + } + + if($thread['posts'] > $mybb->settings['postsperpage']) + { + $thread['pages'] = $thread['posts'] / $mybb->settings['postsperpage']; + $thread['pages'] = ceil($thread['pages']); + + if($thread['pages'] > $mybb->settings['maxmultipagelinks']) + { + $pagesstop = $mybb->settings['maxmultipagelinks'] - 1; + $page_link = get_thread_link($thread['tid'], $thread['pages']); + eval("\$morelink = \"".$templates->get("forumdisplay_thread_multipage_more")."\";"); + } + else + { + $pagesstop = $thread['pages']; + } + + for($i = 1; $i <= $pagesstop; ++$i) + { + $page_link = get_thread_link($thread['tid'], $i); + eval("\$threadpages .= \"".$templates->get("forumdisplay_thread_multipage_page")."\";"); + } + + eval("\$thread['multipage'] = \"".$templates->get("forumdisplay_thread_multipage")."\";"); + } + else + { + $threadpages = ''; + $morelink = ''; + $thread['multipage'] = ''; + } + + if($ismod) + { + if(isset($mybb->cookies[$inlinecookie]) && my_strpos($mybb->cookies[$inlinecookie], "|{$thread['tid']}|")) + { + $inlinecheck = "checked=\"checked\""; + ++$inlinecount; + } + else + { + $inlinecheck = ''; + } + + $multitid = $thread['tid']; + eval("\$modbit = \"".$templates->get("forumdisplay_thread_modbit")."\";"); + } + else + { + $modbit = ''; + } + + if($moved[0] == "moved") + { + $prefix = $lang->moved_prefix; + $thread['tid'] = $moved[1]; + $thread['replies'] = "-"; + $thread['views'] = "-"; + } + + $thread['threadlink'] = get_thread_link($thread['tid']); + $thread['lastpostlink'] = get_thread_link($thread['tid'], 0, "lastpost"); + + // Determine the folder + $folder = ''; + $folder_label = ''; + + if(isset($thread['doticon'])) + { + $folder = "dot_"; + $folder_label .= $lang->icon_dot; + } + + $gotounread = ''; + $isnew = 0; + $donenew = 0; + + if($mybb->settings['threadreadcut'] > 0 && $mybb->user['uid'] && $thread['lastpost'] > $forum_read) + { + if(!empty($thread['lastread'])) + { + $last_read = $thread['lastread']; + } + else + { + $last_read = $read_cutoff; + } + } + else + { + $last_read = my_get_array_cookie("threadread", $thread['tid']); + } + + if($forum_read > $last_read) + { + $last_read = $forum_read; + } + + if($thread['lastpost'] > $last_read && $moved[0] != "moved") + { + $folder .= "new"; + $folder_label .= $lang->icon_new; + $new_class = "subject_new"; + $thread['newpostlink'] = get_thread_link($thread['tid'], 0, "newpost"); + eval("\$gotounread = \"".$templates->get("forumdisplay_thread_gotounread")."\";"); + $unreadpost = 1; + } + else + { + $folder_label .= $lang->icon_no_new; + $new_class = "subject_old"; + } + + if($thread['replies'] >= $mybb->settings['hottopic'] || $thread['views'] >= $mybb->settings['hottopicviews']) + { + $folder .= "hot"; + $folder_label .= $lang->icon_hot; + } + + if($thread['closed'] == 1) + { + $folder .= "lock"; + $folder_label .= $lang->icon_lock; + } + + if($moved[0] == "moved") + { + $folder = "move"; + $gotounread = ''; + } + + $folder .= "folder"; + + $inline_edit_tid = $thread['tid']; + + // If this user is the author of the thread and it is not closed or they are a moderator, they can edit + $inline_edit_class = ''; + if(($thread['uid'] == $mybb->user['uid'] && $thread['closed'] != 1 && $mybb->user['uid'] != 0 && $can_edit_titles == 1) || $ismod == true) + { + $inline_edit_class = "subject_editable"; + } + + $lastposter = $thread['lastposter']; + $lastposteruid = $thread['lastposteruid']; + $lastpostdate = my_date('relative', $thread['lastpost']); + + // Don't link to guest's profiles (they have no profile). + if($lastposteruid == 0) + { + $lastposterlink = $lastposter; + } + else + { + $lastposterlink = build_profile_link($lastposter, $lastposteruid); + } + + $thread['replies'] = my_number_format($thread['replies']); + $thread['views'] = my_number_format($thread['views']); + + // Threads and posts requiring moderation + if($thread['unapprovedposts'] > 0 && is_moderator($fid, "canviewunapprove")) + { + if($thread['unapprovedposts'] > 1) + { + $unapproved_posts_count = $lang->sprintf($lang->thread_unapproved_posts_count, $thread['unapprovedposts']); + } + else + { + $unapproved_posts_count = $lang->sprintf($lang->thread_unapproved_post_count, 1); + } + + $thread['unapprovedposts'] = my_number_format($thread['unapprovedposts']); + eval("\$unapproved_posts = \"".$templates->get("forumdisplay_thread_unapproved_posts")."\";"); + } + else + { + $unapproved_posts = ''; + } + + // If this thread has 1 or more attachments show the papperclip + if($mybb->settings['enableattachments'] == 1 && $thread['attachmentcount'] > 0) + { + if($thread['attachmentcount'] > 1) + { + $attachment_count = $lang->sprintf($lang->attachment_count_multiple, $thread['attachmentcount']); + } + else + { + $attachment_count = $lang->attachment_count; + } + + eval("\$attachment_count = \"".$templates->get("forumdisplay_thread_attachment_count")."\";"); + } + else + { + $attachment_count = ''; + } + + $plugins->run_hooks("forumdisplay_thread_end"); + + eval("\$threads .= \"".$templates->get("forumdisplay_thread")."\";"); + } + + $customthreadtools = $standardthreadtools = ''; + if($ismod) + { + if(is_moderator($fid, "canusecustomtools") && $has_modtools == true) + { + $gids = explode(',', $mybb->user['additionalgroups']); + $gids[] = $mybb->user['usergroup']; + $gids = array_filter(array_unique($gids)); + + $gidswhere = ''; + switch($db->type) + { + case "pgsql": + case "sqlite": + foreach($gids as $gid) + { + $gid = (int)$gid; + $gidswhere .= " OR ','||groups||',' LIKE '%,{$gid},%'"; + } + $query = $db->simple_select("modtools", 'tid, name', "(','||forums||',' LIKE '%,$fid,%' OR ','||forums||',' LIKE '%,-1,%' OR forums='') AND (groups=''{$gidswhere}) AND type = 't'"); + break; + default: + foreach($gids as $gid) + { + $gid = (int)$gid; + $gidswhere .= " OR CONCAT(',',groups,',') LIKE '%,{$gid},%'"; + } + $query = $db->simple_select("modtools", 'tid, name', "(CONCAT(',',forums,',') LIKE '%,$fid,%' OR CONCAT(',',forums,',') LIKE '%,-1,%' OR forums='') AND (groups=''{$gidswhere}) AND type = 't'"); + break; + } + + while($tool = $db->fetch_array($query)) + { + eval("\$customthreadtools .= \"".$templates->get("forumdisplay_inlinemoderation_custom_tool")."\";"); + } + + if($customthreadtools) + { + eval("\$customthreadtools = \"".$templates->get("forumdisplay_inlinemoderation_custom")."\";"); + } + } + + $inlinemodopenclose = $inlinemodstickunstick = $inlinemodsoftdelete = $inlinemodrestore = $inlinemoddelete = $inlinemodmanage = $inlinemodapproveunapprove = ''; + + if(is_moderator($fid, "canopenclosethreads")) + { + eval("\$inlinemodopenclose = \"".$templates->get("forumdisplay_inlinemoderation_openclose")."\";"); + } + + if(is_moderator($fid, "canstickunstickthreads")) + { + eval("\$inlinemodstickunstick = \"".$templates->get("forumdisplay_inlinemoderation_stickunstick")."\";"); + } + + if(is_moderator($fid, "cansoftdeletethreads")) + { + eval("\$inlinemodsoftdelete = \"".$templates->get("forumdisplay_inlinemoderation_softdelete")."\";"); + } + + if(is_moderator($fid, "canrestorethreads")) + { + eval("\$inlinemodrestore = \"".$templates->get("forumdisplay_inlinemoderation_restore")."\";"); + } + + if(is_moderator($fid, "candeletethreads")) + { + eval("\$inlinemoddelete = \"".$templates->get("forumdisplay_inlinemoderation_delete")."\";"); + } + + if(is_moderator($fid, "canmanagethreads")) + { + eval("\$inlinemodmanage = \"".$templates->get("forumdisplay_inlinemoderation_manage")."\";"); + } + + if(is_moderator($fid, "canapproveunapproveposts")) + { + eval("\$inlinemodapproveunapprove = \"".$templates->get("forumdisplay_inlinemoderation_approveunapprove")."\";"); + } + + if(!empty($inlinemodopenclose) || !empty($inlinemodstickunstick) || !empty($inlinemodsoftdelete) || !empty($inlinemodrestore) || !empty($inlinemoddelete) || !empty($inlinemodmanage) || !empty($inlinemodapproveunapprove)) + { + eval("\$standardthreadtools = \"".$templates->get("forumdisplay_inlinemoderation_standard")."\";"); + } + + // Only show inline mod menu if there's options to show + if(!empty($standardthreadtools) || !empty($customthreadtools)) + { + eval("\$inlinemod = \"".$templates->get("forumdisplay_inlinemoderation")."\";"); + } + } +} + +// If there are no unread threads in this forum and no unread child forums - mark it as read +require_once MYBB_ROOT."inc/functions_indicators.php"; + +$unread_threads = fetch_unread_count($fid); +if($unread_threads !== false && $unread_threads == 0 && empty($unread_forums)) +{ + mark_forum_read($fid); +} + +// Subscription status +$add_remove_subscription = 'add'; +$add_remove_subscription_text = $lang->subscribe_forum; + +if($mybb->user['uid']) +{ + $query = $db->simple_select("forumsubscriptions", "fid", "fid='".$fid."' AND uid='{$mybb->user['uid']}'", array('limit' => 1)); + + if($db->fetch_field($query, 'fid')) + { + $add_remove_subscription = 'remove'; + $add_remove_subscription_text = $lang->unsubscribe_forum; + } +} + +$inline_edit_js = $clearstoredpass = ''; + +// Is this a real forum with threads? +if($foruminfo['type'] != "c") +{ + if(!$threadcount) + { + eval("\$threads = \"".$templates->get("forumdisplay_nothreads")."\";"); + } + + $clearstoredpass = ''; + if($foruminfo['password'] != '') + { + eval("\$clearstoredpass = \"".$templates->get("forumdisplay_threadlist_clearpass")."\";"); + } + + $post_code_string = ''; + if($mybb->user['uid']) + { + $post_code_string = "&my_post_key=".$mybb->post_code; + } + + $prefixselect = build_forum_prefix_select($fid, $tprefix); + + $lang->rss_discovery_forum = $lang->sprintf($lang->rss_discovery_forum, htmlspecialchars_uni(strip_tags($foruminfo['name']))); + eval("\$rssdiscovery = \"".$templates->get("forumdisplay_rssdiscovery")."\";"); + eval("\$threadslist = \"".$templates->get("forumdisplay_threadlist")."\";"); +} +else +{ + $rssdiscovery = ''; + $threadslist = ''; + + if(empty($forums)) + { + error($lang->error_containsnoforums); + } +} + +$plugins->run_hooks("forumdisplay_end"); + +$foruminfo['name'] = strip_tags($foruminfo['name']); + +eval("\$forums = \"".$templates->get("forumdisplay")."\";"); +output_page($forums); diff --git a/Upload/global.php b/Upload/global.php new file mode 100644 index 0000000..79f65dc --- /dev/null +++ b/Upload/global.php @@ -0,0 +1,1019 @@ +read('usergroups'); + +// If the groups cache doesn't exist, update it and re-read it +if(!is_array($groupscache)) +{ + $cache->update_usergroups(); + $groupscache = $cache->read('usergroups'); +} + +if(!defined('THIS_SCRIPT')) +{ + define('THIS_SCRIPT', ''); +} + +$current_page = my_strtolower(basename(THIS_SCRIPT)); + +// Send page headers - don't send no-cache headers for attachment.php +if($current_page != 'attachment.php') +{ + send_page_headers(); +} + +// Do not use session system for defined pages +if((isset($mybb->input['action']) && isset($nosession[$mybb->input['action']])) || (isset($mybb->input['thumbnail']) && $current_page == 'attachment.php')) +{ + define('NO_ONLINE', 1); +} + +// Create session for this user +require_once MYBB_ROOT.'inc/class_session.php'; +$session = new session; +$session->init(); +$mybb->session = &$session; + +$mybb->user['ismoderator'] = is_moderator('', '', $mybb->user['uid']); + +// Set our POST validation code here +$mybb->post_code = generate_post_check(); + +// Set and load the language +if(isset($mybb->input['language']) && $lang->language_exists($mybb->get_input('language')) && verify_post_check($mybb->get_input('my_post_key'), true)) +{ + $mybb->settings['bblanguage'] = $mybb->get_input('language'); + // If user is logged in, update their language selection with the new one + if($mybb->user['uid']) + { + if(isset($mybb->cookies['mybblang'])) + { + my_unsetcookie('mybblang'); + } + + $db->update_query('users', array('language' => $db->escape_string($mybb->settings['bblanguage'])), "uid = '{$mybb->user['uid']}'"); + } + // Guest = cookie + else + { + my_setcookie('mybblang', $mybb->settings['bblanguage']); + } + $mybb->user['language'] = $mybb->settings['bblanguage']; +} +// Cookied language! +else if(!$mybb->user['uid'] && !empty($mybb->cookies['mybblang']) && $lang->language_exists($mybb->cookies['mybblang'])) +{ + $mybb->settings['bblanguage'] = $mybb->cookies['mybblang']; +} +else if(!isset($mybb->settings['bblanguage'])) +{ + $mybb->settings['bblanguage'] = 'english'; +} + +// Load language +$lang->set_language($mybb->settings['bblanguage']); +$lang->load('global'); +$lang->load('messages'); + +// Run global_start plugin hook now that the basics are set up +$plugins->run_hooks('global_start'); + +if(function_exists('mb_internal_encoding') && !empty($lang->settings['charset'])) +{ + @mb_internal_encoding($lang->settings['charset']); +} + +// Select the board theme to use. +$loadstyle = ''; +$load_from_forum = $load_from_user = 0; +$style = array(); + +// The user used our new quick theme changer +if(isset($mybb->input['theme']) && verify_post_check($mybb->get_input('my_post_key'), true)) +{ + $mybb->user['style'] = $mybb->get_input('theme'); + // If user is logged in, update their theme selection with the new one + if($mybb->user['uid']) + { + if(isset($mybb->cookies['mybbtheme'])) + { + my_unsetcookie('mybbtheme'); + } + + $db->update_query('users', array('style' => (int)$mybb->user['style']), "uid = '{$mybb->user['uid']}'"); + } + // Guest = cookie + else + { + my_setcookie('mybbtheme', $mybb->get_input('theme')); + } +} +// Cookied theme! +else if(!$mybb->user['uid'] && !empty($mybb->cookies['mybbtheme'])) +{ + $mybb->user['style'] = (int)$mybb->cookies['mybbtheme']; +} + +// This user has a custom theme set in their profile +if(isset($mybb->user['style']) && (int)$mybb->user['style'] != 0) +{ + $mybb->user['style'] = (int)$mybb->user['style']; + + $loadstyle = "tid = '{$mybb->user['style']}'"; + $load_from_user = 1; +} + +$valid = array( + 'showthread.php', + 'forumdisplay.php', + 'newthread.php', + 'newreply.php', + 'ratethread.php', + 'editpost.php', + 'polls.php', + 'sendthread.php', + 'printthread.php', + 'moderation.php' +); + +if(in_array($current_page, $valid)) +{ + cache_forums(); + + // If we're accessing a post, fetch the forum theme for it and if we're overriding it + if(isset($mybb->input['pid']) && THIS_SCRIPT != "polls.php") + { + $query = $db->simple_select("posts", "fid", "pid = '{$mybb->input['pid']}'", array("limit" => 1)); + $fid = $db->fetch_field($query, 'fid'); + + if($fid) + { + $style = $forum_cache[$fid]; + $load_from_forum = 1; + } + } + // We have a thread id and a forum id, we can easily fetch the theme for this forum + else if(isset($mybb->input['tid'])) + { + $query = $db->simple_select('threads', 'fid', "tid = '{$mybb->input['tid']}'", array('limit' => 1)); + $fid = $db->fetch_field($query, 'fid'); + + if($fid) + { + $style = $forum_cache[$fid]; + $load_from_forum = 1; + } + } + // If we're accessing poll results, fetch the forum theme for it and if we're overriding it + else if(isset($mybb->input['pid']) && THIS_SCRIPT == "polls.php") + { + $query = $db->simple_select('threads', 'fid', "poll = '{$mybb->input['pid']}'", array('limit' => 1)); + $fid = $db->fetch_field($query, 'fid'); + + if($fid) + { + $style = $forum_cache[$fid]; + $load_from_forum = 1; + } + } + // We have a forum id - simply load the theme from it + else if(isset($mybb->input['fid']) && isset($forum_cache[$mybb->input['fid']])) + { + $style = $forum_cache[$mybb->input['fid']]; + $load_from_forum = 1; + } +} +unset($valid); + +// From all of the above, a theme was found +if(isset($style['style']) && $style['style'] > 0) +{ + $style['style'] = (int)$style['style']; + + // This theme is forced upon the user, overriding their selection + if($style['overridestyle'] == 1 || !isset($mybb->user['style'])) + { + $loadstyle = "tid = '{$style['style']}'"; + } +} + +// After all of that no theme? Load the board default +if(empty($loadstyle)) +{ + $loadstyle = "def='1'"; +} + +// Fetch the theme to load from the cache +if($loadstyle == "def='1'") +{ + if(!$cache->read('default_theme')) + { + $cache->update_default_theme(); + } + $theme = $cache->read('default_theme'); +} +else +{ + $query = $db->simple_select('themes', 'name, tid, properties, stylesheets', $loadstyle, array('limit' => 1)); + $theme = $db->fetch_array($query); +} + +// No theme was found - we attempt to load the master or any other theme +if(!isset($theme['tid']) || isset($theme['tid']) && !$theme['tid']) +{ + // Missing theme was from a forum, run a query to set any forums using the theme to the default + if($load_from_forum == 1) + { + $db->update_query('forums', array('style' => 0), "style = '{$style['style']}'"); + } + // Missing theme was from a user, run a query to set any users using the theme to the default + else if($load_from_user == 1) + { + $db->update_query('users', array('style' => 0), "style = '{$mybb->user['style']}'"); + } + + // Attempt to load the master or any other theme if the master is not available + $query = $db->simple_select('themes', 'name, tid, properties, stylesheets', '', array('order_by' => 'tid', 'limit' => 1)); + $theme = $db->fetch_array($query); +} +$theme = @array_merge($theme, my_unserialize($theme['properties'])); + +// Fetch all necessary stylesheets +$stylesheets = ''; +$theme['stylesheets'] = my_unserialize($theme['stylesheets']); +$stylesheet_scripts = array("global", basename($_SERVER['PHP_SELF'])); +if(!empty($theme['color'])) +{ + $stylesheet_scripts[] = $theme['color']; +} +$stylesheet_actions = array("global"); +if(!empty($mybb->input['action'])) +{ + $stylesheet_actions[] = $mybb->get_input('action'); +} +foreach($stylesheet_scripts as $stylesheet_script) +{ + // Load stylesheets for global actions and the current action + foreach($stylesheet_actions as $stylesheet_action) + { + if(!$stylesheet_action) + { + continue; + } + + if(!empty($theme['stylesheets'][$stylesheet_script][$stylesheet_action])) + { + // Actually add the stylesheets to the list + foreach($theme['stylesheets'][$stylesheet_script][$stylesheet_action] as $page_stylesheet) + { + if(!empty($already_loaded[$page_stylesheet])) + { + continue; + } + + if(strpos($page_stylesheet, 'css.php') !== false) + { + $stylesheet_url = $mybb->settings['bburl'] . '/' . $page_stylesheet; + } + else + { + $stylesheet_url = $mybb->get_asset_url($page_stylesheet); + } + + if($mybb->settings['minifycss']) + { + $stylesheet_url = str_replace('.css', '.min.css', $stylesheet_url); + } + + if(strpos($page_stylesheet, 'css.php') !== false) + { + // We need some modification to get it working with the displayorder + $query_string = parse_url($stylesheet_url, PHP_URL_QUERY); + $id = (int) my_substr($query_string, 11); + $query = $db->simple_select("themestylesheets", "name", "sid={$id}"); + $real_name = $db->fetch_field($query, "name"); + $theme_stylesheets[$real_name] = "\n"; + } + else + { + $theme_stylesheets[basename($page_stylesheet)] = "\n"; + } + + $already_loaded[$page_stylesheet] = 1; + } + } + } +} +unset($actions); + +if(!empty($theme_stylesheets)) +{ + foreach($theme['disporder'] as $style_name => $order) + { + if(!empty($theme_stylesheets[$style_name])) + { + $stylesheets .= $theme_stylesheets[$style_name]; + } + } +} + +// Are we linking to a remote theme server? +if(my_substr($theme['imgdir'], 0, 7) == 'http://' || my_substr($theme['imgdir'], 0, 8) == 'https://') +{ + // If a language directory for the current language exists within the theme - we use it + if(!empty($mybb->user['language'])) + { + $theme['imglangdir'] = $theme['imgdir'].'/'.$mybb->user['language']; + } + else + { + // Check if a custom language directory exists for this theme + if(!empty($mybb->settings['bblanguage'])) + { + $theme['imglangdir'] = $theme['imgdir'].'/'.$mybb->settings['bblanguage']; + } + // Otherwise, the image language directory is the same as the language directory for the theme + else + { + $theme['imglangdir'] = $theme['imgdir']; + } + } +} +else +{ + $img_directory = $theme['imgdir']; + + if($mybb->settings['usecdn'] && !empty($mybb->settings['cdnpath'])) + { + $img_directory = rtrim($mybb->settings['cdnpath'], '/') . '/' . ltrim($theme['imgdir'], '/'); + } + + if(!@is_dir($img_directory)) + { + $theme['imgdir'] = 'images'; + } + + // If a language directory for the current language exists within the theme - we use it + if(!empty($mybb->user['language']) && is_dir($img_directory.'/'.$mybb->user['language'])) + { + $theme['imglangdir'] = $theme['imgdir'].'/'.$mybb->user['language']; + } + else + { + // Check if a custom language directory exists for this theme + if(is_dir($img_directory.'/'.$mybb->settings['bblanguage'])) + { + $theme['imglangdir'] = $theme['imgdir'].'/'.$mybb->settings['bblanguage']; + } + // Otherwise, the image language directory is the same as the language directory for the theme + else + { + $theme['imglangdir'] = $theme['imgdir']; + } + } + + $theme['imgdir'] = $mybb->get_asset_url($theme['imgdir']); + $theme['imglangdir'] = $mybb->get_asset_url($theme['imglangdir']); +} + +// Theme logo - is it a relative URL to the forum root? Append bburl +if(!preg_match("#^(\.\.?(/|$)|([a-z0-9]+)://)#i", $theme['logo']) && substr($theme['logo'], 0, 1) != '/') +{ + $theme['logo'] = $mybb->get_asset_url($theme['logo']); +} + +// Load Main Templates and Cached Templates +if(isset($templatelist)) +{ + $templatelist .= ','; +} +else +{ + $templatelist = ''; +} + +$templatelist .= "headerinclude,header,footer,gobutton,htmldoctype,header_welcomeblock_member,header_welcomeblock_guest,header_welcomeblock_member_admin,global_pm_alert,global_unreadreports,error,footer_languageselect_option,footer_contactus"; +$templatelist .= ",global_pending_joinrequests,global_awaiting_activation,nav,nav_sep,nav_bit,nav_sep_active,nav_bit_active,footer_languageselect,footer_themeselect,header_welcomeblock_member_moderator,redirect,header_menu_calendar,nav_dropdown,footer_themeselector,task_image"; +$templatelist .= ",global_boardclosed_warning,global_bannedwarning,error_inline,error_nopermission_loggedin,error_nopermission,debug_summary,header_quicksearch,header_menu_search,header_menu_portal,header_menu_memberlist,usercp_themeselector_option,smilie"; +$templates->cache($db->escape_string($templatelist)); + +// Set the current date and time now +$datenow = my_date($mybb->settings['dateformat'], TIME_NOW, '', false); +$timenow = my_date($mybb->settings['timeformat'], TIME_NOW); +$lang->welcome_current_time = $lang->sprintf($lang->welcome_current_time, $datenow . $lang->comma . $timenow); + +// Format the last visit date of this user appropriately +if(isset($mybb->user['lastvisit'])) +{ + $lastvisit = my_date('relative', $mybb->user['lastvisit'], '', 2); +} +// Otherwise, they've never visited before +else +{ + $lastvisit = $lang->lastvisit_never; +} + +$plugins->run_hooks('global_intermediate'); + +// If the board is closed and we have a usergroup allowed to view the board when closed, then show board closed warning +$bbclosedwarning = ''; +if($mybb->settings['boardclosed'] == 1 && $mybb->usergroup['canviewboardclosed'] == 1) +{ + eval('$bbclosedwarning = "'.$templates->get('global_boardclosed_warning').'";'); +} + +// Prepare the main templates for use +$admincplink = $modcplink = ''; + +// Load appropriate welcome block for the current logged in user +if($mybb->user['uid'] != 0) +{ + // User can access the admin cp and we're not hiding admin cp links, fetch it + if($mybb->usergroup['cancp'] == 1 && $mybb->config['hide_admin_links'] != 1) + { + $admin_dir = $config['admin_dir']; + eval('$admincplink = "'.$templates->get('header_welcomeblock_member_admin').'";'); + } + + if($mybb->usergroup['canmodcp'] == 1) + { + eval('$modcplink = "'.$templates->get('header_welcomeblock_member_moderator').'";'); + } + + // Format the welcome back message + $lang->welcome_back = $lang->sprintf($lang->welcome_back, build_profile_link($mybb->user['username'], $mybb->user['uid']), $lastvisit); + + // Tell the user their PM usage + $lang->welcome_pms_usage = $lang->sprintf($lang->welcome_pms_usage, my_number_format($mybb->user['pms_unread']), my_number_format($mybb->user['pms_total'])); + eval('$welcomeblock = "'.$templates->get('header_welcomeblock_member').'";'); +} +// Otherwise, we have a guest +else +{ + switch($mybb->settings['username_method']) + { + case 0: + $login_username = $lang->login_username; + break; + case 1: + $login_username = $lang->login_username1; + break; + case 2: + $login_username = $lang->login_username2; + break; + default: + $login_username = $lang->login_username; + break; + } + eval('$welcomeblock = "'.$templates->get('header_welcomeblock_guest').'";'); +} + +// Display menu links and quick search if user has permission +$menu_search = $menu_memberlist = $menu_portal = $menu_calendar = $quicksearch = ''; +if($mybb->usergroup['cansearch'] == 1) +{ + eval('$menu_search = "'.$templates->get('header_menu_search').'";'); + eval('$quicksearch = "'.$templates->get('header_quicksearch').'";'); +} + +if($mybb->settings['enablememberlist'] == 1 && $mybb->usergroup['canviewmemberlist'] == 1) +{ + eval('$menu_memberlist = "'.$templates->get('header_menu_memberlist').'";'); +} + +if($mybb->settings['enablecalendar'] == 1 && $mybb->usergroup['canviewcalendar'] == 1) +{ + eval('$menu_calendar = "'.$templates->get('header_menu_calendar').'";'); +} + +if($mybb->settings['portal'] == 1) +{ + eval('$menu_portal = "'.$templates->get('header_menu_portal').'";'); +} + +// See if there are any pending join requests for group leaders +$pending_joinrequests = ''; +$groupleaders = $cache->read('groupleaders'); +if($mybb->user['uid'] != 0 && is_array($groupleaders) && array_key_exists($mybb->user['uid'], $groupleaders)) +{ + $groupleader = $groupleaders[$mybb->user['uid']]; + + $gids = "'0'"; + foreach($groupleader as $user) + { + if($user['canmanagerequests'] != 1) + { + continue; + } + + $user['gid'] = (int)$user['gid']; + $gids .= ",'{$user['gid']}'"; + } + + $query = $db->simple_select('joinrequests', 'COUNT(uid) as total', "gid IN ({$gids}) AND invite='0'"); + $total_joinrequests = $db->fetch_field($query, 'total'); + + if($total_joinrequests > 0) + { + if($total_joinrequests == 1) + { + $lang->pending_joinrequests = $lang->pending_joinrequest; + } + else + { + $total_joinrequests = my_number_format($total_joinrequests); + $lang->pending_joinrequests = $lang->sprintf($lang->pending_joinrequests, $total_joinrequests); + } + + eval('$pending_joinrequests = "'.$templates->get('global_pending_joinrequests').'";'); + } +} + +$unreadreports = ''; +// This user is a moderator, super moderator or administrator +if($mybb->usergroup['cancp'] == 1 || ($mybb->user['ismoderator'] && $mybb->usergroup['canmodcp'] == 1 && $mybb->usergroup['canmanagereportedcontent'] == 1)) +{ + // Only worth checking if we are here because we have ACP permissions and the other condition fails + if($mybb->usergroup['cancp'] == 1 && !($mybb->user['ismoderator'] && $mybb->usergroup['canmodcp'] == 1 && $mybb->usergroup['canmanagereportedcontent'] == 1)) + { + // First we check if the user's a super admin: if yes, we don't care about permissions + $can_access_moderationqueue = true; + $is_super_admin = is_super_admin($recipient['uid']); + if(!$is_super_admin) + { + // Include admin functions + if(!file_exists(MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions.php")) + { + $can_access_moderationqueue = false; + } + + require_once MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions.php"; + + // Verify if we have permissions to access forum-moderation_queue + require_once MYBB_ROOT.$mybb->config['admin_dir']."/modules/forum/module_meta.php"; + if(function_exists("forum_admin_permissions")) + { + // Get admin permissions + $adminperms = get_admin_permissions($mybb->user['uid']); + + $permissions = forum_admin_permissions(); + if(array_key_exists('moderation_queue', $permissions['permissions']) && $adminperms['forum']['moderation_queue'] != 1) + { + $can_access_moderationqueue = false; + } + } + } + } + else + { + $can_access_moderationqueue = false; + } + + if($can_access_moderationqueue || ($mybb->user['ismoderator'] && $mybb->usergroup['canmodcp'] == 1 && $mybb->usergroup['canmanagereportedcontent'] == 1)) + { + // Read the reported content cache + $reported = $cache->read('reportedcontent'); + + // 0 or more reported items currently exist + if($reported['unread'] > 0) + { + // We want to avoid one extra query for users that can moderate any forum + if($mybb->usergroup['cancp'] || $mybb->usergroup['issupermod']) + { + $unread = (int)$reported['unread']; + } + else + { + $unread = 0; + $query = $db->simple_select('reportedcontent', 'id3', "reportstatus='0' AND (type = 'post' OR type = '')"); + + while($fid = $db->fetch_field($query, 'id3')) + { + if(is_moderator($fid, "canmanagereportedposts")) + { + ++$unread; + } + } + } + + if($unread > 0) + { + if($unread == 1) + { + $lang->unread_reports = $lang->unread_report; + } + else + { + $lang->unread_reports = $lang->sprintf($lang->unread_reports, my_number_format($unread)); + } + + eval('$unreadreports = "'.$templates->get('global_unreadreports').'";'); + } + } + } +} + +// Got a character set? +$charset = 'UTF-8'; +if(isset($lang->settings['charset']) && $lang->settings['charset']) +{ + $charset = $lang->settings['charset']; +} + +// Is this user apart of a banned group? +$bannedwarning = ''; +if($mybb->usergroup['isbannedgroup'] == 1) +{ + // Fetch details on their ban + $query = $db->simple_select('banned', '*', "uid = '{$mybb->user['uid']}'", array('limit' => 1)); + $ban = $db->fetch_array($query); + + if($ban['uid']) + { + // Format their ban lift date and reason appropriately + $banlift = $lang->banned_lifted_never; + $reason = htmlspecialchars_uni($ban['reason']); + + if($ban['lifted'] > 0) + { + $banlift = my_date($mybb->settings['dateformat'], $ban['lifted']) . $lang->comma . my_date($mybb->settings['timeformat'], $ban['lifted']); + } + } + + if(empty($reason)) + { + $reason = $lang->unknown; + } + + if(empty($banlift)) + { + $banlift = $lang->unknown; + } + + // Display a nice warning to the user + eval('$bannedwarning = "'.$templates->get('global_bannedwarning').'";'); +} + +$lang->ajax_loading = str_replace("'", "\\'", $lang->ajax_loading); + +// Check if this user has a new private message. +$pm_notice = ''; +if(isset($mybb->user['pmnotice']) && $mybb->user['pmnotice'] == 2 && $mybb->user['pms_unread'] > 0 && $mybb->settings['enablepms'] != 0 && $mybb->usergroup['canusepms'] != 0 && $mybb->usergroup['canview'] != 0 && ($current_page != "private.php" || $mybb->get_input('action') != "read")) +{ + if(!isset($parser)) + { + require_once MYBB_ROOT.'inc/class_parser.php'; + $parser = new postParser; + } + + $query = $db->query(" + SELECT pm.subject, pm.pmid, fu.username AS fromusername, fu.uid AS fromuid + FROM ".TABLE_PREFIX."privatemessages pm + LEFT JOIN ".TABLE_PREFIX."users fu on (fu.uid=pm.fromid) + WHERE pm.folder = '1' AND pm.uid = '{$mybb->user['uid']}' AND pm.status = '0' + ORDER BY pm.dateline DESC + LIMIT 1 + "); + + $pm = $db->fetch_array($query); + $pm['subject'] = $parser->parse_badwords($pm['subject']); + + if($pm['fromuid'] == 0) + { + $pm['fromusername'] = $lang->mybb_engine; + $user_text = $pm['fromusername']; + } + else + { + $user_text = build_profile_link($pm['fromusername'], $pm['fromuid']); + } + + if($mybb->user['pms_unread'] == 1) + { + $privatemessage_text = $lang->sprintf($lang->newpm_notice_one, $user_text, $mybb->settings['bburl'], $pm['pmid'], htmlspecialchars_uni($pm['subject'])); + } + else + { + $privatemessage_text = $lang->sprintf($lang->newpm_notice_multiple, $mybb->user['pms_unread'], $user_text, $mybb->settings['bburl'], $pm['pmid'], htmlspecialchars_uni($pm['subject'])); + } + eval('$pm_notice = "'.$templates->get('global_pm_alert').'";'); +} + +if($mybb->usergroup['cancp'] == 1) +{ + $awaitingusers = $cache->read('awaitingactivation'); + + if(!empty($awaitingusers['users'])) + { + $awaitingusers = (int)$awaitingusers['users']; + } + else + { + $awaitingusers = 0; + } + + if($awaitingusers < 1) + { + $awaitingusers = 0; + } + else + { + $awaitingusers = my_number_format($awaitingusers); + } + + if($awaitingusers > 0) + { + if($awaitingusers == 1) + { + $awaiting_message = $lang->awaiting_message_single; + } + else + { + $awaiting_message = $lang->sprintf($lang->awaiting_message_plural, $awaitingusers); + } + eval('$awaitingusers = "'.$templates->get('global_awaiting_activation').'";'); + } + else + { + $awaitingusers = ''; + } +} + +// Set up some of the default templates +eval('$headerinclude = "'.$templates->get('headerinclude').'";'); +eval('$gobutton = "'.$templates->get('gobutton').'";'); +eval('$htmldoctype = "'.$templates->get('htmldoctype', 1, 0).'";'); +eval('$header = "'.$templates->get('header').'";'); + +$copy_year = my_date('Y', TIME_NOW); + +// Are we showing version numbers in the footer? +$mybbversion = ''; +if($mybb->settings['showvernum'] == 1) +{ + $mybbversion = ' '.$mybb->version; +} + +// Check to see if we have any tasks to run +$task_image = ''; +$task_cache = $cache->read('tasks'); +if(!$task_cache['nextrun']) +{ + $task_cache['nextrun'] = TIME_NOW; +} + +if($task_cache['nextrun'] <= TIME_NOW) +{ + eval("\$task_image = \"".$templates->get("task_image")."\";"); +} + +// Are we showing the quick language selection box? +$lang_select = $lang_options = ''; +if($mybb->settings['showlanguageselect'] != 0) +{ + $languages = $lang->get_languages(); + + if(count($languages) > 1) + { + foreach($languages as $key => $language) + { + $language = htmlspecialchars_uni($language); + + // Current language matches + if($lang->language == $key) + { + $selected = " selected=\"selected\""; + } + else + { + $selected = ''; + } + + eval('$lang_options .= "'.$templates->get('footer_languageselect_option').'";'); + } + + $lang_redirect_url = get_current_location(true, 'language'); + eval('$lang_select = "'.$templates->get('footer_languageselect').'";'); + } +} + +// Are we showing the quick theme selection box? +$theme_select = $theme_options = ''; +if($mybb->settings['showthemeselect'] != 0) +{ + $theme_options = build_theme_select("theme", $mybb->user['style'], 0, '', false, true); + + if(!empty($theme_options)) + { + $theme_redirect_url = get_current_location(true, 'theme'); + eval('$theme_select = "'.$templates->get('footer_themeselect').'";'); + } +} + +// If we use the contact form, show 'Contact Us' link when appropriate +$contact_us = ''; +if(($mybb->settings['contactlink'] == "contact.php" && $mybb->settings['contact'] == 1 && ($mybb->settings['contact_guests'] != 1 && $mybb->user['uid'] == 0 || $mybb->user['uid'] > 0)) || $mybb->settings['contactlink'] != "contact.php") +{ + if(my_substr($mybb->settings['contactlink'], 0, 1) != '/' && my_substr($mybb->settings['contactlink'], 0, 7) != 'http://' && my_substr($mybb->settings['contactlink'], 0, 8) != 'https://' && my_substr($mybb->settings['contactlink'], 0, 7) != 'mailto:') + { + $mybb->settings['contactlink'] = $mybb->settings['bburl'].'/'.$mybb->settings['contactlink']; + } + + eval('$contact_us = "'.$templates->get('footer_contactus').'";'); +} + +// DST Auto detection enabled? +$auto_dst_detection = ''; +if($mybb->user['uid'] > 0 && $mybb->user['dstcorrection'] == 2) +{ + $auto_dst_detection = "\n"; +} +eval('$footer = "'.$templates->get('footer').'";'); + +// Add our main parts to the navigation +$navbits = array(); +$navbits[0]['name'] = $mybb->settings['bbname_orig']; +$navbits[0]['url'] = $mybb->settings['bburl'].'/index.php'; + +// Set the link to the archive. +$archive_url = build_archive_link(); + +// Check banned ip addresses +if(is_banned_ip($session->ipaddress, true)) +{ + if($mybb->user['uid']) + { + $db->delete_query('sessions', "ip = ".$db->escape_binary($session->packedip)." OR uid='{$mybb->user['uid']}'"); + } + else + { + $db->delete_query('sessions', "ip = ".$db->escape_binary($session->packedip)); + } + error($lang->error_banned); +} + +$closed_bypass = array( + 'member.php' => array( + 'login', + 'do_login', + 'logout', + ), + 'captcha.php', +); + +// If the board is closed, the user is not an administrator and they're not trying to login, show the board closed message +if($mybb->settings['boardclosed'] == 1 && $mybb->usergroup['canviewboardclosed'] != 1 && !in_array($current_page, $closed_bypass) && (!is_array($closed_bypass[$current_page]) || !in_array($mybb->get_input('action'), $closed_bypass[$current_page]))) +{ + // Show error + $lang->error_boardclosed .= "
    {$mybb->settings['boardclosed_reason']}
    "; + error($lang->error_boardclosed); + exit; +} + +$force_bypass = array( + 'member.php' => array( + 'login', + 'do_login', + 'logout', + 'register', + 'do_register', + 'lostpw', + 'do_lostpw', + 'activate', + 'resendactivation', + 'do_resendactivation', + 'resetpassword', + ), + 'captcha.php', +); + +// If the board forces user to login/register, and the user is a guest, show the force login message +if($mybb->settings['forcelogin'] == 1 && $mybb->user['uid'] == 0 && !in_array($current_page, $force_bypass) && (!is_array($force_bypass[$current_page]) || !in_array($mybb->get_input('action'), $force_bypass[$current_page]))) +{ + // Show error + error_no_permission(); + exit; +} + +// Load Limiting +if($mybb->usergroup['cancp'] != 1 && $mybb->settings['load'] > 0 && ($load = get_server_load()) && $load != $lang->unknown && $load > $mybb->settings['load']) +{ + // User is not an administrator and the load limit is higher than the limit, show an error + error($lang->error_loadlimit); +} + +// If there is a valid referrer in the URL, cookie it +if(!$mybb->user['uid'] && $mybb->settings['usereferrals'] == 1 && (isset($mybb->input['referrer']) || isset($mybb->input['referrername']))) +{ + if(isset($mybb->input['referrername'])) + { + $condition = "username = '".$db->escape_string($mybb->get_input('referrername'))."'"; + } + else + { + $condition = "uid = '".$mybb->get_input('referrer', 1)."'"; + } + + $query = $db->simple_select('users', 'uid', $condition, array('limit' => 1)); + $referrer = $db->fetch_array($query); + + if($referrer['uid']) + { + my_setcookie('mybb[referrer]', $referrer['uid']); + } +} + +if($mybb->usergroup['canview'] != 1) +{ + // Check pages allowable even when not allowed to view board + if(defined('ALLOWABLE_PAGE')) + { + if(is_string(ALLOWABLE_PAGE)) + { + $allowable_actions = explode(',', ALLOWABLE_PAGE); + if(!in_array($mybb->get_input('action'), $allowable_actions)) + { + error_no_permission(); + } + + unset($allowable_actions); + } + else if(ALLOWABLE_PAGE !== 1) + { + error_no_permission(); + } + } + else + { + error_no_permission(); + } +} + +// Find out if this user of ours is using a banned email address. +// If they are, redirect them to change it +if($mybb->user['uid'] && is_banned_email($mybb->user['email']) && $mybb->settings['emailkeep'] != 1) +{ + if(THIS_SCRIPT != 'usercp.php' || THIS_SCRIPT == 'usercp.php' && $mybb->get_input('action') != 'email' && $mybb->get_input('action') != 'do_email') + { + redirect('usercp.php?action=email'); + } + else if($mybb->request_method != 'post') + { + $banned_email_error = inline_error(array($lang->banned_email_warning)); + } +} + +// work out which items the user has collapsed +$colcookie = ''; +if(!empty($mybb->cookies['collapsed'])) +{ + $colcookie = $mybb->cookies['collapsed']; +} + +// set up collapsable items (to automatically show them us expanded) +$collapsed = array('boardstats' => '', 'boardstats_e' => '', 'quickreply' => '', 'quickreply_e' => ''); +$collapsedimg = $collapsed; + +if($colcookie) +{ + $col = explode("|", $colcookie); + if(!is_array($col)) + { + $col[0] = $colcookie; // only one item + } + unset($collapsed); + foreach($col as $key => $val) + { + $ex = $val."_e"; + $co = $val."_c"; + $collapsed[$co] = "display: show;"; + $collapsed[$ex] = "display: none;"; + $collapsedimg[$val] = "_collapsed"; + $collapsedthead[$val] = " thead_collapsed"; + } +} + +// Run hooks for end of global.php +$plugins->run_hooks('global_end'); + +$globaltime = $maintimer->getTime(); diff --git a/Upload/htaccess-nginx.txt b/Upload/htaccess-nginx.txt new file mode 100644 index 0000000..4253f19 --- /dev/null +++ b/Upload/htaccess-nginx.txt @@ -0,0 +1,17 @@ +rewrite ^/forum-([0-9]+).html$ /forumdisplay.php?fid=$1 last; +rewrite ^/forum-([0-9]+)-page-([0-9]+).html$ /forumdisplay.php?fid=$1&page=$2 last; +rewrite ^/thread-([0-9]+).html$ /showthread.php?tid=$1 last; +rewrite ^/thread-([0-9]+)-page-([0-9]+).html$ /showthread.php?tid=$1&page=$2 last; +rewrite ^/thread-([0-9]+)-lastpost.html$ /showthread.php?tid=$1&action=lastpost last; +rewrite ^/thread-([0-9]+)-nextnewest.html$ /showthread.php?tid=$1&action=nextnewest last; +rewrite ^/thread-([0-9]+)-nextoldest.html$ /showthread.php?tid=$1&action=nextoldest last; +rewrite ^/thread-([0-9]+)-newpost.html$ /showthread.php?tid=$1&action=newpost last; +rewrite ^/thread-([0-9]+)-post-([0-9]+).html$ /showthread.php?tid=$1&pid=$2 last; +rewrite ^/post-([0-9]+).html$ /showthread.php?pid=$1 last; +rewrite ^/announcement-([0-9]+).html$ /announcements.php?aid=$1 last; +rewrite ^/user-([0-9]+).html$ /member.php?action=profile&uid=$1 last; +rewrite ^/calendar-([0-9]+).html$ /calendar.php?calendar=$1 last; +rewrite ^/calendar-([0-9]+)-year-([0-9]+)-month-([0-9]+).html$ /calendar.php?calendar=$1&year=$2&month=$3 last; +rewrite ^/calendar-([0-9]+)-year-([0-9]+)-month-([0-9]+)-day-([0-9]+).html$ /calendar.php?action=dayview&calendar=$1&year=$2&month=$3&day=$4 last; +rewrite ^/calendar-([0-9]+)-week-(n?[0-9]+).html$ /calendar.php?action=weekview&calendar=$1&week=$2 last; +rewrite ^/event-([0-9]+).html$ /calendar.php?action=event&eid=$1 last; diff --git a/Upload/htaccess.txt b/Upload/htaccess.txt new file mode 100644 index 0000000..bb89bea --- /dev/null +++ b/Upload/htaccess.txt @@ -0,0 +1,61 @@ +Options -MultiViews +FollowSymlinks -Indexes + +# +# If mod_security is enabled, attempt to disable it. +# - Note, this will work on the majority of hosts but on +# MediaTemple, it is known to cause random Internal Server +# errors. For MediaTemple, please remove the block below +# + + # Turn off mod_security filtering. + SecFilterEngine Off + + # The below probably isn't needed, but better safe than sorry. + SecFilterScanPOST Off + + +# +# MyBB "search engine friendly" URL rewrites +# - Note, for these to work with MyBB please make sure you have +# the setting enabled in the Admin CP and you have this file +# named .htaccess +# + + RewriteEngine on + RewriteRule ^forum-([0-9]+)\.html$ forumdisplay.php?fid=$1 [L,QSA] + RewriteRule ^forum-([0-9]+)-page-([0-9]+)\.html$ forumdisplay.php?fid=$1&page=$2 [L,QSA] + + RewriteRule ^thread-([0-9]+)\.html$ showthread.php?tid=$1 [L,QSA] + RewriteRule ^thread-([0-9]+)-page-([0-9]+)\.html$ showthread.php?tid=$1&page=$2 [L,QSA] + RewriteRule ^thread-([0-9]+)-lastpost\.html$ showthread.php?tid=$1&action=lastpost [L,QSA] + RewriteRule ^thread-([0-9]+)-nextnewest\.html$ showthread.php?tid=$1&action=nextnewest [L,QSA] + RewriteRule ^thread-([0-9]+)-nextoldest\.html$ showthread.php?tid=$1&action=nextoldest [L,QSA] + RewriteRule ^thread-([0-9]+)-newpost\.html$ showthread.php?tid=$1&action=newpost [L,QSA] + RewriteRule ^thread-([0-9]+)-post-([0-9]+)\.html$ showthread.php?tid=$1&pid=$2 [L,QSA] + + RewriteRule ^post-([0-9]+)\.html$ showthread.php?pid=$1 [L,QSA] + + RewriteRule ^announcement-([0-9]+)\.html$ announcements.php?aid=$1 [L,QSA] + + RewriteRule ^user-([0-9]+)\.html$ member.php?action=profile&uid=$1 [L,QSA] + + RewriteRule ^calendar-([0-9]+)\.html$ calendar.php?calendar=$1 [L,QSA] + RewriteRule ^calendar-([0-9]+)-year-([0-9]+)-month-([0-9]+)\.html$ calendar.php?calendar=$1&year=$2&month=$3 [L,QSA] + RewriteRule ^calendar-([0-9]+)-year-([0-9]+)-month-([0-9]+)-day-([0-9]+)\.html$ calendar.php?action=dayview&calendar=$1&year=$2&month=$3&day=$4 [L,QSA] + RewriteRule ^calendar-([0-9]+)-week-(n?[0-9]+)\.html$ calendar.php?action=weekview&calendar=$1&week=$2 [L,QSA] + + RewriteRule ^event-([0-9]+)\.html$ calendar.php?action=event&eid=$1 [L,QSA] + + + SetEnv SEO_SUPPORT 1 + + + +# +# If Apache is compiled with built in mod_deflade/GZIP support +# then GZIP Javascript, CSS, HTML and XML so they're sent to +# the client faster. +# + + AddOutputFilterByType DEFLATE application/javascript text/css text/html text/xml + diff --git a/Upload/images/arrow_down.png b/Upload/images/arrow_down.png new file mode 100644 index 0000000000000000000000000000000000000000..eb251a805e66aded562b4c74c8ea24fc6a28008e GIT binary patch literal 344 zcmV-e0jK_nP)6I?`pu`}e==+8-3$c@={DZvFkAw(I>fkXn!)WCIwC z`)-QrwO?A7y!FMi`qSV4C$E3?KXU1V|NgVD{r8-D@qfaayZ?ii-hT#C15yjpgKhwW zX2WSw<;uhBf|uTT7Q5;3f9t82!8mB;{r|4Bt~~?Efz*K1;xd3iws4QAMAp`I=F_h| zGu!g#$$``mGJruSd7UV4%<^@Ty_cU!^jv-hVuQp$a>N?Iz!|zg qlr>=XIuHi2L1H)!7){EQ82|umovEW$KPDjn0000EM literal 0 HcmV?d00001 diff --git a/Upload/images/attachtypes/blank.png b/Upload/images/attachtypes/blank.png new file mode 100644 index 0000000000000000000000000000000000000000..b123222bb124d05dd133a118edf36886443ee8db GIT binary patch literal 482 zcmV<80UiE{P)ogFCY$W;|IPff zvF;lU!mupsj;AXs9-m67fr=v9?RI)Wnirn0JI!W$%bNj0DT;W{?0cR^oo@F5xj4QI zQGk|&r639d9ox-@)~gjQmrGhK7J7bfwc32{mUTAqQj6v2K&BG zudYi@t@iffx{ti`qyZ`g2#AHo&>x87INDCRT&54to9-(JvlV0jc@R{hU)gSIfj5pV zWXCZCNm!E$h%E>~lw`_-*fBt)7BYZ+1qBeB=kNqT_dxd{t|u2_^Llt-f$#jd0?1B5 zw1przVF4BJRTV*y;^;xA-LmW$-Th{od*}NT$ zMk4!OF8%#dwOp=!8AdEwN+jT+-EMv8`V$jHotcY85S${O{Ufl)aq!&fyb6NQU)eUW z`FtJ(SL-!&dp#GYQYkP^6Y}|dM1XR_oQMFA>V-lfLZH2E|4#u9gM-1qJ$*8nM2NJv zz+XI4)hz)m(>DPHip8RfGnve`ylN49wq^>ZOLWhR2Wc0WLZ7ew9{_C527H@qk;r2Ndnnhf~PyN3t!p&JQQPeL4*Odj*u>?Q1Ij$yp7N251{Q(Utj Xf0EWP$vH}`00000NkvXXu0mjfF>~YL literal 0 HcmV?d00001 diff --git a/Upload/images/attachtypes/doc.png b/Upload/images/attachtypes/doc.png new file mode 100644 index 0000000000000000000000000000000000000000..905d3cc9df86f5b5909bc77609e95dfaa2ef4eb6 GIT binary patch literal 645 zcmV;00($+4P)R5(wKl3z$uaTLeTtMnFR57L9^ zN<G-`ChyiB4+*I!`bir`Rs1@kTS7C%Jek#&dm6Pk$=#9H5#SMlatgFiBL;t zClLg_k(VTe(Y$GL#xQuJP~fDd@sC`Nzh|=+@zqsEkKnQefRtM+36XFu!uQ|vS~AJc zmX{evhOY}QM{sHEwN^KtqvFC!ppg@4y&OYZ%ro`O?iyWQ(z>i{UR(vQCdDK;TBen!@ z=X4-2CJ>;e6Hj?_(_r7VCH7pI=Z~LKPDCE{t$f~*Y!r*!H9Q;=2v9@&V^&p@(`o%L zkVk!6_QIB6PfiXFjtc~+zGW_P;K&@;!slP)tbD62$(Bmo;rE9H0whh;aCDZA_4Q3u z<-MDg3YP^#wo)&bxgZ0Yt~-*P+|esw22U_V?TP|!V{xk0>YkFk+|i4fW{-!gbI9$c z!(Q(ld;9j16y!5{F=L-Pq5h!Teb?DvNQ4SR0z@T27nvb<^kQarmi7y6b&ZYV`&wJ? f{SWBH3}$}=-kXN`FBkO!00000NkvXXu0mjf)m}0; literal 0 HcmV?d00001 diff --git a/Upload/images/attachtypes/html.png b/Upload/images/attachtypes/html.png new file mode 100644 index 0000000000000000000000000000000000000000..3f2d08d124877c939eac036bab340dae29c6999a GIT binary patch literal 566 zcmV-60?GY}P)uFAh=%3-b?vd))q^HNn7spbmEa!oZw&RqR z*4LLGi$z_%HyVC@D4k4ZU#r!?W+N1$t>fdP`$Az)>3Tuc>h(7H#(CurgDxRx|K#Lc z)3p4@=O-!Kw%g=Kvq|q<3<_vEd%hV+b_aq2{I3QA20V?R5I+p0U8|7~jY-7@<>zNQ z*xaNB3jyS)frF;AN7i`pp_r^!Ds;HJOT(k16p2JyK#m$XXukD0j?+Gl#!tAtzNUd# zjN*wzyNY2q|PX zzIcki1PtO6nas#dK2JK1t?Lv541-J$*rV><5);kz^u%-R>50cPnbnt4smxDz1HpgU z+Ro0Yh(;&bq#H&;gu@AGSyS}SaI4k3X0dpQUx!io0z}Lpi-kcKPyhe`07*qoM6N<$ Eg2}uJg#Z8m literal 0 HcmV?d00001 diff --git a/Upload/images/attachtypes/image.png b/Upload/images/attachtypes/image.png new file mode 100644 index 0000000000000000000000000000000000000000..b41267fa98cec71d6911324936aba7310e4251e6 GIT binary patch literal 555 zcmV+`0@VG9P)4z$r7}P7__hx1TAbVL=^l7`XfS$v|?)|*jlK6z*b8eyO2syY}{;&*<;Rk8H)po zoo=R^f%oAZ=AA%9I87-|S;76CojbsALH!r)oEyE`-F>!*`rh{TW9_UBya?By2B-kS z4(JXv7DS-zLYaV8FjV z5zHHKB3Nscw#FzY!Z3Tsg~2-gY={V4T!q!51=S5q&a_TWYzuWFSYuj%^`5sMp7TCQ zxqam>H#Tpg6-2tVT^m?R!MJvohG4yK0mc|*McCWlqgVBKdGvzAqtA?2))*{}Ia~JW zMhOIID~{ULetN+eqqJ!n<-F(QaKyJCn&WB2>)A)T$v#<{k!Lx1o>SxnRZ%it8M3}I z;@bHb(=>k^Oa`}zqKG(-Nz;^~$f>G=e!ryOFQ}@FvP{Ub5EUz|)W02cy!U_IS46PZ zQP&Mh)mW=IJ{ArR97&Q8$1#^TJ*H_odN!R#oiOChlZXEp9}m=Y!id>)8U@+L#v_%c tYl|e&&*z^4AOd=T{!hIHX2EIS`4!H$9_57tdoyh!V%gB=p_)U^fCV|G(%&kKdD2Tuk`inJ}XT5P-T zzVoAlvu_F!&1Hs}`9AY}zKr+?EameEAsz#F`1dF}=RP@W@!kWV0mcgj)+Q$I78Vy@ zx2z?$me@J0_sPX_xlCba=P4k7gEmp@!mFz=qr!;=3=jh?K;`qKr>5B3+hcrmlqU-d z&w%&d`vU;65B>&_24pB~0u7)J`~q&BoKP$llN_sSYtMlf0NPx5Ri;whjv~JF_Tml? zabaIeNiLVedrxO)CtKxmtqqeVs5SxH*GIg+Pshke5+MdUv_?yb5CQ;WtuWSNtVKo_ zl-0lh)#YVwPEL{@8X^jiE2-2ah&4u7W3a{`n;~mvY>e*td9Do)gL6FG*x=sW91)OG zDuJkTfNTSFBWONaS>fyECf~NV`M$f$&q{^ZTAF|qf|ODKD5WsQ$aW8O1Vq5Qo*n>v zXsQeARsax8l$01_L;`5RvVj>Firj@_4?LKjP5{7pggE|V;9&N1Haq(^mz)2vzW&lV zhX-8vh0c4Na|uAe!QUVPXw>VvQLAxODj|W)QK^(YtJTtprVvOekwT!PL`jKO3avFtDb8xO^iipl v1u`1Q0NEdv%IWp~{w4lnxJKg?$O7g!QF0C2i;HJh00000NkvXXu0mjfINKo{ literal 0 HcmV?d00001 diff --git a/Upload/images/attachtypes/php.png b/Upload/images/attachtypes/php.png new file mode 100644 index 0000000000000000000000000000000000000000..f9130c9bbab58f89862d41cc86888c850b03307b GIT binary patch literal 666 zcmV;L0%iS)P)*b?sts+9UMj`5V0sW5L52Ph zJcvSSDM4+ro92I<3E71OY5m|~c7}OhzHfHG7L5X9kHxMNt`q3F6^X!2S%w>u1Q$dR zfD0YmYNLU_t5rNGmocv>_@h+9@5N%9H<=7_4`I>_7`T1^8QhtiVb_ULt%d~>{yaRy zZ-oNp_V;mnZx6Tfc}y)YBOmS~OuE77=u2=qmqgFx(rz@ij-k*yj6~P)`OF4pK7Q3r zW)~K8OcqO+0EP_)gTWPLdU_M%@vIK#;qWT1Z0s0r!q2e=0`~}DV0=84ouA*vbUKI0 z4bNeNYkt3%00vyHl)AXMg8+d4ie7KpFcTi^fY0Y6fC0Nbk)50SgsIdP zCK8*5$n}tvHVl^k&Q*`+0Raq{&A~y3I-I-RuWDFPViw@yHxUAvBUMQ7{!K6qv?j=|QaCvxGBiN!vX^_EjCcJFitLdP}Y=%oV z8x!J9Ytb!^Gf^q$Ue>U-ea;C2oVQpWwRiOdlQMmCFKe{ZMVvV+2v0PFwh6&AX>{gN zBPwK8rJQ?N)6v3d;$l~K_tdH0-uVB(y{uvFUv$QIb^434xBvhE07*qoM6N<$g0f>R AcmMzZ literal 0 HcmV?d00001 diff --git a/Upload/images/attachtypes/ppt.png b/Upload/images/attachtypes/ppt.png new file mode 100644 index 0000000000000000000000000000000000000000..929af5f00e5d99d2e56b427466b3bcdaa0a4acce GIT binary patch literal 653 zcmV;80&@L{P)aTvy5(7_@&h|~@` z6dON^DCl4+)M7zN@B_uPbO@FVRfC3_7?eiaLIjJ8OD7jyDvsh{7nj;em!e>a3RwQoqtUaGGZkXCDnXb<}c-;+f#Xo{Gg{0s;Cmyn`FnGB2kCjMxP^ z>WGVSBd!TL^WWAjK2h`DDlf7_FuqVeOk%T~i7J{4S76O~N6`ABouE?*tCY45mkA=fYfdI)6 zJwMYyM~8-P+j8%wWpPt5WGnS%lWQWV>bhs5N{(3p8lqc0?Q}R40(Y=Dwr#I#qDhWf zXuA6P$T_?He%c!h-gUQcJ(HTmn1#kYZ9@A_zd!BmFH8grMgoi)f-Yu;q8 n2irP36I;8xr~U`bLIdp|DH@XJ8rEO#00000NkvXXu0mjf7Bwzq literal 0 HcmV?d00001 diff --git a/Upload/images/attachtypes/psd.png b/Upload/images/attachtypes/psd.png new file mode 100644 index 0000000000000000000000000000000000000000..58847207786fadd1bf6706000ed89bc3b89806b0 GIT binary patch literal 480 zcmV<60U!Q}P)C= z`|b7h{r>*>{QUCx_|@j-Fl5RgQ@R2*o8j{EHfhi&S->1kv=)50)j9AK+zf4I%EjjNTso8 zyZ`^61cu(XdjJ5_cGC>7`oeA>#ftLikE$Je7-LT(H~9@~(bVLes26V~lQ#G$=x&9gwZ6ID>;Ti@TFXo!%#@0Acz z!!RhNp@q<{g2|lqk}M>ZP}YGwzgP+@$&xw^h>ZvgIQSERt6=~kqXj>xVc7aN1mFvV WEEN>H5y%+;0000 literal 0 HcmV?d00001 diff --git a/Upload/images/attachtypes/tar.png b/Upload/images/attachtypes/tar.png new file mode 100644 index 0000000000000000000000000000000000000000..18d96432bb46063fb4e14374f1aa1785af0ec6c0 GIT binary patch literal 470 zcmV;{0V)28P)L(?KYMaU90+-@Es{J2WTs5^KHKmY9*kP^YAZlgQ=CX;B+C(c;X49}%8)3_&DQY>mNo!Lm(uh(H{JhWV zeS6>A)>farwg2<|U*1N{OtqklRRZbUD%oXA3YUp;TG}&g(V(TXaS57ob1ggX=|wK3 zyk!A^gJZ;jQVT%SW?GK6&{JdV{x6HB%vG%EjEgH16 zJ0QY#>0*UnPCXUD77bbo^%)@iD!-zq!-a}qiv}%i^%`LBG3n-q_jm<4 z3&+KnlM4s46~Pt_T6`L9t-_|qEL>It4O(1KCo{?#s$?v;wf>#|0W^+PRh(qv{Qv*} M07*qoM6N<$g1KGR7XSbN literal 0 HcmV?d00001 diff --git a/Upload/images/attachtypes/txt.png b/Upload/images/attachtypes/txt.png new file mode 100644 index 0000000000000000000000000000000000000000..467a7ed05c34e6fb87c99a74a5cfc2a1fbca5a93 GIT binary patch literal 580 zcmV-K0=xZ*P))gTWvSheJ4w$2mzlo#yw3VZfth+4B}A zvH~QCBY=6bP1A%mzkf*y-@2|cCvfpWZlPYU^Xi>Whm*W{Mg{@_a2y8`i3A{KB>`_C z7K_cR3ne1x?8AQ$qb^#I2#B`PXv~2^31vEyCp(b{cC(s*dmt3ZKFE8&suF?J0?u1j zAUvS45m2tK>pC2u0>u2%0xF0`qx?YC2)K*p5fLL*7z!VV)WS!z2^*o%(iDVTs=AK~ z&|Uy zkp`tji?&FMBFbqSmr^%ZHx{)?&D*W}rrmh)=r2(6;K8dmks=Y#9{mlT?QbSF*SdFW zr@oz;@A-W{=giCxp^Fg?htX&>LWjfQT;gW4A?2zAj-u)}c!|U~$ zq*AH!a5$9h_j}`DFt~;FHx76u$iu7Eib#@F2BB`Z%RC180_*P_@IsJ>m&+xI$Kz#~ zd)c$o>2QBKol3C2dkr8i77G%IM0hxt%TXBk+>b`1=p}$SpU+7k5a8i#HcPA3Dn9o? zC>RW01&FiRjQD&$9)^RWl}ZI)`s@k%3&8e9oK7b%N+y%EP$=MQzRTsppl1MaGMNyo z)yj)vu^5GY<7>XnX2SqO=Kyg$9ut$v#EP7WM4|%w#uvUf6bezZ*^B{(E&*OJe`GQl z)>&S?Ue5v|^aeT3y?(!+8Vm*uFvI{losKu(3EBDX1OmGi*->H?~VsX zH5v^D7*ea%&)WV3aCkhPdqEHkjYflaTfg7uf97_(sZy!L3WWk)8z+FK*Xv0Zi{(M3 zQW@*@`up8(_toKWP`OJP);sjGQGyn zn4rE;hzNqo#c`60YjxMFmp>GX z{3xGiENLDS0$PxLa>c*sv~a&#D)GY7k|tmnQvv}>Ka8;Jxr_)tmELpifZJQBSzrXV%SjeY!{)=g92?Rrl#JE6!V!4xSxfZXiylp*1Ojy7 z-XY#_HuyndUW1&QH!3Q!9nuZo?wuA4P#PG-*%FQ>`{vz zwYr2|yMw{368I9K4Uqs*Q?Nzm$QiZh`O`}~g@LZ_?&OaC{@MQlwdg_bZ#)c$iseTU QM*si-07*qoM6N<$f)}kOTmS$7 literal 0 HcmV?d00001 diff --git a/Upload/images/attachtypes/zip.png b/Upload/images/attachtypes/zip.png new file mode 100644 index 0000000000000000000000000000000000000000..796f1c5821339cb3fea0e1b1946321998133d265 GIT binary patch literal 493 zcmVC@d{D}3!2QIDFDPZ>Xe2SkA$NvPnaNyE%tpeuF z;|bO@jUV@dX&H@1?Ucc6z~>IbB_RYD#X?n8{+ah%!?s|WCL4yqx~|(hA_@@RT(ujl zpnSL9&vHUU{si;xVs{KK+1baUjdW jW08{~9^3uxcm0iT+EYvBaw94W00000NkvXXu0mjfqpaTv literal 0 HcmV?d00001 diff --git a/Upload/images/buddies.png b/Upload/images/buddies.png new file mode 100644 index 0000000000000000000000000000000000000000..5db72e27151965b9954a2ffa115029d347bbec0e GIT binary patch literal 797 zcmV+&1LFLNP)X*TbR0O zY*t=kd-^`tu3fhN>W|Mpdw##?``H6B7Y5;+y^MjK8Oozzr1TirmH9#~r=Lu-=^tTy zXu>>jcsGMsJAgcQsC^Rc^0iIwy{-zj`%W``H}TH^;l-F^(ta4KklJH+b|6mFB_hp! z0FE3WHV14t1)PUucY&pcS%PlD zkxVm3!vO+nP75Z^J6KwN`}w}XcrMw=%5q)d%=CBtt@V9HG9<@XfsQlC0RmKkf(hA8 z-|er>&rS8)F&-Xi`z+TFbTb{fNIocce&8A5AhTDvfmrSX5EvQ(SEX)HE)k$KfE7+P zXROS1<>RO3^tGh;eFF*llG&`bENp6OLh|LeWwSf)om6e9@=fFcD-bVqfEe8a;>AAj z4~ucD2(=z<&k4k$Nc+#3t%~J>Ni|;5-ocHH4Wn;;e2i)O>eW;2DeuIhBk5*=7oI$l zX*xIi%$_;d+bwV6v@J8yoq1?57?4bX>q8ZoJWzr{jz>EMti-79gk5pkvNVlhwy^QJ z@mz9x=k$U_VtubD&u#TS5iA$7JX)E;t(&E|_JjP;2wZWA15wtJDlHu!%kMUBS3S4XaU_6&hf&4B5 z=4fV+_BbFUOEv{0$|y0QSStjnI+(Ox&BD}mK0ZG2z|Exh)k09EMhsB)8uuhh+W$L% bi2ube%3`LQ;y8rK00000NkvXXu0mjfP!4&3 literal 0 HcmV?d00001 diff --git a/Upload/images/buddy_away.png b/Upload/images/buddy_away.png new file mode 100644 index 0000000000000000000000000000000000000000..9f48e5140f543d394d137c491b50f1f912cdbf14 GIT binary patch literal 391 zcmV;20eJq2P)^@R5;6H`2YVu10|SYa2arHEhEFJ zjf^~JHZw*7@gyK#4y7YO;vjiK2JoC%&)D+dLhzaI?`D4Z`(??W?{BAmcyQkD3`iU# zkJo_1s~My3oDDep>+QsU-=9_fhv6TuyZ+re>2ek%kJo^G%NS>Vc-r>yca`w%d*>9tzPPFS_b!m$yHembNE{?j$N+{pZ47)fn;Fu9cnuIA lh0^IDagh8VPs#&g000eq&C~o$dwBo=002ovPDHLkV1hzNw(|f0 literal 0 HcmV?d00001 diff --git a/Upload/images/buddy_delete.png b/Upload/images/buddy_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..7fd7a0cc46ceb1025a2227e9bdc0027db782d136 GIT binary patch literal 651 zcmV;60(AX}P)=gIp^ zPa9}m%gVHw8Pot|U#dYYWE25u@+hn95@I0SVko2RHgv46uAcsuy@9jiVF79KD68xe zV&EDV6`b=mE*YbPGh=-M(&SO5>uLj6?1tayZ#G0G9|Q`YhA$#Pnmm0kT6%(Xa1hJ~ zy5Xq20eW^Z!j?L*CHsCThy-c!D5DN_RcR620{Ar`IUj-K8V1Szlry@#a|e5V|4cIy zq{$N*b$EB7fz2FWx7YqLm-Hh+nmmy$Fiz&J|?!KE141T~1kEg`I$=h$SSS$+qYAyKH>HLE*Kt>zbqon-F9G*>0mIsdCe2w{h z{yWjWRmM(!gAS7wgKO4ffOBkV&Gh;54VpqOPFk|}KQzcnlI@KRu>ESpYPB9A*giGN lJ(V)*h%P@9Ed7K3;RpIqw9?hS<1_#O002ovPDHLkV1g7yCI8PsOZMbQ8IJ{lh!Ji6rWLcI>)0`GXu_?>4%JY0< z7{(NK@T~z+6t8q$pEXBynx^YLrdHyj;k_wJit5>{OEPt@=w+eh~faAD(gx+_y?cm?c=gS@V)&R@0*OSS!h0sUs zx@&yIan|*4_+)`^4KNIILDTf@U@*2V%iDY2=a*%neZN1lVF!OIKu{EQNs?r*Vbt() iczdveKl88rFM)50&9X;7ZWmVo0000zopr08m~niU0rr literal 0 HcmV?d00001 diff --git a/Upload/images/buttons_sprite.png b/Upload/images/buttons_sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..e5d26a9e241aa8757d8e45e1aa8bf13f0a6d8090 GIT binary patch literal 3629 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 literal 0 HcmV?d00001 diff --git a/Upload/images/close.png b/Upload/images/close.png new file mode 100644 index 0000000000000000000000000000000000000000..8ec27e670edcb80d37cf3af06006f146fe7f19e9 GIT binary patch literal 950 zcmV;n14;aeP)+8C@ zx?Egb2L}fM0RaXE20J@D^78VNlaq9GbOHhb{r&yi+}x|Ht2Q<^D=RDL=;#0d01*)p zOG`^bLqiY{5Ca1P0RaJ=oSf9u)PH|}9UUG0{r&s<`=q3#^YingqoWrW7bGMke0+R6 zJ3GFFew3etv!?CML+p z$fBa6a&mG!JUpYLqn(|dprD}R85tSx@9)dY%TG^F zVq#)lU0whG|M~g()*edE00015bW%=J^8f<~3osWF4=Y_r96cZ)^ZonwicuvU{`vT2 z{`&g$^w)GZ_Vx3gf%^IQ^yJX5u9Ag!a9~_d75w`4=G4r`#KOUzj$=zgJU2Bc3;p@` z%CoVtu8DtbT1btJ((3>K0ryEnK~yNueUoQn+CU73UE6owb{ICBunL3}LPCJ-J=!GQ z`{n=tk4hKZ_*0&5_G3vWOQ*eAqcg_SldeeLt~D9+AbboT9!g<&U>drf)hr+Hex8Gv zT;GK@eUNGnwZr=DF=W^)8A zIG#0SF5QpO+|d5BQ300hS)20x6o+hIIKsIjOA*iP4`*fj?v=Nkj-=cZT>T5%$1hi z`IUOpQ+3Jb`50)sLTNGIMXt}iZf|h=6;5@Gud$G-F>lu9Ub9qjGV>g6%#MQF8=#uC zy*hT>=ig#V5zlsjPnp;i&N`IaR3k|OcaMDIb6?5AF>p3?gM>%I19iOG-nTZeYBZap zGH`NPta)mnY8`w*esI}_qWxtsta-v$>!6k?5}w;B4t`vmo?d((6g#dbc-rYITD}v+ zwa&0e3_GCKkFR5Z#vHD+%(N zqWFYO^Oy)E;S4ArbSxvuvg{eI>&a1+%ODVlB5fa z@d=+P&vPu8YcoyL8?^lZc&CIF;1nSJ;RTPh6BuNL|NU>=0b?_%_#dZ$+5i9m07*qo IM6N<$f)TW`4gdfE literal 0 HcmV?d00001 diff --git a/Upload/images/collapse_collapsed.png b/Upload/images/collapse_collapsed.png new file mode 100644 index 0000000000000000000000000000000000000000..b13bc66d988bdae99660f0ec13696f4113d092de GIT binary patch literal 453 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0WW zg+Z8+Vb&Z8pdfpRr>`sfU3Ot%CX@M6TzWtuwj^(N7l!{JxM1({$v{(FJzX3_EKVN{ zw)Sgt5Qs~tWaqG7y7Xe#rKTfJ)w(M!*jddVFv&P*OWCq^PBjt+7K23#^y4ZoZ7*?-7zL`=JC*|)pxGtat9mx8W; zjhq|st^9had}!$23*1ILkIgumj@z8)u22Ye33S<{Gh5O3vJ%f>_TzR$rVcI$*i=M6P?mD|Nf@m^8LVkFMXl3)&5jLU=TBSy85}Sb4q9e042n(I{*Lx literal 0 HcmV?d00001 diff --git a/Upload/images/colors/black_header.png b/Upload/images/colors/black_header.png new file mode 100644 index 0000000000000000000000000000000000000000..b1c20445b825f249b478e1532948b199a6a84b02 GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^j6j^i!3HGVb)phL0>we@P7LeL$-D$|I14-?iy0WW zg+Z8+Vb&Z8pdfpRr>`sfEhcsWLBlrpx-6g&M~Q1hiF1B#Zfaf$!?!cj_5;PrJzX3_ zBrfMp2o!2?;Bb<^x8_~_vKPw1+ut5P=;-*whM&EIA#LMa*3JX-T$DIYb{>;bOHpMK z-X>(LyMD#(>uLsD-8Sk^49eMFbM0A7_dCXFzo{7!b$3p2#Iq!&PLH;lZ5_Qe>sw`^ p=hw5kujV(@uhn|BYSXhFj4C=MYE^%?djg%n;OXk;vd$@?2>_}^RJ#BG literal 0 HcmV?d00001 diff --git a/Upload/images/colors/black_tcat.png b/Upload/images/colors/black_tcat.png new file mode 100644 index 0000000000000000000000000000000000000000..a924677641afb5bb920b67aa979bf12b73f6bd03 GIT binary patch literal 182 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{M!2~3ezCWG-5-1LGcVbv~PUa<$!&%@FS89ZJ6T-G@yGywo1s5aaH literal 0 HcmV?d00001 diff --git a/Upload/images/colors/black_thead.png b/Upload/images/colors/black_thead.png new file mode 100644 index 0000000000000000000000000000000000000000..10691f3922d9f745b2e1b440c82f8a388cf90984 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!2~2XTwzxL2^0spJ29*~C-V}>;VkfoEM{Qf z76xHPhFNnYfP(BLp1!W^x0u)kcoc+Z8?^w1I7(b2N}Tg^b5rw57`~mEwjU^F>*?Yc z!Xe9gkdc?cK;Xy%@15CadCmpjj1m*>n@>}?6c4v;| g&7)2nx!Jeb&!|UizLgc<3p9wq)78&qol`;+0LYU#F8}}l literal 0 HcmV?d00001 diff --git a/Upload/images/colors/calm_header.png b/Upload/images/colors/calm_header.png new file mode 100644 index 0000000000000000000000000000000000000000..3ba023f24cb44fc7b1b1fe193d40bf9f0e74e186 GIT binary patch literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^j6j^i!3HGVb)phL0>we@P7LeL$-D$|*pj^6U4S$Y z{B+)352QE?JR*x37`TN&n2}-D90{Nxdx@v7EBh@bE-`UYsh=}J=5my{MwB?`=jNv7 zl`woeGi^Umtj5#DF+}2W?u65#hYdJb+I0;>m-LCOJEig{7B{si%ip^IJP7V-S`?vO#1}Art=Z0r&|8MS!yHix} zXdUEk=`LM#FOcWc+;H31N8iRi(9GSUcKK&P;yp9b+22`b94eT%e*V{^KzA^By85}S Ib4q9e02+l^#Q*>R literal 0 HcmV?d00001 diff --git a/Upload/images/colors/calm_tcat.png b/Upload/images/colors/calm_tcat.png new file mode 100644 index 0000000000000000000000000000000000000000..d627a154403bf5f74bf911dcfd4a6c0455ba18e2 GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{M!2~3ezCWG-5-1LGcVbv~PUa<$!&%@FS&%GD(R|=?`!PC{xWt~$(697pJ BD^&mh literal 0 HcmV?d00001 diff --git a/Upload/images/colors/calm_thead.png b/Upload/images/colors/calm_thead.png new file mode 100644 index 0000000000000000000000000000000000000000..fec5276e4f74594c190767d156060ad45b824c41 GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!2~2XTwzxL2^0spJ29*~C-V}>;VkfoEM{Qf z76xHPhFNnYfP(BLp1!W^x0txZWF=oNu>A}aviEdx4B?PvJ;*57z#zb~aCUD7SFyw& z!K!`R1+(?UoH|UMGE7d#W=!L>JnN)9`Etim)6*wg=4@+yc5Cfyw>RwaFCw&WPs-*1 P8pYu0>gTe~DWM4fJX$eJ literal 0 HcmV?d00001 diff --git a/Upload/images/colors/dawn_header.png b/Upload/images/colors/dawn_header.png new file mode 100644 index 0000000000000000000000000000000000000000..c588478613647c98312ac16586ba0b6dc7d09711 GIT binary patch literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^j6j^i!3HGVb)phL0>we@P7LeL$-D$|*pj^6T^O!1 zM3VGZRpW_ud6BXlWDy~$gi6l4^8fR s7&Yq*+n2)LzwXCNcOOi9IQt8KaM~*4+_n$SKvyt$y85}Sb4q9e0P~4h%m4rY literal 0 HcmV?d00001 diff --git a/Upload/images/colors/dawn_tcat.png b/Upload/images/colors/dawn_tcat.png new file mode 100644 index 0000000000000000000000000000000000000000..d627a154403bf5f74bf911dcfd4a6c0455ba18e2 GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{M!2~3ezCWG-5-1LGcVbv~PUa<$!&%@FS&%GD(R|=?`!PC{xWt~$(697pJ BD^&mh literal 0 HcmV?d00001 diff --git a/Upload/images/colors/dawn_thead.png b/Upload/images/colors/dawn_thead.png new file mode 100644 index 0000000000000000000000000000000000000000..8cb0d6afea13c1584aa6cbb9e8e840777da37501 GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!2~2XTwzxL2^0spJ29*~C-V}>VN3FMcVW27 zki(#J+FA4?P=vFwe@P7LeL$-D$|*pj^6T^PI= ztQhpm33!)z^2*6cZ^eG1Qhh+i?#-1zN(Sl(j3K90i&Yy7k`Iz;C%yY&WS?vLI2_gbm+ p-Ns!f)vl}Q7n(g-HmCdp+Y#=Jid~Z5yn&8j@O1TaS?83{1OWCdQRx5x literal 0 HcmV?d00001 diff --git a/Upload/images/colors/earth_tcat.png b/Upload/images/colors/earth_tcat.png new file mode 100644 index 0000000000000000000000000000000000000000..d627a154403bf5f74bf911dcfd4a6c0455ba18e2 GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{M!2~3ezCWG-5-1LGcVbv~PUa<$!&%@FS&%GD(R|=?`!PC{xWt~$(697pJ BD^&mh literal 0 HcmV?d00001 diff --git a/Upload/images/colors/earth_thead.png b/Upload/images/colors/earth_thead.png new file mode 100644 index 0000000000000000000000000000000000000000..d210b29ab2e42796c6c4b1f0f57820aca3ebed5a GIT binary patch literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!2~2XTwzxL2^0spJ29*~C-V}>;VkfoEM{Qf z76xHPhFNnYfP(BLp1!W^x7hgk)fA%lO*sb?VoUONcVX~iuwu}Y)0!p+6mju%aSY** zWj*M~c$h(eW#P%H)h(ww{@)k8@%z7S*({y6Mo~V`X8D|rlzbauDjCLG{MJavx9#Q3 l-IcS9O`{~;4qr(Mm)FSfW?kk{yA^02gQu&X%Q~loCIDbSH_iY6 literal 0 HcmV?d00001 diff --git a/Upload/images/colors/flame_header.png b/Upload/images/colors/flame_header.png new file mode 100644 index 0000000000000000000000000000000000000000..142419632b28892ce2e97dc7207f8d91d9bf6ace GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^j6j^i!3HGVb)phL0>we@P7LeL$-D$|I14-?iy0WW zg+Z8+Vb&Z8pdfpRr>`sfEmm&%GD(R|=?`!PC{xWt~$(697pJ BD^&mh literal 0 HcmV?d00001 diff --git a/Upload/images/colors/flame_thead.png b/Upload/images/colors/flame_thead.png new file mode 100644 index 0000000000000000000000000000000000000000..e95cb6f3cda9e27b14efdcda05841550f804a6d5 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!2~2XTwzxL2^0spJ29*~C-V}>;VkfoEM{Qf z76xHPhFNnYfP(BLp1!W^w^+sbShRNtrhEhnag?}5lsM<-=BDPAFnl{RZ9h;<-P6S} zgd;jR;>dvmU*x&}u^-_Hkeb`C)3;9UnA@_AE8VYm_wrw1XK3$GJQ@+#Q~=b%;OXk; Jvd$@?2>`H+FFpVO literal 0 HcmV?d00001 diff --git a/Upload/images/colors/leaf_header.png b/Upload/images/colors/leaf_header.png new file mode 100644 index 0000000000000000000000000000000000000000..163c7db4bf3e1372a857a5603881731ae68fe242 GIT binary patch literal 278 zcmeAS@N?(olHy`uVBq!ia0vp^j6j^i!3HGVb)phL0>we@P7LeL$-D$|*pj^6T^KAF z@)#7;jQ05eMK}vQB8wRqxP?KOkzv*x37{Z*iKnkC`zYw~n)43W58JJFGk$&iOx{h!eOhm-$oINX?<5!T@ys`>3oUd2AS zwk8FZUjj-3Vk|1#Tohkz@bu1UXbHW(cA3lSz4I9O=c&u72Hj>n!m7FL#|$|Q&UX^x zucDusO?8NU5?!2DoOnIyPg}OlI@ec|-^+JB-O1X&q?j?=>jjtn^h>={%pZ9)^z2)_ R&%GD(R|=?`!PC{xWt~$(697pJ BD^&mh literal 0 HcmV?d00001 diff --git a/Upload/images/colors/leaf_thead.png b/Upload/images/colors/leaf_thead.png new file mode 100644 index 0000000000000000000000000000000000000000..8a7282f21f7d81b9295460a0f3a63f332e8c3d88 GIT binary patch literal 198 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!2~2XTwzxL2^0spJ29*~C-V}>;VkfoEM{Qf z76xHPhFNnYfP(BLp1!W^x7hd@)tO(#{QM3SVoUONcVVz#$YW4UGur0^6mj!(aSY** zWj)9!*uWrgctf1-L$=8pf2JP!UagW7adT7R;Zsg}+U6=b9y?VJ>vBh$>8we)@ziM= nFZXR7l{=}5hflTXYD?SaiH1p5we@P7LeL$-D$|I14-?iy0WW zg+Z8+Vb&Z8pdfpRr>`sfEjE6B7KY&%GD(R|=?`!PC{xWt~$(697pJ BD^&mh literal 0 HcmV?d00001 diff --git a/Upload/images/colors/night_thead.png b/Upload/images/colors/night_thead.png new file mode 100644 index 0000000000000000000000000000000000000000..30645e8ee5af3f476d776f0cbed640325c4e1d20 GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!2~2XTwzxL2^0spJ29*~C-V}>VN3FMcVS>+ zP-d{0*tNm}D8gCb5n0T@z%2~Ij105pNB{-dOFVsD*>AD&^Rq}uEKg={=s978y+ z`}S@WJmA1{sHErX?Uetr7sNaD*J-dc%~8)dpb#(hV)o&-+xs_1N=w+y)BFA--2eKq d3x87&a2FpoSyy4zQUo-I!PC{xWt~$(69AGWHd+7x literal 0 HcmV?d00001 diff --git a/Upload/images/colors/sun_header.png b/Upload/images/colors/sun_header.png new file mode 100644 index 0000000000000000000000000000000000000000..be953e3f3c2822f88d61e4383da5399521066405 GIT binary patch literal 242 zcmeAS@N?(olHy`uVBq!ia0vp^j6j^i!3HGVb)phL0>we@P7LeL$-D$|I14-?iy0WW zg+Z8+Vb&Z8pdfpRr>`sfEjE4u7LBKC_e}%}ag?}5lsM<-=BDPAFnl{RZ9h&6 zh2cNLT?XHM($Dt-MdCbN9780+dncS0Y%t(pHUARdBpT&1uRVoH$xZ*vhMYs}bK7~2 z@c2qJorqZZZjJ6U*7TbHpB6{IwpOi3Sn+Wj;Yy#TE;OXk;vd$@?2>@4RQ@{WK literal 0 HcmV?d00001 diff --git a/Upload/images/colors/sun_tcat.png b/Upload/images/colors/sun_tcat.png new file mode 100644 index 0000000000000000000000000000000000000000..d627a154403bf5f74bf911dcfd4a6c0455ba18e2 GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{M!2~3ezCWG-5-1LGcVbv~PUa<$!&%@FS&%GD(R|=?`!PC{xWt~$(697pJ BD^&mh literal 0 HcmV?d00001 diff --git a/Upload/images/colors/sun_thead.png b/Upload/images/colors/sun_thead.png new file mode 100644 index 0000000000000000000000000000000000000000..14c2441e56fc282ad5b9c09979b8bd0cb2d27669 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!2~2XTwzxL2^0spJ29*~C-V}>;VkfoEM{Qf z76xHPhFNnYfP(BLp1!W^x7hdvSXp;wUS0|mVoUONcVYO?aF@Y%pY-#+KoKKP7sn8e z=;R;&v-pIW58JD?{dYL?LHQoVY8tJoN%Qp_q3 TyJ+?Tbu)On`njxgN@xNA%(yiT literal 0 HcmV?d00001 diff --git a/Upload/images/colors/twilight_header.png b/Upload/images/colors/twilight_header.png new file mode 100644 index 0000000000000000000000000000000000000000..5a0e148a6841576050440d04e8c0866effa9834c GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^j6j^i!3HGVb)phL0>we@P7LeL$-D$|I14-?iy0WW zg+Z8+Vb&Z8pdfpRr>`sfEjE5e8Agi-<&S|v93`$1CC>S|xv6<24ByU7+Yc0DOY(Mi zVNhqVVsNv0c%}m=Qs(L67$Ol~I^m$8Qy>TP^eJiD-x7WvJ1njEXT3R_)20KDe{RZA zW@r>-oB8hMiFcXb7nG(avsHf&sehBZ_*Is{F@4oHcdXq~Zmd`}m*0Eo6PCX_bPq9J zWs~|)kojR^i=NW*?W<1Qef0YJql|!?FM0!G=Wo8aZ-;!xn%dl)c_GR`7ch9b`njxg HN@xNAu;gGV literal 0 HcmV?d00001 diff --git a/Upload/images/colors/twilight_tcat.png b/Upload/images/colors/twilight_tcat.png new file mode 100644 index 0000000000000000000000000000000000000000..d627a154403bf5f74bf911dcfd4a6c0455ba18e2 GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{M!2~3ezCWG-5-1LGcVbv~PUa<$!&%@FS&%GD(R|=?`!PC{xWt~$(697pJ BD^&mh literal 0 HcmV?d00001 diff --git a/Upload/images/colors/twilight_thead.png b/Upload/images/colors/twilight_thead.png new file mode 100644 index 0000000000000000000000000000000000000000..bcd569624b1bc576e0263a1b4c967a81a7361f2f GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!2~2XTwzxL2^0spJ29*~C-V}>;VkfoEM{Qf z76xHPhFNnYfP(BLp1!W^x7hd@rI}~0Z{Pq5u_bxCyD+FTSTVTSJUr6@6tVYoaSY** zWj)9!*uWsbvT$~9nuxQ+f5EDI>vMNzm#h;svh3Yin>}RzHZS2I&?p8^S3j3^P6we@P7LeL$-D$|*pj^6T^N`c zlo>20cCD}gif|TqL>4nJa0`PlBg3pY5H=O_FHWH{4$0j%d=d8LiL_5jv*44 zb0-`WJYvAXEdFa}(dBjK{I@3@`To&h+Ju%LvC}y}REQW&aPe$(@sKceTy=DDg&yOC z9Zh`j3n)~5) v%Od;y5AZ)-|J1udjN{ynDi2xlwa?jBd)KWI?-ywUI)%a0)z4*}Q$iB}y@*ly literal 0 HcmV?d00001 diff --git a/Upload/images/colors/water_tcat.png b/Upload/images/colors/water_tcat.png new file mode 100644 index 0000000000000000000000000000000000000000..d627a154403bf5f74bf911dcfd4a6c0455ba18e2 GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{M!2~3ezCWG-5-1LGcVbv~PUa<$!&%@FS&%GD(R|=?`!PC{xWt~$(697pJ BD^&mh literal 0 HcmV?d00001 diff --git a/Upload/images/colors/water_thead.png b/Upload/images/colors/water_thead.png new file mode 100644 index 0000000000000000000000000000000000000000..570ad01e6442438ba9cf704a181baa416a789ef6 GIT binary patch literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!2~2XTwzxL2^0spJ29*~C-V}>VN3FMcVUoY zNM=Y;yX&+BD8gCb5n0T@z%2~Ij105pNB{-dOFVsD*>AD&^ULz>zEx%k6ms!&aSY+O z?%KOikcmN{+2UJa%yH9*A6ZkCI6qX_>9(Y7_H~-2`*2fAr03+j%hugDv^thM-SDU3 lxAc}=w@<%z?CblzkFoVhi0PGrGCQDo44$rjF6*2UngH)`JOcm# literal 0 HcmV?d00001 diff --git a/Upload/images/default_avatar.png b/Upload/images/default_avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..9b40bed947a36742fa21db582ce62429d5bdea29 GIT binary patch literal 2068 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 O&GfP*tj^Fa{{H~)sg0Td literal 0 HcmV?d00001 diff --git a/Upload/images/forum_icon_sprite.png b/Upload/images/forum_icon_sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..0944c69657d418456c59be0c96b45a19b1211f41 GIT binary patch literal 1130 zcmV-w1eN=VP)0003&P)t-s0001> zprF0Iy`rL{+}z#X-QL~Z-KnXn!ok9*ND=RBQLqp%+-yt9&*w@%iO-?74qobs@wzlEm;WINcN=ZsyUSHVQ*vrbwWMpJQLP9VwFiJ{FbaZqn zDJpn)ct=M^D=RFbqN3T^+1lCKNJmK9+S|Ihy1l%;+}qs0zreS*w@OM%NJvTD+}*Ua zw6U?VtgNiBuCLzR-r3pOsi~SA4kkixDva+&wcXyndo0XN7o}Qj;Y;0s?WI{qhIyySm z*4A@#b5UOjx&QzGI&@M_Qve4H{AX00N##L_t(Y$L*EtQrbWmhJyhSkDwqb zf{Kb-wdGK&C4dx2g9s9uwr(hdLpaI(UqCkqUlMlt)#*&FK4g;}p8a+wlYM8Ie*;U< z<;!M$uAqfxV;9*m7coLEy0Qjbi&NH_HQ_XSsD*l?4d!x*95Ctz4ceC@@agtCF)2>y zy=%~(1O*Rhf1jfD+0P#agFc>CBR6{D6)r$OXlO%VmVSRQFjP}G*Vq0|!4KN~gMu6M z%})w93~*H;xMFm?rAn!U8@|R=yo`ZBX^MdPd;5Qx@K5iDrEdn7zyjW*i9GUBcd9pV zgk8XEVO|v$+xklN-O9R+`re!K)k2|Atrn{Dn}po4@&%qRV0iqq?wIY|S~|`1JZ{gd z&6%_{nKolJT3d1im(;Nt^fLEMQok?jb}Js|?zwmzH;%i9_X_Sg);^? z{z`Dn=-358XbKw8u`>o7cT+gb-}@wQ;$)67dq>fL11xZGSRQkDK;5bK(^ZyTJ+=RD z34M#;Uya~xTS2NYD}rU2MTnKRXGBnJcZb7nJ2oSN!%i=i>UBIbBG^@XnM_ZOP$P)s zp497RFS`*>kP<;T)y$VWk|-i&pAtb?Gh(YH%hEn2f~IORf~IORg2U-*h~Q@}f|q)A zlp%4aGD5zLkfNw=nhv<5p2(6$lzADvCG;g8l5ObZX@?~0OgiX*a!4XoW%B~=i1kk& z$wN{p3T;J{FsVoIdO}(8u9z2^cxaK$guz2XMX|_g^)gN(8zvH3mRgFUAcO~?@HQo( wYO8x03WX#w1eQD`osttQ1t(Z49b%7 literal 0 HcmV?d00001 diff --git a/Upload/images/fw_pm.png b/Upload/images/fw_pm.png new file mode 100644 index 0000000000000000000000000000000000000000..19818c2658424f2f46c27ac0c7da0774dc4fadc2 GIT binary patch literal 791 zcmV+y1L*vTP)`ALGt1=#3K;YMWlfzy%JBVAQ4 zU%)U_l*=X(!fT}aP7f0Ip)Jw+KKE!U}pC&fYAg`It;d_tNu^J_$E ziUo=pHG;ppq@uvQ;o0!Ta}VFvP9)U`Mkz1MsdcN-_OqD&Wk+7O5rJ7G#wuhk#Qm}+ zVrr40wW%L7`8uPd>sAj03IuocHgt5K$LExcoK_+7S6CpStSaE+0?^hr0H-?y&RG|b ztc7X9;R>OpV-S<^$CVPSmvG1X0kpOcKz8`S&vMS6Dd@D&DOuDsqzZJf_c8)L-^NK{ zDV@erE(gV_!A|1(e*%Vq`BciP-!98oURn7^famz$z40u%wquikstTEW9=SpR;b0Kz zT5X%n>+vA5l*e2q0~R?E)74@{Ae+hBr@wxKKNP|D0yS*aKzhYMhJ#|h&KFG-G!uqy z;$;6We41&FF`xGe@rRgif6rCf7u>4^>J=r>;8gq#Zl$))BUcAJvZuyfc=927LX1R$Rj|g;Z+dqy_e2(Ke+oW zPLmq4N-#<#{y8#hn8g-mQlm9hegFFYBa5uKTor+>2%Bx0MoFI}PGMYjI)~QtzX3w3 V5keS$DGUGr002ovPDHLkV1nRHZtnm9 literal 0 HcmV?d00001 diff --git a/Upload/images/groupimages/english/team-administrator.png b/Upload/images/groupimages/english/team-administrator.png new file mode 100644 index 0000000000000000000000000000000000000000..d2861d656225ef0ca2a96fada1df74498019cfb9 GIT binary patch literal 1300 zcmV+v1?&2WP)s-`TYF+^Yioj`uq3y`1<+!_V@So_4V}h z^!E1l|Nj5||Neh|fBpRY@bU3-a&h|m`s?fK@$m8a_xO*Gk2NzhczAd)Ffgi{o722zAs;c(Pn3I8l$fA63UteWYQ>Uk=g@%P+Ute8JOn7H!x{Fz_f>WDn zJIBYyqQKtb*2#35!I`GB*~YT5qon%Op+Ik)@x+mxjf*i-g)ST%w&?6s00005bW%=J z zC5MN+hT(3@%-+riPe||1&!o}`5lZjhN#|ammQM&Z@ZL*jLAli|w+gC>Q)yM2m1Ya6 zOu5-=6>6mgrCG)Sixv_lDC9k@LB_!Z9^;ll1(GDG6`)B0JXRy2#0I$0T3qT#E^6#O z4$*$JP{1Pt$5bXs4W&}0(y3Ic9p>)$E~}!%sdm5tq;*iYs+7@G^Hj)S2_1kMdPvWS zLWc%GE=i?Yty;s@>EYqwep;=f!7aiYXe4KH`Hegdc4|OQ7P&)_L^5fpwVK+vxW7N# z$M+YtM(qM05RC?E1ayrH02wuMLxo<01Q{I!D4;GHuOw2TQKr{0QPqYDIM>_lwWBtu z=^-_^3I!!g0~9?7gy9Go6FsVkBMl*+C4xFA2yZk@>Kf74zrSs_-+o`$>onG@*Ix#9 zudbps2O;!2Dh>U*jjE@DQby*n5&cf8AxinEcEzW6pvea71vWA+`5Z~!I@7=8Wee*FCTqx zEHE%^H=p4NO0000< KMNUMnLSTZyD3D(O literal 0 HcmV?d00001 diff --git a/Upload/images/groupimages/english/team-designer.png b/Upload/images/groupimages/english/team-designer.png new file mode 100644 index 0000000000000000000000000000000000000000..4fae7f84865db4ad5108e10292b9c88791a46ca7 GIT binary patch literal 1524 zcmV^z`-e^Yi%k z`S$hp`uh9*{rvj+`S|(y^6~QS@9+8g`uzR;|Nj5@`Srh@$c{d{{Hmy^Zon$ zKR-V=H#hh8_~f*HMn*>Z`1Y19F&7g6>j#=&P?cw6$*x1^|aw?NO^m+ULy^q7;9SqfMyA)l@HrZ{QOb2 z{c@?QvFa_yS=m;j-`Nzpwj5tdF|DQ}p_Fteuu_03V&NR10EUTBKjzKs!>k!L_@V9f z^%sH2D-KE46z5sj<(=whgEN6|sVGBvY0>Cq zj3!UDR!xuEFc4+8t#fcJjc?8+imXJ9Lb4Dj5FmUDNDe_9_Up3J_E`1*-}@#Msr>N{0Q9s4Q1gTE&$hm|Ui|TES%PE@Jmb zT$b^MvJ!G47q};YDGnTALS)IR>n<(aBAvW`zHTkuOculAQ`Dc&&!h+0O!h-c;%w?z z6f}sboXzL+5oHx_(3TLbMQ{+LSBC*PO#q^@@-Z8SxL5q@|h!iC!B z$%$a z5J-90`%)z>wGYo~J-x^~#38`!KTufrD!66b0~6m@zB*l-rYWv3xu=v0z<7ZIjqUjg z2^@4HyF6{eGczn=O~3=_p@cL*0vC8_dWsKx4NQdR2_g6q3ahQqLX(<7=H}+Py19>!kFBn) z*x12$W{=B~h(F-9zKK}&ovQ58Uh_scT!CU)vI(?nIdIBI}z>T@T!P-eD%f7=E zE&@BX{Ro2O`x}~&U?VVi_zF9`@P*N(zQv1vDwRQW`i^140supGiXq^DlTd*eyL+VP zy_N83?6=pp*(p$*@bNebqS#^Vx-otQ(BzDeMO&OXki;rRvdORFx9oFY*bv9A1d}v9 zr*f!=qHPNZGELJYg0k^gcF^l2V#bs4@_< zIPqU|Po%6oa+qK0zLt;u8xb}!mxk4($+issk) zT7n6mmF(aLC?y9oaVMKza!O$%ahC#fYa)1a>%fGA2_y|i=#Gol6q~tT)xy=>nzh#X zHP@`l#R5G`LlulX_Rz|tQZOapP&`0FAaMYg2qC(@pXJsxo1FW;6O0LgCcBZHE{b9k z&9W=jng$92CaMu)=>?dG$L?jAgTn=b1v$bpm@vS2UALbw{Mpv)$Sm|O`$x{g`%c1x zO?qhe$Ta<^KUq2qV>6+~#$iZ^c@HN(j?Nt0rV*xNE&LlADRJ zNNHWNGH3Oo4fLt}Zc0Y13|~TE3?E~_E{Ei4fP)`{r&Uu z^7Zxg@bK~e|Ni&*`2YX@@bB;R^z`uY@%8rhFfcGdK|wh=IsE+0&?-``D5P3Pz5)Y8(mwX}3}bYx^?;^X4O!@{PPmQ++!VNg)Jyu7Tftbc!hMn*=J zm6eBtgteumshpgfo12V`jB;yhabRCtTU++bn2(Q-mV<-jwSmc^e0h0!ppTF4z>T_# zS+9aqn`%3vz~184$#j~*nWnSZ#v`lL+tM-Q}bkLdbo1FT4{HIe$aQiSR+VOAMowH;lZ2PPJ;}OC_UJ zg~LH!HL3=X#{eBnXa-t|N(@nBh$NpcRr4UAMQrpz3o1WD5hblGCFSujfL^#VejE}?*q zL4DYnN(rV}i$HvCM6PSN=LdD{DitI_Di#aHLZQ$fuGhmpk|J3V9>&2_US!>DfF$dj zvn>DrEpL;^{r!CrHU$0-k?@)z7b(dM2MM{%<6g;EVithw19*tY6}f_qzfZf}>9>3@ zqn6JiD7a+>UEngf2H?tu=ZDiOS(ijqT6_BQW4HV9=TuQ;4lfiT7duV4f+<{u)6@!i znF=z3%UtJLcxdTZcqM{3d;xYL>1 zj;DK3PnWSfo4MPbuI}A|uO_iS9gNkv<4z%}+qMo7-PQs7+spCz@{M}D_C{f3x;>|< z3rXU(^+`AiroOI7Y&OuBsqM!)bKA*wY{!Gv(&;ohsV;ay;00Z09n4%)4BH~@#U&Bb z)Pd;j_4O^%FYu)8xHo7*BpA=9dwsGs&Ca7P_GW9Ryh=?!)qCN5zD><|r8k_OId=8^ zbUvTXy3R-soQ4^Wu*SrpUt*djGtJiG^>}<;w5VXHJ;_fWmrbV;gtOjYZ%#T4BIab< z_MLKf8m}eR4%_W^&y0Pu=>%--n)3k~Lf2`T5MkknZw4U3fZ*Zj;q%w8pAiDa;Yr=l zYc`yQ?^;2)XAohXN9OwC#8F0ZGhs~e{Ib|!vCo=L3nEPNB-Tx+2%tLkSq2iZSnqK7 zzF?m|vBmepp~uj%z)w>PBF%v}=&YB_QdU9o%xy%M{M zg}|TJq9_|cL{XGYzyI*m{rR)|1d)wW!%=EA1j@=Nkdez$FmfB2pxOMOL?#6Td~Q8XVoLqw%G>wn^mXz+Z4A z-WZV}+%?1-qmjdhMB}EvC29yCZ~jS?yLGkb Avj6}9 literal 0 HcmV?d00001 diff --git a/Upload/images/groupimages/english/team-mod.png b/Upload/images/groupimages/english/team-mod.png new file mode 100644 index 0000000000000000000000000000000000000000..a97ae6b1960edbc42d22e7175a832ccf643c920f GIT binary patch literal 990 zcmV<410np0P)+7AJovp2{ zR#sL^OG`pRLUeR=mX?-0Jw0DvU$wQhe0+Qc1_mG?AR?KonE(I)2Xs zf>*8G0008{Nkld9`5LAv`UBn7l3Ic@g!;E4>B{naD$7#|r#zRZb6)1>{9K}(P+WMcB5A*?!qE@qLW&}z zMHm~~jEz%row6cX>$V{2$%O<-aO$vO0JdjW!g6;J0v7ZkL-&_nkCueI86o;x-3q%% zqY8H0=gkzuwi{h^i(M|M*_W~C>vbV_9la}Dyg&&Z7D5Cp0qQRLB1F>17t+$ofv>u5 zt94Xn6IyD$8ZjQ-wDPu|Z6|c9WgE-uAjY||QhC=Qr1;S;gcHP6Cl?fP?Hew*kjXLW zS=CBQhJ?5`oNq=PN8i`Ft*;z!N3=p(E)KjrF6072_zmVB2mx1|U+V4Np(Rm4%VadS z5h2sgxRyh2DvqFeyI!wtTQ{6f>!fSVrLFifR@Kpyi?`Te22h2Nig2s<`^Z>Tv5L7R zlUD8uAxci&%~W=8)MD5;E2b)pW7W1*Q*GHgvg$UgL^jR^!h|pkj1UHxKg+#m-ysub z4u%jmt@VC*oMk$BENZC90zd%TursmIlH;kn~@KXp!R62BE zv?xOdLI)aB#{=XL!|~TcLp#hs2xXZ2oIVc-iPQUrj2KAqVPU7#`o>eJPD6zS3jV)u z;-Gy<+~4Q;nMk5&h@Xt1iC$FvWT@ZKYong}w+yOzfBH|N=;ih8FGRqJ(pp&f>Hq)$ M07*qoM6N<$f)8i;EC2ui literal 0 HcmV?d00001 diff --git a/Upload/images/groupimages/english/team-supermod.png b/Upload/images/groupimages/english/team-supermod.png new file mode 100644 index 0000000000000000000000000000000000000000..941f116928509afb8492c9f2e8f7fa0ec8b25178 GIT binary patch literal 1219 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 literal 0 HcmV?d00001 diff --git a/Upload/images/groupimages/english/team-tester.png b/Upload/images/groupimages/english/team-tester.png new file mode 100644 index 0000000000000000000000000000000000000000..3390a9ebfee75969d257aba6b9aba41dbe147b57 GIT binary patch literal 1311 zcmV+)1>pLLP)V6%*@RF{QUp_|M&Ly@9*#a{{8#<`|$Aa_4f7h^78oj z`0?@a`1twy`TFzo^Yrxe?(gsa{{Q^`{{H>{`uX@cI5_zF`Steq=jZ0?>+0Lv+xq+Y zQc_a9yuADT`;3f?b#-+xFfg^Wv^ID(H8nMbhK6r%Z$ytoJv}{_mzP4BLO+8);pX9h zfPi6PVOv{UMn*<8U^Ug()yT-mdwY9jwq>fSs+6&lal&zMjc{YBV@aDyN3KVopPy-I zX}i(8TA*51t5#E$R7Q73v*zZixT>DXo`;);FM4b!8{G!NtsMfq7zT;PlQyT zyos8Y-GpHv*jp-Xm0DZ7y%DymYUSqfDLe%_@po`Al?{bViUA(4Jgb1fhi3kRvUeDwcj;uv-7pRY0VBU zr?m@^t#hf-)>v>0w{&a)u?A!997f948gM5*=Zwad4KqTRn77A`Z`!tP{N}i2X3f1} zIUf*{khdH|2u?N(6=_X~!iWA?lZFGBSc|D+0Z9n;iRyFV{kRx=Uz}?S)%#8M!-OD0 zUd>M+nIjh#ma$e5& z&xb1eR`PlCB%SGqz75>SirXMPwHzF zjXqw#v*?9Z&#Uqs3aJosS5&r-Rw^n#qmEC?!Gm~^gf1l^f3;TIZlf>|rQM7BV9B*C z*}Pc72#Z^q4NH;@Nkv4%wo0q2>gE5xWzRU<<_kFX%$%7saKszNY=^FEAMe_`$F}Q+ zZ7{iQ=2^sSaWl87`9rJCs`Mnm#9W^gkuUP4xt{sYew9Ht2)xwcjEZ@ld~LDe2mN>1UO^zjZQ|{f5h8uKUtUK<8_%<^773T^w7lH-D8rZNdbPe_a5p zWTJ4AkM8$~(|sfml#;eAvz*JT%-TXOGn@O(qR2dnGGC(vMP-Xkp=4vN3q4GrV+WAL zsE~;O)Ubc8$8oG*_k$t`g&`%8IARH?6G5Ov848MHf+U9ldO#6S5tOOIgcF{4@>Y-a zTf(0N7c>zR=Y%-ZP^bcDMh}99O89DE!s3{*2OcN;dY^Fi5VM$JgK>;wBIsfe3d$_# zOmKz?rJ$cyi6CJLh6p>sWO7_Z7miH~7e$vTn;7X2{79seev3<^pOgO*U0i0%h002ovPDHLkV1n$Hm{9-# literal 0 HcmV?d00001 diff --git a/Upload/images/headerlinks_sprite.png b/Upload/images/headerlinks_sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..e74b12e19377d9caffceddac65905c72ee67b6b7 GIT binary patch literal 2302 zcmVZ3C@r108i6Y-$PX&Tw>CHQK8|-@RViv`o5~5u>A{o?soWg$F^GhTj-$2DS*Si?VPVt&0185}MTIb4IsoVG_qdi* z6j^Nm9b)eG_VxPu`~3X>|NrOk@NS>uPkg+?&F#p^%2tHN)7|!5iptE@@vg3~;p^-0 z!hhexW$N_w-th3+=jYSpM}LiobhXt!!#)YW3t)z>rYWuTRLPM#CyBtR5k; z#ouz5$(pjTe%6v-UteFONlQUN;^FstpV5M$%iF}b<&u+jv}NK(N7kl3w3{Yy2@8<0 z+5Ym)_sz}c;;zrMbD5ec%?7)~0001vbW%=J0L~ejiN1$;W2C@!vSzza&?CIs;?lF)>>+)>-&5<7m95h29X!Y%zE~!k0L@H=!FOW*4u|qLP z$XLnP1;Y~?6NkqxY8K&# zcA?>m{U!!5eMr#H%Y6K}x>8r}KB-i5q3H8mPvV2b?QjhuoD>?f0bsUiC}Fq?cxk4D z&G6{atE-<3wqPWl+6)H$tK%<8G5D$3pnr7Yq1IrggkD=(>agg|JCL|$uxRV*v=)nj z6nd@Wc&S6H)khNo6dpdT(`qffp%`(^;&9Z}IUEkJ&>}27pzw|AL2?B9=j@*LlNdP? z8k%UM%DhJ;=jP3GJ@-Sg8K$?1&)#lEBDNpoSz^DT7>$X~CZbFUm}!8^ zqipAx5VpneKfEh}bZi5Z%)9R^JT>=%3aNBaOn(bk9$LG6EM=K*I09Pa^Uc zjY5;Du!G1q<;QdoF*zXrW_au_UD!ODU~if+V-uSu`eZzRp3#RUMl=|W4I{ic1k4~X zghIR`)mTwsOoakbByl<=MVOb->m`!);1eqX6-e-;&COCC7MgYe+`(`tt&~Vs4jIZ- zF+mLr-M84<>U6d~9)E`=z_%CAvRZA8jpM%GS-y2T5I&h2d`f*Ce`ox-OdlYkH9(kO ze*jsdiH1W8pHhCGmv4>kO`B6u3l!LICAKp~EEH3YQgnu2xV-G*(c=&xP(w}NZKzR0 zO*GWhz@Zwd6A*PT)KF0qs2AB#q6QKeS9OZO+c;JVQKAM%NewNkak4{$<$X(cC`8>U zMA%;?h|3M4Ck9ug1dkvh?{UYA-EMKbdk->VPm5=r$Fr`y#UqA-5wFvgdpzYjT|5KN zF&xeW-2{;cJUE;fAUG{$)jAgVpLNw`EgT^D)j;sU3Pd#@pPhVumTn`TzfqUP=MTUD zp{%O1+7~Zs%c@wR=z~?=sLHCW%mNDwioT*s5v#J21(v=TGE5<}wiY~KCLKus19Rtg zi2h3#&h_)B<-8T?k&*Mfrg)|?@=C;-C6tgSIonOIeCAE5n^E& zAryJ`$V*oO2Ih?+Uy_1Eia&8g$jo{t5D}}2(IEV)u!R2yYxfhX=281|2bgRTzh#_smR^W}D1T zGHDWP>sAUvL0Bt=E+WWYsO%Okh_J#6g8#mQH{OaLKtVsi`j7Qqdu?yT8@=#GRuRm$ zhRyDzNoMApnb(VUvyFl;JXhzO-#O3kh^q3+j$!Xv=F_MN&ARaCu>3Ze5fz2L&{`H+ z4Vmxx`cV1mhY|xU90m-qzf|FamC)Q*#aHDvaPw>pfY+~_hWP;IQ81Wfb~ z$BuRIka>V}3&h?2rS9n7JqCXb7@rg*G@4aLy6$zS6mg6>2++t;= zLl{L=mYaChK(4>`{IzK+d$WuloPFc)K5yN4|DCN3QY5*G%+fR3S1K{T)ZrvI2(`jwwz~8+F!$G1> pR2301K>ZA#|DOVw08>>h{{aiSE?0|SG&}$R002ovPDHLkV1hR@aaRBU literal 0 HcmV?d00001 diff --git a/Upload/images/icons/biggrin.png b/Upload/images/icons/biggrin.png new file mode 100644 index 0000000000000000000000000000000000000000..404859b350a0289b1105d20854b27d7b26206149 GIT binary patch literal 706 zcmV;z0zLhSP)B|&R9L5X@( zix!auL6J&bbWwyAt6*NVA(9}GR}uzYgj5L1>Y^YorkHGE`>2R!b&=b*m3!ar7z}#h;k@TOzvrQ}o9Oc}(N_=Ayh4VB`(zPv3i*XX%M-f= zJ~;5mF>~p&TwoSb76bcZOP{W1^^7aexkp7z?6|`RSFXT3r>s|hM$c=UaWXFmX)fl> zaA{%}clhAIuM{K)$&eZ%ar!cU2{!Z7?kz$lp7poMi5++N;J_m%3*!A`nH$|1 zFV0?IJ$8=On`WLLw+S`#ldCmyV#ggmIPl2Hf@mK(zrV9)_3%m7-=F6AgL>Ad?W{*z zIR5aEoY>`E_~5`JCkw*2$iFmoHa~N(mJ6?s3LWFZn?|7%tJGM!3m+VKvJaV$&aR*r@dMo4FXdQd6ZRPX_mBZmM z=W@A!ChqXTfk#djjI@!#-Ac;L-91`LIlyB#YWaod5~n`C;_+ZWPVBhD2L~QGSukKH z>bH@3sHH-U4(!tweP?*eb&y})-p#6GyPVi@hYt=sac&FjwL-u zve|$w|9i5vh>0C{_~5|f{ViB4gww7~MryF`rFO?Da^JC%Dgq%)?6?cRPH-k6pYUm+yP9HixY1 z@Zh|N{#OGJ>kdVvsaRRpEzYzwbXg}gA%cda2d61vtlGe)%TfQY$M?-!laEAMp|K^ z*QmfYXl0>iRMslJK_8OH9oiT5+r{?&28ZC{i|w zJVvEr&9p5@yY*UrH`^VUW*57Lf!SQ!{tVkTQ8)Hrn^vww#hUmiFHhvthQnAa_=Z`| z$0uJP-)?v_RPt`RM(z~{l-wY=gzH|Q(fEW}&c|jG!H)p$rK{xKbdB80bY5&VjRVZ9 z>{MVF?_o3!VKfhNJMZ59&9akof;eEGz2rJ4_LYfiRag_&|Iu2$ dciHc{%o9h`@UJE^r%nI>002ovPDHLkV1kR?0R{j7 literal 0 HcmV?d00001 diff --git a/Upload/images/icons/bug.png b/Upload/images/icons/bug.png new file mode 100644 index 0000000000000000000000000000000000000000..c53091e92c6034a1fe9e10b9be3a596e2a6e2da4 GIT binary patch literal 651 zcmV;60(AX}P)@7I_|49q0f;F*qf44pUip1xUnBJ>^{eozz}2r+21CO~j-KgHdjl{^ zx~{M2ew9;~0&{`&$+bzYe5^D94IeprreE>~iZU>v{j$ES&a2P8_jU7o{el5*NR+zSLX0+*f2DF63li-pSUp zoL|aw>}Jd`G<@Xfp^rOfAV4(=(m6pZbkfz*fwqL8Loto11o~v18jR+QMDf zt+g%NFvyG6>figkp2dg)!HXZ~eV^z5d(Ovu2moyc+VlWA>Rso!kEm;+o=!Zm3a$uL z!H9`!)~qta*{WAFU}s&|__g-l@foM*SuPNYlyzMP!)vE!GRHm6aQ5#3^>xR_Z0B!J zWFnCW5{U%T=`^z0tc2IeWD?P66rABKJL>}udx(xaJh=aoR}Th*2!%q>G!2Gf{236B z#}Nnw5DtfBpR?>pmpVt8zJcM#1;5`9hrP7chV+cAf;?geyQokZKkQAumhkfgfj z-Wk=vX?qOpuuEj=pSEes;*s+k{sx?7hh3t*y>4o~Z2XH#rGi4CfdBQSyIuT)JBW%_ zMFC%F>#k;MY7@sp7CvMXi>!%WZI)fyBK||MnB~GYqA?Lx1bYN6f@YHzv!-yylxNxH iJ2eQJYQh_Zord2~K@@9ABpeI?0000^@R5(wil0j$_K@^6EB+vw;X_j_f z0>N7g5p!rExt1CTJ(RQvrMN9UxAf>;L4;QD;=zMxX$0Hah*e2NXzjKolptB^Vxbyx z>Iy~=IViig<@x?4J48@CIPfiR-~9hSv$G?JNc<1}-;>~ zx=z;kxDRUdzRb+HFXM3&+TQ|7*jhAdoKH`?pQonitXQPl=qLpPHF}>WC#hL1x*I(` z20SugmA~(Jc-Y2j@5jb`_On?TfI8@(6bke%ownhT0S|@P_*f`7MlMGIuhVI2wOZ6@ zG-!2TfF3D|&zh=IWoXEOM+Q9LljhaE-H{P`o5@f)m7)@h>-9QWmPKoc1eLmYo=SP} z$bkF&V&?PS&fp-G`}=8&Me7XA&1TcD(F@qtG!GsbaF4fhkjXd|UbVu4fXxowJ+Q4P z4m>ho1s6wE&kyv0KOpvzA|$#8jY}4t6?US!CWqfj^j`guBH|26pO{D;c$rk zejn@gI;K*ocgi15E7;I={X&*2l?p~8k!Q;5(+cJY%PXKWIH$ZOi@{(}@Rxuo7>4n} zf^<6lN`gH;Z2y5z5^N?Ci5nKs_8+Mj=R5jylLR3}QI1(a#WOtegz#!jar=2ojEt`7zSu_MlNPyQD!**q)U s69O7N;{G4>q=3J$C1QC7IIpqb8{8WaMpvGR1^@s607*qoM6N<$g1BncTL1t6 literal 0 HcmV?d00001 diff --git a/Upload/images/icons/heart.png b/Upload/images/icons/heart.png new file mode 100644 index 0000000000000000000000000000000000000000..92edf740b35e51432d5befeff5344e41ab18d1f5 GIT binary patch literal 714 zcmV;*0yX`KP)!oUfVpIODAM$qds+Euefl+puCPVIL8}Xr$@?aX{59!im$wm zzU?~|`MS3u;wv}L=F%ChZkiTHT=XCpFOmD?d(GLvN7EsSF|_so4dhjlBfX5emz7Xg zvMEZpb`!Zx2Ls}Wix$jDPS(zm=TJi-*M#7j|U8 zhKyXhlI{4s`$TXsZ432taXto?ZX{RswxCUw>4-Y)q7(WkPqD(>wJ6{9$ygQka&d@- zxp?_U-t^M2U6bRIZp_1D=wie@g09KFFwgVFup{hGDJDOQQCJ?)mV|BbSsv*~H|EWK z03AqGJ%sk0H6hbIrrR9;!J;slYz$i!y<2wDnd_h$i)XonWZXlF>NXNB9U84Cn6x1x zbSPSnWU`aaY9!#VrvM5Xkf6Q_O`CmzZdj06GTHs>sF*}1l}XD1j2D1zL1xJq{xg;^ w>iHg!=hK;W_$?UCzBOnglG1)xc~qF literal 0 HcmV?d00001 diff --git a/Upload/images/icons/information.png b/Upload/images/icons/information.png new file mode 100644 index 0000000000000000000000000000000000000000..250ac154af380884c06c777e911c383211850f7d GIT binary patch literal 701 zcmV;u0z&EQ?r9>fs8ygyO^_`f+AT&iBNQ-Sa*R1AjAY^Ngf2PF!L$&S5rV8%m@aY~d*0F!Q$oU0MC4-+n%k zwhn#=)48u;aE2+Ut%FO@Gq99ir+wzf>~903<)yVAw`Jg4+Sor2oqeA`fAk&X9%}UP z)^%nvU7~v8#tt`7b>F(f{C2M6^ap6^4N-R60{H>dIluK}6t;EF%wZ=#z^lCN>gbCt zHy@dW98H#2Ak*Cg@t!+Sseb^Hy>}_7)yC(`*x?4GH@(LGSO&k;*fRslHXq3LjY1$0 zfM75PQr$z4>D_tAJ%b%?Kzw7o{Zu5o-SiUV2PUD)@D#SRcxgEl3Q>(-4n?~^iydx2 zbp2YB^-a3Q_!<-kSCF?&(Q-T~I5{t~#X6zL@541Zum(lp14@mJ^8t z)j1!j(0V>%ha1>=bj(u-s93*1JKiI0w4qkI1C)ouv=?{hGnf8kq#ry=5@~9 zcK~p)H3V>K$G+;O@{^Yv{AHn1E4`rCX5xwI-Y1o7^V30~8_?N?9H2A^sNcE&;L*lw zk1j|jrKMcA)AqNFUHCOzcd4yn_+h(iWiGa;G(&j-pt17I)n-R+7)se`AzYZI4=Iy! zB{^hPoxa!*x!1O&$pc6QKUtgfImd#G_*c8Hdqqv13Sab34#Cq3D}{^T$dlDJfYUoD@BEk%F_aSd81<)@*ZF zCjlZcm4AY4bVinFX{iBzP*YQlZF|Vqm=7=j4^YtG-|wxhttF92u)6v^Ti**E*7 z+W`UifMTF98jXHzYHEH71hm$jz#d>7SOM%T@EcaQpY(1CfI-VCAnUnB#sZI~6X1hUNhi7&SLbih>b#295{j=8r(Zz*DUZtQ`W_I)wusOIcthe3E9ur!pRMS#an9DxEzD!&;^*5ODU00Td}i zuHDn|k4MO7D}T@T8}=?lM>m4#&b0!8{uao3+zP$3;XSF~aOoF5w+ysFF$c1X`zjE` zkqj8_gJ`=&Q{;c^+7{!p-q;K!^_KxEbBp^Oy#N3J07*qoM6N<$g6{4hCjbBd literal 0 HcmV?d00001 diff --git a/Upload/images/icons/music.png b/Upload/images/icons/music.png new file mode 100644 index 0000000000000000000000000000000000000000..4e35c7710bb7e069406f485e074c536e82e4a4f3 GIT binary patch literal 709 zcmV;$0y_PPP)r+70Tx7wbRpGVmYh4-k|I4n6FkUWT<7LGj|jT_$$4h%oR_Ez_i} zZLBp*(>Bfby*^J!DY^5}BXc(w0U!ZZv4-z31OQlFB7?b`ivR#-W|*9`5~I}+9N;Uw zg-HO&0002i);4TzZaX~uSDu%Xd2S^Ht2oAw01<}61OT!O%yl}4%bm{QN{rc^c6%na z+cRcoTSCYd0YXa2txwMZK$eAcdO8TZyT1cm#4=X!=F-w@5LTCnP>jzV^fCZhMhG?4 zYTIbE4?R4h-8riy%V(aR1@uYxDCjT+E%G zp4;CWZwmpO4Ems6D_wbMY3(yL#*4^&79uUwW}&I5_jyvxDv9t##gB z7E($=2v9+eDyqm4VEUc4-)_AAMl)c4XUFLu8}D_#xcga3sTToIK@C%wLLC_lp8jzE r$)JBX#`ruu`}y;eNB6(SEPDR~CguMA0P|6=00000NkvXXu0mjfqBTA5 literal 0 HcmV?d00001 diff --git a/Upload/images/icons/pencil.png b/Upload/images/icons/pencil.png new file mode 100644 index 0000000000000000000000000000000000000000..96b291271c6cc60140dc0aa62003e1d6508cb601 GIT binary patch literal 1506 zcmaJ>drZ`J9515IkrA9i=ACAiqJ}AVZLjyN9CE$h$uW-|2ZTcnq1^p|3cVg}frA-E z6J6XO8krj~h9Vo=+$L^J$8hs89}zU0OI)T-LWUaOI9~xK&h-$GKNg#`zt`vU`96Q$ z;!0Z{8KI1TASlw2Lc8U0X6T(UUH;C0@RX4Ug=F(c8GM0M!3Y4d`1pJPJ2<8gxB=s< zEbRt~5ERa`nI6gGTtRwyPR)cc>L3@8*$|YtEEr(C#Xy4dK_TlmBXCl;@#s6oE$}Qn49% z=9I_jf~~v&V4WIMc`-c(>v1(sXblEK0<6Js48=4ku2JCzlF*PC29G_6Y)$YLkZ#&O zW=md~ks?V7kSJPFQK7CN)VxrL;wFb&KEN{ZUQYzZt&ds z|J4^WD+2&^1CcKiymA!_;wG7Tv7r!fEC$la2*p6IqMa!b!RUe0Nz%Nxj01kjL7Nd7 zs`jxy(tv4glvc0B2%`bVZMcQDX{?l$z%UD?(`)qOT!&wj7{3>cbJ^!y;)Pt&DgZ{} zg-o6=8E*zx5ijv#5g&l983dfo`h9$b7^;)(Rme{uu;svK7kCaHO&Q5fvR+muo3>bS zyT)cD2#wZ4+i~1tp^R1?VZvymj?z&CGDh@G3VD=hHPM9Dq}OXLgq5aooWhJ2ilVG` zJ8sb6Iz58QZlIz5nA9)hTXGYIrW4&SFDC8}@XP5IJ7;_n-c_D{bp3;Ob~I|yMbpcVoE6e*yKA)3oA<{i ztoe5Lsomi?x*4%0yxICuUV-U0m9kx#JC(mXXt*48@!#B_KPlK8btt_0Xo=c(y~O6q z%8IM)WR<0Pvq}duXz#uBA;X2_?tQ&U$s3^B*rfF}9uR+X%B>h1+vC%Gcm3X3ic_6{ zURS=WjJ-7b;RW7dYFOc3yaU;J;{Jju`(k=hp&uXp&Ere@qWXz{l)Hv{xyIW8*!5}F;cHD>+j8gc{_Hc7YzOmt})<1jmucYn#d|lw!)ZuWla^217Py2MP^QfKAef1Yld-X`z$BBb2 zj=IO>@$-*P|E#z%YgbhL)v%u7*=M^u?)E0kZ{14_^{-q?K1N^mM4X!!y?)s|MP916 z*BF2G*V$zcZ`?`mI$wh>eXIXavwo_=)nsbsI%5)^eD>Gz@1^`CMSI)U%er#|C$n>- zx<*tp_NJbBnp4$ST9{as_zkv{`r_WHtsfjSRvidieegis$RADZ%MZWb`qNGNa@Z?( zzE0ls;hi&!+v;z_z}PZ+P|Ct@{0Elm)tu g?K#bn-NiExL+{1L_iS@}R)_w&4qF<%m&)7tAA>I`_5c6? literal 0 HcmV?d00001 diff --git a/Upload/images/icons/photo.png b/Upload/images/icons/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..b41267fa98cec71d6911324936aba7310e4251e6 GIT binary patch literal 555 zcmV+`0@VG9P)4z$r7}P7__hx1TAbVL=^l7`XfS$v|?)|*jlK6z*b8eyO2syY}{;&*<;Rk8H)po zoo=R^f%oAZ=AA%9I87-|S;76CojbsALH!r)oEyE`-F>!*`rh{TW9_UBya?By2B-kS z4(JXv7DS-zLYaV8FjV z5zHHKB3Nscw#FzY!Z3Tsg~2-gY={V4T!q!51=S5q&a_TWYzuWFSYuj%^`5sMp7TCQ zxqam>H#Tpg6-2tVT^m?R!MJvohG4yK0mc|*McCWlqgVBKdGvzAqtA?2))*{}Ia~JW zMhOIID~{ULetN+eqqJ!n<-F(QaKyJCn&WB2>)A)T$v#<{k!Lx1o>SxnRZ%it8M3}I z;@bHb(=>k^Oa`}zqKG(-Nz;^~$f>G=e!ryOFQ}@FvP{Ub5EUz|)W02cy!U_IS46PZ zQP&Mh)mW=IJ{ArR97&Q8$1#^TJ*H_odN!R#oiOChlZXEp9}m=Y!id>)8U@+L#v_%c tYl|e&&*z^4AOd=T{!hIHX2EIS`4g;;OERsqE_Al9s7PjFA=I6=f}p?x+X{*Z3M>5TI9#non6+37s(rLj zBq2jVce>kndY{wgSyFV-3%~K~dH(<3#i0Oz`X9I-VaW(3EFGhSGKMgbE0jC*gh9f1 zoI!4fH_Tv`bp9l$&#H8e>^292rb~;RSFL;nJF^esd-D4)48yGAgamsQS;>ifP$=-wGnpLh>z-|5Riz?=5mTqINR zWE4BRp!kttm(CYzJ@Xkfogbm$xDT$}{=hNrp63L%p&9Ph+#Q7Nho(c=SrrJR5A3aH z!z*>iypW(){~C7CF6h4C29L)BJ=RH(>>C29`Y}|{&sVU+3kvQ{(7oa4UZV$UI;NrQ zpcABxW1#JFg4gSVyAP+JuwfVq)uSBb9>oqX$iL%g=?TPkw!MOq11>0TdJ0=L6A%i8 zIEpk5ZkIsT;*Md57l?1&tTnug$musAJIqtGf0844hZHxxj9`ZsY`$SGsB?xZj|QN; z-OnMX-@?+;5(mzSJt9&vU$DaqHeJtKx5dU(>Vj;Qc^;}vUqR9KX;pwT?vS!0el}ff zW3a;uL<5u{_o_NWVxOw$m}RR^ErW_sruA~D;{O%xGwk|&`xIuevns%sk}jcAGIWjU z+15$1l9{d0&9OC|KVk^ZxWgM}FpDo)kV?oQY$IQE50%<{o=Q7;pGvd5_yw79hc}8U rCFEi!Ss)-}5;hV<{~#xx6=3%#j}j7bLZ8#f00000NkvXXu0mjffGtU! literal 0 HcmV?d00001 diff --git a/Upload/images/icons/rainbow.png b/Upload/images/icons/rainbow.png new file mode 100644 index 0000000000000000000000000000000000000000..3363236ebd58fec5cde99dba12870fb7191ca88e GIT binary patch literal 666 zcmV;L0%iS)P)=wMvK$m;~C;=AF#r zdM4CGi?)gbXR?@k9^d0eky7G+9z|v{|8m|SG{SWqqEIl^zaV*t$vrqw(MAFt9Ea(C zJW61KI6rcp#xAa)iE|K$KylL_B`{B1LKp+wBKacv9ZhKK2&ror_mtpOo*yD`omj+K zMqR>AXIufw+qc==1F0ONFmDG!ve%u)H-ZH)~xShK;{I-PZr#o}5CacP;^DYPebG!Bk2O?X1EYs=gxM=66#;^mxu9901EToB(8P8aJD#*SxW zNRk}l+1GC?#oE*NtD{S#W;ZtQCY8Fz_0+gwl1m~vXSQ_K(SJA&8)mcS0AmM9eE8(u zYCXSM9JxNmGpPAiD^fAdGfGejrv`jjqnp=gg9ia9l|2aJ)-+-^RGbu1V!n~m?ft9j{pDw07*qoM6N<$f(SM- AwEzGB literal 0 HcmV?d00001 diff --git a/Upload/images/icons/sad.png b/Upload/images/icons/sad.png new file mode 100644 index 0000000000000000000000000000000000000000..2b54f596f85eec646041f54587eb6ca1eac99ad0 GIT binary patch literal 711 zcmV;&0yzDNP)pk^M99k5%heB8nPtH3s^tqcE5UC41hz?>E3dYJRQ z*2FG8?%=>L7i8{H#dJ4mKPEgmp1H>JNgpR4)N|(5X)ev(RTDdW+`)lIP8Cdcl56() z_Q}#mAAjh#bKGCU>8DQq_SVOx=^JWdhmSir@W`oxl%E3M$J}~x{5b1FPA(J-uJs03 zkDugX>YSR`;o}YtJaVdF{5FM*cc;ukqKOwG^$PR`lDrUY;zIJ6n%Lp1yKvx$0%JS9jsSBc}=;o~MdnD{1fV*W`?W!)(TzdFs(YUK~EdX7Zw%*x}<2 z4m@(Ipvyzl*+RDNvunbsuG*Y2;$icRm(8)uqAS*v9X{^hz$2#$@U~SEwb{w$Zzk>8 z)#`Mn&!Ov)7W4OLYY7uOeB8l-$NO8bS_Esy#!9Ml@1#o|Cn$KwO<@TnFtNjz`)=X3 th$>eWtP-skZ4zz%kE%r*L~9X5!5_kbS3MF2u`2)o002ovPDHLkV1jD!RwDoa literal 0 HcmV?d00001 diff --git a/Upload/images/icons/shield.png b/Upload/images/icons/shield.png new file mode 100644 index 0000000000000000000000000000000000000000..a86debbf8c8f3d65638d7d0fbfba563d347ec8c3 GIT binary patch literal 704 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 ZeD=wGa~|2vRpaVE*O8P;9wV|g{|AxaJp%v$ literal 0 HcmV?d00001 diff --git a/Upload/images/icons/star.png b/Upload/images/icons/star.png new file mode 100644 index 0000000000000000000000000000000000000000..ae61d166611aa291872d056d9f1b38fd213d7ae9 GIT binary patch literal 680 zcmV;Z0$2TsP)Gk!%;;B-vF#c2incnY)PSK3mWiC{i#hVy;~FL6f#H*s6iiY}OVvbzA6mwn@{J zj;p!a8JjrRg}lAbIy-E+=!GBWIsfev~JSqhPUfUWvM5IjBB?CBDmg{sJV*o~n zm>loTB^TTlDavo^Sg9ush}*(|=as|`Zmjk-f^$Acr?6A>f_$?4!EI$u^1;pkA3Pnv zIiLUSuL;IX47i3F`0$+RU-@-6x$;w=#2GWZ`|kqeor&2wVcYJ=3VM=F=*Wak?!c^+ z3w9$jQi`zqXgI}pk<_>IB=qrc_+K8_hh%a}zvoSpFCEusGQvHw9P1^^KYEBTcQ!{l zdWEDHFVU=|hrcAS~sC!(45jpE|{-7B7>fh?*>f+R4mRE8)C{=(CMX zJ6rg-rb;`yVh8dI^5EAzn)SCQg8pX0P4AZocn&1+PIRP>G*|~%7}hcH^cLI+PBsf) zLrPMJ-@RABJ9N;M7T|e&L!#WMWu39ezSUTyfh^57(O*%J*p~+KeP++9QOh{d$@|i& zuLXF}n?w0>a6OltZzR#+?yS{N%~=gqT$HQH3UhVj#r-M{9dxl%bXpGr40OX8mt_Gzg7d!jLqR0v5UH@p7jZ(GLKInvL^WEQBgY7) zZp+PY`}Td`y`6hEb%F`Bt>VS~9s3j;#8=`f>Xh zVnJTpE^rLTwbofrxb@71l8so5)szr+5R2@k)s6c_Ndiexpt3O#UVJei@d9>Bmb=3W zUF}x~P8T^U?51JB#`-#F=``>p23h8w&26p&RR*EOtTAVR`6r?()CTU|n(MsO-&S3B zxO^j-ghV_Jip8=6GBRM$32^b`Vv7J}R-xy3@12u2XN8R|nz{}ISpcerIsh?EJ}06G zBo{YKPmL%OCWP~m61fU1KdZ7Qzt@-pO`!H$q)fXS&(lOuDc zp8kM|BZ>rnL?OFRPU-ZuXLQiEnTX9KLoBo%?d(3HX&N}oO41)EpMN$osh3toa7)6D zJ|GhcZj*o;8!=@MN=o7I*(-ewf`}sHGa4Iy=+(5;sJ%dN!!E|Jf{CSbNuZ~psd=BQ z6j+Rmrj3t0T147IxIW~^NBlOxuN>+t0J`e4ROFi;3N=mvt~K*{Yh7bYB^!7b-Y*d& zJrj(>(DV{OFh;k!{#pfiy81(qJ6L&K? zhdur%bxj4tap~2Q3=2#Jgb9zIu&cF0_GhX&&*CJ%0GqHcODB9}dcp_OxfspGbcB)T bcToBd?Kfd777?${00000NkvXXu0mjflP_ab literal 0 HcmV?d00001 diff --git a/Upload/images/icons/thumbsup.png b/Upload/images/icons/thumbsup.png new file mode 100644 index 0000000000000000000000000000000000000000..0ceb293001e2c0d89849233da73583445ba275cb GIT binary patch literal 745 zcmVi=g< zTc&BKloC>Lt5mR(SV%}jB1f>aks6Cnr-RUx%$ zsL_s&IhW6((^2B`CU0``ec$_jZ_YW2-*9@3&w`wqSZZ-Xn-x6kXHZtw8m$Kjp}N8>WV03g`D&_e;90;RxLP&AeP_GvAvmxxtS zDqX9L!FOfzFfo=g;P2S)C&T8(Je2zCQO zK}$#Hwew+J!|Z99+FUxGs7i#BYr|NgDuw68JkRr-G0b1wTJ!elgC}PmNmu{R2SEY; z!a5o=37TU*O*1l7=R&f{fNI|(qaaWa3XFEY<8oIY4}n48vxry)ct8rM0%H6h8u$i` biirCGT`n_TgLUoQ00000NkvXXu0mjf?`mHz literal 0 HcmV?d00001 diff --git a/Upload/images/icons/tongue.png b/Upload/images/icons/tongue.png new file mode 100644 index 0000000000000000000000000000000000000000..9bd9d899ae3f99f44a1c2f262e88cef6c0d81447 GIT binary patch literal 723 zcmV;^0xbQBP)I?#h6iaH4c@u-6&rj$7eKRoD1h@!sDshiT05M!hR zwHkBfhJN%%-?yKq_kOpD2SG2~JnwVg*K^YsH&LXADAr5#RiT3UKC%kAgjAtmZeq70 z2L~Q^%$)t?3QR)Ef_L|n{^_=sPIMdm{YeHBJACBe{#9U#Dr-EyLKotka52vd#k-jk zJ=uv}_{hP5Un-b>Kn1g1r2L$4#ODU<_)Y6psi^-lXJYr|%zMbefybRJ2zQV*+P^KF znYqYwYBfh**KkC&am?r7%<)~)j!l3sbCc^dJjm@=^Eq3fhtao9hVb3e3=UlJnm#cu#JML z3410PsN}3HoE(7;E|Vqe=NRy~lLh`3Qh$$D8^+*1{`jbjjiLQQm23=~g)G^LUHCE= z9C+Nx0`(@jzP+f>bkAOXdSe|cSBv;%%O>`p-La%scQ$k1wPKMMF*xwJlLgP3$?9({ z3F`x9*1Zk}~;lXI%Fk6|kL+w+%dV z{V-3O&2nOgj~pC$+{uDY2T?~onYtQQc|x7#aec(W#ycl3_|EX>{*!WIhmRZ_c-+YX zys{FaW(%3x?W8=vQaUx=dq~r~^~Rsk#tbHQ_{hP5$IBP26oR#VeIZrYcG0D_8gk#W zkw+W^F|orJ`5wV-5h`3>utI39&<3H6|52$>vC!&#!C$x^P8SmP?w|kw002ovPDHLk FV1hDPQJMe% literal 0 HcmV?d00001 diff --git a/Upload/images/icons/user.png b/Upload/images/icons/user.png new file mode 100644 index 0000000000000000000000000000000000000000..4630b25b5c152152ff5a762bbc8c4505cfa15203 GIT binary patch literal 628 zcmV-)0*n2LP)9*Bn=PVH`=G%Kv5WO_krmBSLySts%!2mbteLcG;c^;bxkySvoCw9b zsf!kw3@c(6TN;a}^FP^gYX}|q9UlH)Y&GW$R7y;LDPPaIE(t85L;K@bE_J~2(sEqe zYiefBx?I_lx}M!uT|EP>RF$`24}CT*F#E70J3n@b0B&fdvP>KpV&dR1Gw<(V#~iiHx03^Fv~_FZ<47j~ z+|b}5gDg7e<_E;#Q6`*YOz6)f<7>Ki@Rvj9Z3J*bQywzNt}w7g;^}eQ=aP{&0=S_m zZ-s#>;e6tjc#Y`=x-#&TzK(kpmj`0xk1r5Bl|i;}AX;y7$AS&MSChRj(kkp3Oj0-; zR^ax>zmxBInrywVCrw9VL3Dl(G~WZ)PTzl@=@|Y*7axC71E=o3qg*bhXub1R4Rnuw zCS=YGCNt=ui&rjo8_~8%lG>xQ`GFI+-cTx)`U#HrC-MWxoO|$r&_Ndin?>!RcG2LC z347lo&0$3Np5Sf1FBGs?EJpy}8@egA5Ikg5R(8$uyZXsJJX+w~>6H=grLn{@fu_iSbd5g~(GBgvt zVUm^qX8kLZ85IDPTCLU*9E8GxP*+EHRV?6;W%(nSMV~Z)C)Xzo;LcL|aAkUMrn+#Y zyPytp9elvakbMVz2#GU78{7MBY!No&E!bi$7~M4*kmo)h5R1iPiOjM$--SKdhLCJw zE8fILxB>HC9Zw7r9%^GWP-d>k2Rw|*PPhfLM}g5UL$fMcQJ#0ps z*xmmOe@4OTZWYG&r!-KV`+OiMNm7~2Pa2J8L|Ix|8md&P?!Qonxj{Ym&m28y?HzgpW$yEVNH&|L)rOEB!xH<3)xhO{=>0<)XfQXz2jYyTkop0W ze}vb;5zNu68K%&87|8NVcb^8DbDs|+)9Ez*o{lwe1-(ow5O1$ip22*soHNUUo*GF2Sh@ZFkKMpihSS>;U3}sf>8G^-TezPDdVpY Stm*>*00009EvD2$9g2rs$_Dv0Pp20>vXrlhEdL&!`DqRuuyHb+xLj6n{~ z*qD~HJoM=~&hz$v{xk6+=)l9f_kDiPGtQxC8&RyCXttB+lbh1!y2vWz5>kXhD-*jF zJ~;5mF>~t2N`Xnp{ndMDLi>1EU7l~%`CGSvi5++N;Qm!$in}*?eugh5c;3Z4CzNPq zo^MZ0?BWg|9Qf6OsV9^+-9qjkB&$rFL;m1 zf?C%IFZhZ%IdY08yUeSvC4IqxM@|-m92829R~Soy0#3=oOG8l68d*~J6$U(VvcP|j zlwZLzUGG22dVe141NlM)tPd6nS>*if%V&>cSIQS0c;sY(a*JG_U*@Ws=Ll;)0rZK` zK#2$*7b=xA@gkpt4O!9$2Oc?D&{IcNe|<(o^A)n@wQ!{4Fh{$^zXvOMaj23LuTHZ6 z;a-kC&67Sj@W{!6jti95RzvRh&HEBs-wD-;E|IB zO?INjYBIH)-QWo~tdCw5x|W(^#~nU6@W{ymJbN;T>MUe(R*?Jo^~{N> z&JtDiR_lww8UqtM?(o5Z$Md&fy%0{>Thl4mc7QHB%Bk&0Cj|D#NyEkYX+M8O}V!BYfJyxyn)0000 + + + + +  + + \ No newline at end of file diff --git a/Upload/images/invalid.png b/Upload/images/invalid.png new file mode 100644 index 0000000000000000000000000000000000000000..2d44b047e91390ea93d82032d62b3c4f1a1a6174 GIT binary patch literal 404 zcmV;F0c-w=P)$*y*8Vk1qFu`hXfy;4sOb2ytP`;t~}N2{&ruj`kUOKfWY<%_9(nG z8n`SLaaXC}x>UkJE{D^69%6FjMhhs|E`=S6<3a&PnT*eIHVfUvgmRs%xk1fJP& zb>07^7Z(3tdVcZ$#pf6PUwm%i|AlAg|DSbg#{bF3CjMW3ap`}My1+Sp9vBArP4GIi z>e7n;3(n5_KmW{Jpr+~nCmikl-?Fdqf6>%nfP(L9|1aZ4Ak=V3Tik283<%t;mZ;^K{dh gKpZoK^8z6Z0BDiU=;|=sCIA2c07*qoM6N<$f&rnQ82|tP literal 0 HcmV?d00001 diff --git a/Upload/images/logo.png b/Upload/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c1193d6c2151528b3a8ef07f255cc207f805bce5 GIT binary patch literal 10286 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 Ar2qf` literal 0 HcmV?d00001 diff --git a/Upload/images/logo_white.png b/Upload/images/logo_white.png new file mode 100644 index 0000000000000000000000000000000000000000..e4cfe49438c83d77ef2206c82260d5dfb46c342e GIT binary patch literal 8603 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 literal 0 HcmV?d00001 diff --git a/Upload/images/mini_status_sprite.png b/Upload/images/mini_status_sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..ecd83ccd50dcc42cc72eab090255bded110f96a1 GIT binary patch literal 557 zcmeAS@N?(olHy`uVBq!ia0vp^AhrevGm!kyF?$n`dKKUk;tHh8%gfu_+yDRnzjEcu z*|TSxo11rbcGlI^6&4l-2M62O*koj6L`6l}+1csn=mf8N=s0>r?UA&iozE z6q^r9B=$8lH00&w#m2^Zcz7gic&t#rD|Pc@rM9C$uDiRtgM)**x;jv$+T*|W#_njAz} zFC1)YjeE18q3cF zB*3EAxq@@u>pl~gK9Q8hCk)&6T@wE5r*-|zQlZq#OH0J8 q${|1Pk&4*vimb?JojHd&8_a7?iOuqR&G8@Teg;ohKbLh*2~7Zns|&^e literal 0 HcmV?d00001 diff --git a/Upload/images/modcp_sprite.png b/Upload/images/modcp_sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..da5af0154b68a50ce6190250bca62b22b4f0f5b9 GIT binary patch literal 5209 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 literal 0 HcmV?d00001 diff --git a/Upload/images/nav_bit.png b/Upload/images/nav_bit.png new file mode 100644 index 0000000000000000000000000000000000000000..c4e781d6bbe1aa4740190992e9a3d3785f996d6f GIT binary patch literal 111 zcmeAS@N?(olHy`uVBq!ia0vp^{2U z7w(s5ZmGr=W1=T{Gjr$6^Uj&Mhpj&1;2e-i5=qP@=8mH@E-(fMKn4t(w0tP!K5HS; zRb?=o3`G~_0p`>`XQqs1@eQpnlPZ5Q7$RMhJ;N7{PNgsUBeMz1F(k$%M2 zRdboMR=X;UR!BPnVswQ8DmSHSzANF$R5Ez-eA0Go)qxEGGbXtsmlbeH=`_Bry{hG& zzqC8eHR4~hm52O(B$`?bPh3hm3_gMh+ItMw;D97qrRQ*3wJ$H0tDl}dk(6_{=TFb2 zmpr_!sNCKIS$|lFl4zK+y20WTkKgiDp4Y>AY-SO;?E#VK!9A0G@n33mIo3-Y(eX5L z&9KEy)8t2nM=?8h2kR9NcDmw}-v8WJid@KU7=yeSG!w{@%U^))G{^K~4xQh=( z3H8o_3P{^Jko|5UHhmKw-v|UFSlKiTX4*Ck(}d;=VLW~d@3T+oREt3BAtwHYm@`aH z-+-zG(WSi#RVG+jxEN&6p~a42px#xGxO@*julKj^+HJQ{s8pcQs3{6{ko>a(E-GkH zqFk#X6bQhk?`ErYs6_*QKQ_x{caNm1q5>{=bX{ucItrx{MuI{2rMs4eej##0WFqz| zng+qjwXH2}BcI2Ku`y`m`nT}V)r15iSmuw%m#E}Z_=n(}e`Sv2;D6!=FSG6{vjE>? P00000NkvXXu0mjf$h|-hg0G0c1zps_SaUc^{H4aUS_jd zJ%5LO{kRvJDhEY)v)Ry0CQ}`aM$h*9{fpsncnS4e0XP%-6JD>^RF>r`2z9$%?s3RV zsBixTz^m1YCX>l3>?OW-IvwH9W-}S;>!$#Cxm?m{G%CV{LV>|Uj{SH%j?Mw_VzHp1 zP)LOH`8=!F>*Ux6p>Q~?2*C6CoCX2`5r&ImwOWmw`g{fb1>n6=kH;eprPFCvDwT+m z@AY~K=n()1IK-huBEg_1PLHy8{T zjYi}7Znt~wcDtEIqaiw-4k-a%#bS^Cf^jeyq+r@URw|V*E|-g`R4SrYtC12QdUb`~ f-QAs?#Q)N73kv;1q+?Xx00000NkvXXu0mjfk$?x8 literal 0 HcmV?d00001 diff --git a/Upload/images/pollbar.png b/Upload/images/pollbar.png new file mode 100644 index 0000000000000000000000000000000000000000..d89302d27b2b127833e1e5cf32d7dc4770a1b577 GIT binary patch literal 2433 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1g!2~2fM>D50FtDg(Iy(n=Iy)-_6y>L7=A<$( zSO~U;-p{`sB4XE>AGAcwULnH0z3b@u(BSBu(o$=Wv3X8j`qoQq>B}2hDo?D;J6B4x z-+sAmm49`kIolsbhnvj&9yW@+Y)REOza7}(8QiY5%G0Cz#Swl*wYRLH4|kU(sRtj4 z`TFa$<$cTN*3aW^yV%BOZk;6=+A(eQy1D07rcPciHf5e~*QL!@yqT}8e(9$>@$^|C zy@R6P&%J&q+r@GE?ZkKg{Jtsguj;;Yu~W(aK%S^h1$z%y5}w|R@~XaD^pb35Ce z&oUn_o3SvhW}03*N2ucBadlfiMSIS^3tF#5*K+J(v)OYaO@Di0JhQ}!$qz&Gq<1N$ zP29Y8Qex5hhx+}6+YSHo>&-6x@+P)9;`f}TJCk?tciz+f7P7C?{`%H0G9SD*#IN7! znOM*IqyN{X8m0>Qz%MH&)t20Q?j9e%R^%SrJ=W@r1U2+n+v_~4*d?W&pavkJqWwcI_uIcnw^CguK={maij zX<%=#-?Dbk3f8litjvuUiGA`8&(2%7((%^1S&@O1DknV4l&GBYWMRooJ}!e@Q6kZlz`a^V$Rg`Nbs&%cquvQDV#nzr!Nhq6PQ70R-S(Z7{>E8^o2bWXx%>Uz`KmXn*T*Lc-|dRcxSBoRR6W@5RP___ zr&Ipy`LoGJdV|Q$c)7{TpX~kchV$E5p1-ntB}%w9XZdce*8RvLVZyJ)g+|3M$D2ed(u}aR* z)k{ptPfFFR$SnY>W?-jfNYSkzLEl1NlCV?QiN}S zf^&XRs)DJWp`MYF9hZWFf=y9MnpKdC8&o@xXRDM^Qc_^0uU}qXu2*iXmtT~wZ)j<0 zsc&GUZ)BtkRH0j3nOBlnp_^B%3^4>|j!SBBa#3bMNoIbY0?6FNr2NtnTO}osMQ{Ld zXGvxn!lt}psJDO~)CbAv8|oS8!_5Y2wE>A*1*I0}=ahns56#Ogu`{#*D@GSa*ap$% zoS$1zlv-R2)MjT2)q*UBu08@`jh(p>R0Fagx(5HE%v4~2fZPRl6S5e(`bcaRAPYh@ z*yw`-5h+l?F$M|^G;u0$ z@{58C5|dLwfq^cBt{QAhB*GR$1E?N!32KK)N-{j57nBy|fRlMjvVLk#D$v6v#lS!@ zL`{Jy$yUXsNm;4MC9r6KBx!JDI3=d*BMIB+W2&ZFYyvYp-03Jery{WcGcJLut$g!S zGSezu5=&C;j0_BobPWx34NO7|4Xq3ftjvH}0!SA5`dhy85}Sb4q9e0QWwp$^ZZW literal 0 HcmV?d00001 diff --git a/Upload/images/printable.png b/Upload/images/printable.png new file mode 100644 index 0000000000000000000000000000000000000000..59d9cfc71ab961bf780f9f0cdb787f4e1f0a686a GIT binary patch literal 701 zcmV;u0z&;2P0{NE-Ogz zB5@)?7JfiF_38Z|oXkw=J^aqs`+J`EJ#d(HaF7+T1%oDzcmcO8fdCT*2F}3fWeJX- zg#z-syI9-V!ME*giJ43WG{>ntS0MO&r8s}>?_+Ii3tu-k@p)qdpYnMmW@kZz<_$eP zO0Cn$2(!b%cVMwFvnaB*{(i!>b8vv~eAUvDmlG4GR2mF^4r{jAq^xwZTCL2|*~yH( zz3yFJ@MCZ9TnX)jK8GA~rOZje75-r2ILgY(UU)nnTn0JhQiifj5QG~(pD(z{S8_U? z2#3Q61On&q`~3)oLXxw-z7DU~8>B2V8jY%0EH=KfvI4u^j=sJ=h@yzDt}Y0I87(b3 zG&X8bS9b>n!+pt_n@eM8Xn35mthKeZX>xKhoy+B*)9HBF0lnS;ji!kQ@18-YyC*p_ zGYc3Uji)Kgv|6n_o6W8+EiFNRs5i9`ZQ zr4m-_W0*`2FNB=2u`x_dO@Xqkwzk%j$-Kw(bP8_wGmMPH5skh=BoZ&-^(ih_4;B_a zN>G-mR4U)%;xgvvm(kJD@m~}RD9g&r%exf{#V{e0$)fbjK8OQvJ^*jCU!V}GxabNn@qj*le@M@J~|D>>v+hO(yx*J^5*yt?|y j)vBtWdP)%OEaz-&<| zPzscWh#~+y*PF>b&=goLwf6ddI!&E9& zHYYMzb@YFkmq_q=a+0EH;#gK4STNjrplwU@{$KX&=H{Kd+&=S!a5O}uF^rK2)6irP zO-5$6K`a{Q^@~x;xl*it0#^U8Cyu1Y$H(dI$`B9)mTT8)ZtYves+bdFU(DjjbZM&k zwUje+`?Fji=6?=sSP<(jCADD!?>Q0H%OEkOT5z;$Pc| z7lAT>9uQn}utH}~Ux)!Q4SkoO_|fP90l{TAa6-U(7Y9RPKMec}3^*C@pjU`>00000 LNkvXXu0mjf8g*yh literal 0 HcmV?d00001 diff --git a/Upload/images/send.png b/Upload/images/send.png new file mode 100644 index 0000000000000000000000000000000000000000..26dd31e8e4f650122667a1634c86717d0a3bd6d1 GIT binary patch literal 446 zcmV;v0YUzWP)S1e1ww#1aANX@$vEh|Nr~_{m{_R_xJbY zgw<2(Za&Qy1KgC&AEMjeKa&X_WS$u^Yh;E z@zT=L)yTA^rKNOqg<@i2*y!h~s;X^mZR+#$+w1Dg;NR%p${&Woy}iA)wY9Oav8}DG zJUmE3LPabrFWd0&=kM<1?(N{<;MmyMzR}SsmC?(~%g4vZv&Y8W(!ayDqH1btRaIAY z!ZOg|;N9KbOiWDjMNB;BK`Ev#Ww0jG03G`J`t14n=Joa8=jS%4<=f=s)ZgFB+1V|e z*d>t5;n>8jtihKQaC;3y=PD8LpdrXMCth!@EK7rX!ujk*6lfB%-e z%rsz^CRB80Pi5O41UG&tHSc+XYj$ zv=Sn1YUNHOT)t5>q)T%f`gHR$gsMbCy8CWJB1I^$3Ri5|9=6U-7O<9<5*Z|fvDs|i z>sN0k-@Q%8$1p(QJj6$be?9EDM;QDyIJvho;L~N`F$`Tkz%g_g`5wkD0|z+##*xN! z7kuDzAS7MV+}kWcR<>rD>Df_`6}Uq6}-S85(LGvI8~8MQ6>_JSgw#k9iAx-#BfTGDyq=cOr)m5Qey5@`iG-7URe_*LCR0#bj*ll@ zAuCIeMbpESW5Yp0C{J2gS6EQF<=EM9oV`GTI13NaJCBI704%YzSgfin_&hzmJspK7 zB2FBN+K!3T`8e|IL*m@8 z3BNr-*Y9~xh$7%6?2o z^Q^6%guWhs@bBn$hl&1y!R`(Web%{|+BJ8u_F=Hd=WA=%Oxg+iz`opq!D^kaefi#` zowPgmtyX{FTDmcOFttzG2Yz&0xWM9aV`5^WqoYqFE|&#I;U{|59UynN>L&mI002ov JPDHLkV1jsQ!eRgb literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/angel.gif b/Upload/images/smilies/angel.gif new file mode 100644 index 0000000000000000000000000000000000000000..bb2eb521b31ff38f46e77116fdfca8f6556befc4 GIT binary patch literal 7785 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 literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/angry.gif b/Upload/images/smilies/angry.gif new file mode 100644 index 0000000000000000000000000000000000000000..879eca87aec8b52acd8838186518f602b37fb09d GIT binary patch literal 1245 zcmZ?wbhEHb6k!ly_}>_KxBO;$mC40=`DBlTkaYcV(o4R**tWV zed{Fo%TeT?ljwgZ(O+)T|J-H%yUV=uQh)EI{?OO(VUWdlPo;m}D*wGz{`hPE577A% zXz(@A@Ozlm-w@+}p(g)BP5wpN{*Sah7wUE@-tT-|@P#6a3F7gr7={IF%WH zBQfk;Ve+}+j60c$kK=rw#QA=YcKj0O@ior#U%c!8c-Qv{zV9<){wDeUPxkwh7V_=wQzns|rxp9wk)1Ty|yw6Ynl$Y{5KjlMl?!Usc|AlG4OR|2H=KU+p`Cpd%wY>0q zMe(2V!oL+o|0;_gwq`%*s(jE>^LTdq<5^vgX7@ds+x=vA_p|xk4`xnzuz1#kCG#FF zo&WaezK5o^> ze!O|{@9*D#|Nj2}{~t&)i~{1ijW;|zV3Sw%hC|8KYl5upohOAF6Zj@b2d}I6`RVBC zshZ{u7YZZV+xfMk53~p>tMSax4XOFC!dT#Zzf9B!kZtv9wJ`POzDz`UzMzE%_9wlBykU=k&xy(nu}t%mT+TP9#hz`;3Mq0cmf7CcB;$iKjZ z*{VfA@zBoVcZyaqJRZy$6Xaz$R4RTj9J21}Myv_F9l9cqqjJSLI6Mvz@z zhLr^o-s}v#3~UU{!0;AgU|%VrQZRv|iN(Ew!Er*O15&gglnF4fGfJpzP;hKiU~BZS J&`@Bo1_00ugJS>y literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/arrow.png b/Upload/images/smilies/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..1accfc05784a82f237c24e5b4c53c27996e2df21 GIT binary patch literal 659 zcmV;E0&M+>P)mBs*E0UxH~rKt{@yzN*f0LoD*eY2{^CJoLAS}(w!4~%jV;>tg0 zRUx5>5oJjYU|KcBu|1b_5#y~2@V5)UrZ?)!9ZxFFU7p3*YQ<5$INzwoS0VqjCK~xyiMbPJVfeTk#M#Q?@G90&UJ*iX2y`4YrEa`k>S1o6=5Bq1q0j;44Rz9u@#@ z-W!3wOeW(FFG)1>m4%qoAOm8zS1R?fN;AVe*i%xi;9V1+QFlL}u2C1JY3jQEfGjc0 zOa_%@S>>_xpAUxdP}i&?ES~QCV7Et;uKk8uu2e*h>my32-v!7liHagOCW!hOhlHvS zy&r3u-fW?IasnW>RLZ_`T$|^8UF88Fr_OOUQhbA)225%+kF?dIhvahzZ?>U&D;y1z t&Ww(S^Y3}@TDNJqBu5ob+Nnr|_6H%LF?|uPa2o&s002ovPDHLkV1jnu9svLV literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/at.png b/Upload/images/smilies/at.png new file mode 100644 index 0000000000000000000000000000000000000000..194020f780865dac42495fd96317a731743d97b0 GIT binary patch literal 719 zcmV;=0xlw?{lW|W${POCC;iA4{?8))-aq}u6#d#bXJI-1;z9ku3jW?V{@^`wS`_}-F#gsl zW>6G~ZWsOBJpRlc{nRgIND5+FG+{ymPd*VtG!XsQG|#Fb+qx|A$0oXq3Ad0F@xvX7 zYZADaBcO#Jpn(`^RUXK(H)K~S{@pynm=?sJ9$-uym30_W%F@6LeBeQviX&VH#>VFb_<9K&ADV#FEk6 z_8vD=0003_NklEj6a?TKOElIb2v|@-!2nXF*?Wl^dwP5S$H)Q9xIe#H zn7ar03Ep>FtrmM1M3>xjw(U)&TGjhQA^wk7RJ&ZRRH{Vw0q+U1GrqpjpjA)Fm*=qe zIkli^w>nl`%`b%rsMs#j-SRIdF^ts2NepWwq54rQ(q(OA!w*bulE<*jPaFk4K{q3f z*X?E>XAICr0*Q-auDf$8s>E?JZdjnpI-(vyS?wq}#EHQV43;T9f#z~_O;&7KCx#r} zvq0A?=;mq#S#e}ShbLHu-xc3MSxu8CEW=uC9`ukzw=+9E%%K}%n&5JG_&sN%r15$EYV0gFS_w4m@jp{gca0XEd52y!h>UCny8$u!*K_`Ew3 zu9D<>UI+9OO?9^Y{dnIS3aKc%Bos~$27`3?Y=4+SIEG$*&K`Efh)!{zY*H~fBF@%wix@cn7uCx`tX9}fI~(e>X2*T0uN|6lcb zf7I>I6`wo1eEy!W{&&*m|5?X>XB@vDcl>(N^~(v@$2*;$>~guW!TH7}xAQAq9-M6d zbJ+arK8r8=ESyaQz8|(dzuf83nW=9d?ECiN;lJHFzjo>U+h_27m*KxdChxZxz1wW` zaFxl!br!c*THan|d2WIAsYSl0miRw7IrZ!NN58jeeBY%0cZcSOH5$LRYrkEieQUn% ztp$4L=9r$I=W%X%)VY<>4~|cLdw1`4Z&Q*%8Y?5=vSx8~82-mmW--kmJ{V7lDZez~g?6wY)iob6LP+pqTINZ;eby&vu! z{PFSGwH~Q6&5~y(*`AqV_vqlH4-ZcM`1t%xqxhMA%X9rU7iM^0nCbIyYsKRO6P_KJ z`tk0ej}K4(`0(_{r&s^MfMFC2TnH%sWMO1rXkgF*IRTU>7&!hjFmlRRIJ@zPY9*bR zVYuPp0Y#^#B`*>VI<<>9w(t~c6r2*45LJ-S2spsd!euber%;2HgNvP?ML@!!p`n4D zFMwg9kwDL6VQwh{4u>ro&1~F$7L3ds3{&Jq1T+FBELe4QC5OhJ2BrmGlZAxTWC|WW zYPh*ERo%nj;8HIUHE9c%0>Q+**j;6oISE2fyZMDAO*rIyA`03BZTD3?RAf5bdVGSi z{V|26_UU@oaV-kmi#9($m*TwV#zofNNn-Lb5sIg0nTm?bMd)}gKGxGGx@zrgHWzXb4vG_Zjy855)i96a96P_5Xdbe>VmHUg7VjFT;l$Fh3D^8-ruL$f1hIe zeVXm>b^c$+nE&4u`TtPz|0Bs?$60(FQ4DvmBaPw#gnRZ;gyRg{kkf!d_n)uqfEPIaR2`G^ULRtTPJYd+`<#;D!6*d zl*T;KdDB~x{rM7o`A!_!HK9f{z(F9uK`=Ga`pX%fV{_Rr@0Pl_Q+ofdwdv7zS1+Ba zOXK_hL^eN)zpW-UDNyj%^$Yu^vG-L9Ut7m{bUxSK9c!90feK{&>;!ghUN*IqYwHYt zPfPyyds()wUr>@H9ONwc=bFIRlN_Ce0?h>?v#U6l&g(5m_5Ael{lt#qm**t+PGvhb zo9*gq_S$s8m#0NPo)?-mss7nk<`pd**Y`_R7lzNQ;<~+oqb8ZJGLC0?pYY$me**0I zi_(2^qlM0&K6GIBx^t%v)}#x#n+r_tF8g_r_s@CGf47DHT;Te9ndjFDmjD0%GmHY_ zLO}5+3nK%=90nbba!{UN;P}sA$tj~zaJr*ey-y&iY4u$U2z3n8#ziJ zTy1ggo?zH9Nzl)J35(EgiSJMDy42ipm%NcONoMD~PU-lA%a0!ND$!Y)rW@-v-)w@! zqYslk1^_&( BhdTfO literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/blush.gif b/Upload/images/smilies/blush.gif new file mode 100644 index 0000000000000000000000000000000000000000..7de17dee716961c5807255d4d47d85d9869c4879 GIT binary patch literal 1200 zcmeH`>rYb$9EOh!Xa%#iQo?0i3N%m`P|(6!psp8ATcA{`j6q>ZS(r16S#U8~Ls)_q zxk*R4RE1QA$RwaH%rPP;TT4r!&;XWo=@@mVEjnWcv}8ybaDJN~_do3Y_$1GlCwYar z0w$}1f>4lc1i|rraLM+ZW%%lc`|k2>N7>f03|3C>E*HV?#rV_WP3svPE8TUJY%CV} zek=7XeE@ceZ%KmxD&3eXST&q-8>H|A1#2GI^7fvH;b#fhBrD@$uyA1k-7pB;WBk?e z9Q!ce{y?xWn1h)cz`%ehCYZCq#O5U9dBdTV{EN4HZ^tqb_)L8ao-4U)%ca$pz=J` z`@GM8X^FHbBP@;7g{w&mElIog(%d&v9GYW}YpJVWXIR?Vmd=wdeY*!U`@DZxE`?cI zS@W&gi#PHYyTr~P6mFgRxl!YFOnRMjKF>4X=1Umj!?!~GzHmqTF5G6}eJtqD-s$7O zfDqSaZfcmD*O=Q~Z0O_oy4bQ4VW39wR&>AlJ!s*;WiGDdK^-5j<3qgwzQ_RpquZmvS+z}Q^ z4W}3Ckh-8_TG55@D};lDxBN-rskODWgf~T=#^Y7u4svj0Dv>inR|W}Q{1jou0rL?BD?xPhttZ5{-GZ7V) zC_Fm9ruc%s40Q61v#RL)TY^jDBPiNTd1tiTFa2f6ovicAGq;T9Gf5)Zr@b60Ke%7g z!+c-Wy<}4LWU3Nbvqg2LrVvJRWi?|^dNcbo&P>4QElzSxLTh#FrxCYlR&MbS>2q*@Y6F?CFLVxd{lrxlJyV1%G+81 literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/confused.gif b/Upload/images/smilies/confused.gif new file mode 100644 index 0000000000000000000000000000000000000000..55112e849e8fbafb94e2520cc9a41fbe981fe867 GIT binary patch literal 1154 zcmZ?wbhEHb6k!ly_|Cxa@8945kD~rOjQ;l|_V44E?{}lW-irEvC+PRBkpK6?{@n}v zbSe1XgUH`^Bi>&K`Efh)!{zY*H~fBF@%wix@cn7uCx`tX9}fI~(e>X2*T0uN|6lcb zf7I>I6`wo1eEy!W{(s8m-$|SQXC42Yar}PV@#{&~FDG0d?{t2$%jL!f=Np^c&aZTN zaI*dXVUs_H&Ho>>_`1*H%RUQd6M^rCZO<=vdUR&$+Xwr;eR%kPkIui{I=^=5{oil! zZ=b>UU55V-nY`a(^lr1!!&N2^*IC?NX?c5<<+%mcrxy91TH^oUspn!%T*pO(mFNQ9;)BZ*yUW_l220 z54To4J}}|gk*Oc=9{Tw3^p6iue|&oN9}E~q0o_AD@h1x-14A=|4#;Luo?zhk&%n+p zld+hsS5!OW$_B#?4;@t8dse(iIOxPK>ei=Fs3E{TRZ>(zLL=Y+LkpMjiiE<7r5;@D z{44?z1`Q1j?0i8YJBI5)se{5Kwk&VhLTYw7_8r zSA$NFkH?Gxg*F98cD^~ig$Ye9!tt9TIyW^svusXRcCpabaAV< CC6zh= literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/cool.gif b/Upload/images/smilies/cool.gif new file mode 100644 index 0000000000000000000000000000000000000000..b8720a2073cf5f33710d8957a02c7fbad37258f8 GIT binary patch literal 722 zcmV;@0xkVVNk%w1VH5xq0OkMy{{H>{;#&OSTmIx-{o`Es-COnATKn2m|KC>r-d6I` zQ~uyt``uXY&{X)_S@6?W|JY9N%T46NPvgT;|ItPM&_(^zN&nSK@5M&^)J)vEO#R3^ z|H?f6$vpqfLH^7^_s2o?$wl;KAk2v%&5kC`k0#{Aj^o3P@ZQ1r@#fZy8q9+k%#uCKls@9YlJMZk`0?k=ffvk= zInIwf(3nfmnM~oec;mp3=ERlp-NNzV%lPo+`10!i|Nj6000000A^8LW004aeEC2ui z02BZe000O7fPI34F)%MCCND5CgN=hjLO~@O6B8OGK|({0f>Tc}5)TFi1qKfiE>BaA zQa~gP4gv%N0|WvN4J1HPgI-P}3M|4b0mT6e3<@JoUVQ*iKM^bm2?*BL)CUniPykd- z!{OrLT2xU?7#ZUb;}}d)T|Ocf;urSfAw6AOJRlVm!zc(8IIIE)9$dEUXz{^=!-o(Z zerT~{iy0*=I&j#?vE#-KDwdozJ)HXRxicq@nlE3}#F=x4PvAj&^5C&!2Tz_ooB{y= EJJ=I%g8%>k literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/cry.png b/Upload/images/smilies/cry.png new file mode 100644 index 0000000000000000000000000000000000000000..a33974e677e75c268e3de4b483e941d9c2f27b7a GIT binary patch literal 610 zcmV-o0-gPdP)M{n9D^%^v>QFZ%lW{?a45iwT|7|6f@(s(lFJ%0I=iJ=LHHmva&0 ztqN&X9>ba!zos{^ojmW=La3ECXId;`Rx9$i2xm(U^UpEmwHsqj8kvJF)~q34OdMQI zDA~b4j)OggUIfXnG4aPD!k{RCwNg$1000zpQchC7d4DoT+Tk%1Cv_h zOt7=TSfo}_{m`V8D2kFjj7eS#;NiUs_E1HND~;mBW7 z_cc;Mf9Lv!i34?ps!^&92qyD`p?>gLs#$|hr#F)AzAc-og0s=GKfF%!3)sl0D3nKH|ZW@Zib#@#oBe7tD`2&W}9Mm`l)^ zOyRY7g!tvqD`0(ZU^6LNp{{R30000000000000000A^8LW004RbEC2ui z02BZe000O7fO>+1FfT4ACoV5AgN=hgKRzZK6cigKK0iQ?f>2B?6AlFg1O*NgElg03 zPdz0J4FdqP00RvSB|T4rTT3Jf3ktIV0kaAV2_#EfdIC*65(fwf0K~)q(+3hfO#)F$ zA`lS<55vU(4-XL#BUe#QNf{dH>9pwd8W~AWT00>Z7y=3$81MoJ9a^&F_+X)e!-o(Z zTKJG73lbu#*7*( zG-}keH)}-=8dlPn5wHe~5g9Xv(poV?h7mAp1n6la=L?Y{F+6gNQH01BIc)~9dE=#u zkRU@i;tmNSq>7g}Y#iN*gQm+ADO9LPnbHMKoI9NKw{%^5CS&bWa?Cr{!*c0V?KcSRI}P+X2=zG#_dO2#J`epr5AZ${%uX!MPb|()JIqov%u_YmMdWEc8(@^-(eR zRyzGuGyYXH|5Y^pSv~(*JuXk7hbP5)y~{AN`DXjb@XTK;TZ|7~95ZD-_cWbbch z@@{1NZ)EUuZT@j)|8ZvfbZYo@ZvJ&_|8{NlcX9W4bNqL4{djWzd2``~Yv77`;Ea6Z zn}_3?isGA&;+>1+n~Ub3i{P1*;G>%0q@LoXpY6rI@yNXJ$iMB##qiF>@zBTh<>K|` zZfa*|YHo9bjeG%oa%nj@JWWkJ zI5}x@kBtEVJ2g&HSz20IQcg8Hpr4>mR$E+MU0hpMPoR*3aXJA|RaaQV#aC5O0XlJf zdT296Q2+o`)z#BeQAIOodUQ8EN&tI%08HoO@y@dAd+ zmoQzrV4*=wn*t+JsMyJ~=gt%)479O>p~DFj_LAB|aiYToJ9)?u@DM_TQhOpocpyL~ z51%_W5={62;wp#_6B5|CGw2Nk1UwBOM36vNLIem65KwsI2+oE93m79i-VAld`XE(j+TW-hMt{&K`Efh)!{zY*H~fBF@%wix@cn7uCx`tX9}fI~(e>X2*T0uN|6lcb zf7I>I6`wo1eEy!W{(s8m-$|SQXC42Yar}PV@#{&~FDG0d?{t2$%jL!f=Np^c&aZTN zaI*dXVUs_H&Ho>>_`1*H%RUQd6M^rCZO<=vdUR&$+Xwr;eR%kPkIui{I=^=5{oil! zZ=b>UU55V-nY`a(^lr1!!&N2^*IC?NX?c5<<+%mcrxy91TH^oUspn!%T*pO(mFNQ9;)BZ*yUW_l220 z54To4J}}|gk*Oc=9{Tw3^p6iue|&oN9}E~q0o_AD@h1x-14A=|4#;Luo?zhk&%n+p zld+hsS5!OW$_B#?4;@t8dse(iIOxPK>ei=Fs3E{TRZ>(zLL=Y+LkpMjiiE<7r5;@D z{44?z1`Q1j?0i8YJBI5)se{n6O~g)s-9?0xOvm zxZL965D-a5>!k#lRw&x?mz z-`?JlyZyt$WxdjtaTQ+@48`@j6HU(2Qwu;3REIcZfdSK#l pc^O_I4*7~3AK4^R_9U{))v#Q8;Lz~n;&Hj^FAv!jWLQ}ktO0x@lu7^q literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/exclamation.png b/Upload/images/smilies/exclamation.png new file mode 100644 index 0000000000000000000000000000000000000000..4b885b0eda7d80b8a5a8dec25bb270a028c978b7 GIT binary patch literal 619 zcmV-x0+juUP)~r%*D(IzKK>VBe000tnQchCt&%yZ`_J6-h)vR2b7u(C2o7KoAAsjmBQX(nJU%h!`M%6nl#$y}bX^ zWLTEO`|~?9_v{YJQYt<|>|zQ1=l0{WJ@m%owVyb(9B=fkAgG|C=pLOrim!o0)phYK z>5z3jkW4{U_X8hhF>`XNpyAFSI#mXuh#7|U+A#WV7^L7&`R^Jk>}W@ znkWp?g8Lp(O!WMN^bKhLN_l=}AzhP9jjEjK6X-_Lgj63CU&cc^8@}Z_5~-fssIel- zag+HoJR#M%h0405_4_@JTPSmR2nw}zgbJ%n*NYcSG;YF=>-sXQ9g$krvnmKuiUkskt5xc2_;vTl45h@7H$^pB(9Xe7N_+y@NkKK07nX z_R+yfA0C|i@$vb?trgFXO#OKG(8q_Te|&iQ84tJf}biJ90kIa;ZRh)O=@ zeEN)2R7Bm$(a!R*q@0|zr0}=z!b*ykcCN-BzdX6f>^On-Air9Qh@z14J)8C~5gT4O z6w0tGIX~cRnX$0tIFGbhfkY9@6N^eY3$`W489jv>)C0NhY?$aQq$*``>W*iArx2r$ z$-60%M$E#Dp>rB|EKF4P^7yftMp~7`T~zB^67clrlweV<=s>ZrRvBI*8vgSfI*nR` H6&S1m*5Cy5 literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/ff.gif b/Upload/images/smilies/ff.gif new file mode 100644 index 0000000000000000000000000000000000000000..46ce40304bbacb7c70217e24d2029f512c348cd3 GIT binary patch literal 859 zcmV-h1El;%Nk%w1VI2Sz0Oo%HLq~JmvTXSB=$+{I&M6DGuC4#xRL!PI|Eop$js^bW zTlc97{-ZtrghS`XOohVH{<0f zaH>iqL^Kfk+*tP9TjI)>)ISIbhPBO!A^x~M4h}a0&g4LG|z9 z|JhIg0088}Q18xC-<2Kz$vo}gzW1^xw?#qd#y*_ZrLC8tfB$zx^|&!kvf7ug zm+-(c?cKfZZ5GKuHsyO0`gsw5O+~%-`QPB-+{2{v!bbo9|NsC0A^8LW004ggEC2ui z0384n000O7fPaF6goRI5LmeGMR!@bGkbh4@2L}>TQWBLzj**ZTN(WLiLZw18QU^*G zo`n|&JySsnw6#G~JqN6h69q9SF&rR0GqbhFK{Gu{oq~RQUPTmIXFMJl4h9B5K-%2e zw=zS1&IK#dT6%gsX%$~xKz@GO@<32f8%Q+*e||4LTs*i@vSq-4HF7G%lXp*^A0Qhx z^f^ICfRY)skld+b=0O|^ZL*xG7jYqzlYO`-x?$kn1{HWrP_STu!yFqK9xhoDF9U*~ zN4UHQaAQddqbe}`vfzSD2o?x3q?nq*r;`Rw7?gQ21P2TlCE$F>6J`Yf7a$glVQ{2G zl`18;jxcEOrU3~x8vF!M0U?J7B1C?$agk>Pi>yb$mVhDmsuL1MXb9r-;X{)qEq(wH zlb`|`1|vdz{Td<)0}>=u*x)C~1d${=F1OgRz(|A61nl?#bHRp)3Rjvx&vB)K2phXv3A#{22bBsD;zy`JMMsVF l>IDhVU_*xpDpZJ|gAE$6mR}(P(4fH!FK9r6frA7B06Q3;m7)Lu literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/happy.gif b/Upload/images/smilies/happy.gif new file mode 100644 index 0000000000000000000000000000000000000000..70a9456c692879d0c3b48cf9f41b713c3a5ca291 GIT binary patch literal 734 zcmV<40wMiJNk%w1VH5xq0OkMy{{H>{;#&OSTmIx-{o`Es-COnATL0Wq``T3h-&X$K zR`SwQ{@_{r-B|C?RQTIj@Y7fS*iQJ=PX5|a@5@c(!%ySGQUB3J{?JAJ(@Fo;O7F!+ z{M1a`x=j7ZJO0T$|II=E%t80ZLG{T+^vFfyxkKc-MA)!H*s?~?sYKw(hy24g^}aat zzBofP5ck79&!;KAk2v%&5kC`k0#{Aj^o3P@ZQ1r@#fZy8q9+k%#uCKls@9YlJMZk`0?k=ffvk= zInIwf(3nfmnM~oec;mp3=ERlp-NNzV%lPo+`10!i000000RR90A^8LW004ggEC2ui z02BZe000O7fPaF6GcqwMDlsxMgN=hjLP04V78V^TK|({0f>Td06%Ymm1qKimFi%sC zQa~sU4*~=O0|WvO4k$oUgI-Q23k?hb#KjB^3nxxqe*jQF6bK3m3Dwrq2oyh108~vS z5)%i0eh22`qYRof zZL-|JVKXN=7dUQYVUq@cn=wgh*eKek&rusSl8kW!;18TSVvZo8!O{f{BuB*5fivih zoG@5BiV!hE*9eg!Si;D8<46ykHDIh%xpJk76)9Yf QlLwC-J9zT!;S>k}JHPmN-2eap literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/heart.gif b/Upload/images/smilies/heart.gif new file mode 100644 index 0000000000000000000000000000000000000000..8f58db34af58771d56c42c7c8f9dd0e4191add23 GIT binary patch literal 1166 zcmZ?wbhEHb6lD-)`2K+5o5|!)3Ju>3Cww!S_{(?MXQigkDlK2s+rMaaP3|uHW<2Sa z=VEtbq3_l+e>lwj>AvW@<&0Cu_Ixv)@;hL~58GMazJB>6Q}fel-k-=d-^`|bH=p|5 zZ0b*!1z)tgx2&80Nv`gv)BJy_>pm+s{`On`+i%(5q;BBPuGQBW@4Y@>*q{qJiLGNSA+hqy1nO5ANnL)`&qg9t3Ht1^TU45@4yxR zvetdKoIb6$@}pGMSN*;(njJsv=D3;&{f%F@a`B}9x$C|-&fdRk?FZ4)U7;ms5}H3s zR?eH=5^16INxJ&5clDpBH4kH^ebMMRxM#z^zkh%K{F&~Z_?x)yl0)OG7f&9_%YyT;ImrWeTAZ* zZVMaioVIOPbou=8?-tWsO$2l8jej`K3p0`PHWK|AvV6X>>kqrxeMrK|o%udOZ&|0GxYz_P8z&^*(@;HzGrkE!^L zt7lhxWPG=p@jGDopYYW`eta*{(*6^+YU#Y*i5X zH?N)l6tm>W{w=@#mlvh`{PJ4zCuG&y<~f3Usyq7p(iD+4b&rkU<@mFnNYD__5Q7U--L z?56rRX6+OCk}4gedUvO_aSQ0*^~Q24W)gJ#1gHv{-v+WNpMLrQ2GD= zKLag+;!hSv28IU=Iv`6xd4hrCKf^&zmhY#Udpwz0i=3R6Iyp5q_UU>#zjf7YOcSy& ze6}pGr)6W@f=j6_?W-*fWq2z~(wP{8=GXA-*}5dfJTNh#Fnehld#5nJg-oOvS4>Od z-cv0ajz=cQX~ekAh`9KuX#!hqT4VIm6wQel5?YxPOVb*;1+0R;oLI1+&sZmD9q%EB z6_F}T+_yFqI4~Y!V_<5~nDmh+TEuf!%%!Rg;Q}hW3~UchG&1zCXUxs|$#SaEZywt< z6`mQ6i=72TX5On{R-L-)DqEq7#)GM+uB>Bb<9gGW>^&oLOV&-UgfCC8Fp8QpZJ4suA9Z@-Ws$DVa1+!dq&Sc*%vA#rhRo4R&NvwhgBm@|&0X7p0LI3~& literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/huh.gif b/Upload/images/smilies/huh.gif new file mode 100644 index 0000000000000000000000000000000000000000..584bf4d272eddc9b0c6e3131c1e03b0752a40bfe GIT binary patch literal 1169 zcmZ?wbhEHb6k!ly_|Cxa@8945kD~rOjQ;l|_V44E?{}lW-imtu?BV}ALBDT>{J$Ue z?_SuaOTqshME<@T@%}={kK2(SE{FfW;rI5G*N-cH|851oKkfVEu>a%3f&VYM{=4A% z_p;~5ldk`-dc8mDc5aRBpDR8`mfGFf<@5K1_5V{g|4!QcKkNAKjN|v?jwhB_d^zE| zXNLLXoz9yln%&sod}EW_`IRmYPPYF)Z1U%@`Tt`UU-wyj*=ONwBJlmN?fKr;z-Pc89(aB}Lzww%M;W_*4B=)#%9cWz$#y-nl$CiTBNG(W7-__ba8 z?HcV{^L1}6&^tHB^z=NBbIYU7t&DzfeCpe~d*3}g_V&TilLyv*|M>Ltrw?CNE5BW; z^mVPu+vO?`7ipcE>+xWB)q}k?kB;c;pW4}ewI@gV z9v|-gaPQ!ckI%04NS$exJTuAm%oMvv2Pb`aaPr5;=Vuzl&-7cK>$kZu!~4QapNCs3 z9v_(S?8wxQcMpAhc>2eOr$0Wu`VR&SqktMAp!k!8k%3_ngAT|rP@Z7m_|KrqDf46T z@jeN|vM)arPaf}Ww_)>|#q^YuM^M6`qv0b<*G#QREAB`{sQL793-X9)Bq$tel}SA1 zVPy~`B&n`1=OEyaaDah{Nx`P#p-Wd^N6~>D2@e)HHY^X2wn(_}$W6qA;fTq`2?+i^qklmdR zMrwS*qS96+E3_jwr0{7@JJPtArL~P`0e^EFw^cKnh}VNXo=uNiIQ?*eDCG)lw@$U=R1?F^^Y$InbjnnmPB=761hGqpM>HO7iijv= zl`fSq>TsE4(R4z-WW~f|QrSxuvdPvfJmP3&a@=%6vGs@HahW=iq7zCJCTLt#?loA{ Pq10pYiKCN|k--`O!~wc% literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/lightbulb.png b/Upload/images/smilies/lightbulb.png new file mode 100644 index 0000000000000000000000000000000000000000..c6897aed473e50452dea6108d421313e3d5cb959 GIT binary patch literal 617 zcmV-v0+#)WP)3Wee3VFL&DC>e=a~btC@O<8@kdS7 zY)NoUdcAYPbZ3z6GgkYw3&6UH@`P&AA2f7`0UXdo)GyS9YBHSycuafPbw^z5fYD^C zpH=d(G^sxR(@BoxyQbN{(KjPcNM^|u*=9N^9!kH9eP8zz43I5zRpnnxlJrMoQCBUgVXjLJ| zu{W1<5oA~`9rH@)k5;O2=T@t^35@sgDtm`7L|J*poJdRtReK$GR~n9j)OgYXdSqnE7`$7 zrg#K}UIbr10jrH59ekMC0000IbW%=J04-tHOlpA;Ge3PD!ljt?#FDbN?#=)J0X9iQ zK~xyiUC-xof>00z;H$>iODMt>1;r~Rf|1yJZ?UJB_kWM9K+KHi=Qn3}XOR=HuU4y> zrq7H1bJN__pPBpOrrQuge|Rg^#RtHAp2`}Fu#2;)cu~I9@Z00k5{n`O3Yg{Tjt~TG z*JTVHEN>W`T8^RiQpWH4ff?)C#xi*8 zC9QV8k+haE8S3m|s8RdUzQm;qEdfawi-hQXy{l0v-CBV@fv&Ma$ndC*Kr1CUcJ8)6 zu<}NF*3W2QYg#RI66kJ@6|J`&^d03uKf}l)DM~KKvYE^ymEvi8Z3Lm{{7NS=_&6d} z9i<#C3jqWP0fRyn6flVF1e>$1tE-9NL2d%^=B{@dpNz&LejdNLKWUm~((l?Y0Jb%e T2EanG00000NkvXXu0mjf(Q-0o literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/ninja.gif b/Upload/images/smilies/ninja.gif new file mode 100644 index 0000000000000000000000000000000000000000..e2ec3c4ff306cfa916cd71a83cf0728d75e7e45e GIT binary patch literal 652 zcmZ?wbhEHb6k!lyc*el+|4z{V8-D+81^&P2`tO44-^-r=uX_Et;`9HM&HuBG|IRp0 z?#SA=b&jQlX;XR3<9io<-OQ$U<(R3mn5nUusdJiZ3!Cdn`@87I2V2Jm+gTW?&F;>! zFxEV@W#-9!D^BfSX=!F)X>R=V{$(>2CUXrQb4>wr9r4zDHw%5a)&fs|XWiK?F|(SZ zEew>VHpcq7TbhntU&n}@%-w^>P0-(~U?eL44r>UXA!uVQ1Yd#(p r6p$8b;*!l`_E@IuTya6-;1*3@Ip;n;u1m_t`(!PvSWb#?FjxZs+c?D1 literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/opera.gif b/Upload/images/smilies/opera.gif new file mode 100644 index 0000000000000000000000000000000000000000..7090aeb5af451a4ffd9720da73b655a3619bd59c GIT binary patch literal 881 zcmV-%1CIPhNk%w1VI2Sz0Oo%H{gs)_rbzhl=C5>b`1kbU+R^{sRQ}>y{Zm!^Y-<0j zM!T4o_3z};pg81*N|pfu`$R|M!jb;EE84Y4|Aa%!nl$aDCH&J&|93>R0t4K#Y~aa< z%L)tc;m7qlJp6NZ_?kNXqdon*LzOQO{>?%E#yYM_8{xTn|HC!(tR?Z&Rn}Elx~ZxC zDJ(-X5aYvA<+VK8nkfIiG5cL#&Wa_;OcAzLJkFX*QT-i9*%i$MB?iruI~*QHzT zuq?JvQ0qWJ>r7JOQC6#kGVP>J=Ac>Rxb3K zMf@=}<;b4>JwN21HuJ(p^UX}@i*uS76417q<>BGEIwAl6|NsC0A^8LW004ggEC2ui z0384n000O7fPaF6goO-RJ{uc8S`3Ackbew50Ra;)FB6qMj**ZZL;)`u((X*U9YerqpHR^(m-6{`G*^I-}DKl0l7adF|ooeEkA z5K%GfOCA6#0yG$rflQnk3m9Ht=Vyt@J8UAXfnh-21vFl4bUO!R27&=Dlqg{*LV?dG zY))u^p@f9dGhT*}U~^7N5(s^^7~RrS4h1 zlMocnFi-&DCW0RgI3)Dok|2QzFlICCXwkyT*Agh+cA?M(1dTR=_SC2`qw)X&O*js2 zVZy6d8CXJq0D+^)y*~u1a7cn6$pAkQ^a!3a$B2yESg;`3ZGnc}K|(SlnUTcFp8^ju zw15C4jD+XVd!#60Z&{Tw31)cU!{h;nItYyPfUdWPg(6LI5gPF0!v_RXswjtGLXCwK z_)}O=1LcPLLM({!K>`TWQO6VuM9>5jMI3QN5l}P{!D*gEvA~5<3?e`q5u9*B1Z_|_ HNFV?^u5Fh5 literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/plask.gif b/Upload/images/smilies/plask.gif new file mode 100644 index 0000000000000000000000000000000000000000..2f24dc2c25ac00febd6a6f7a22ac88888185e4d8 GIT binary patch literal 1473 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 literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/shamefaced.gif b/Upload/images/smilies/shamefaced.gif new file mode 100644 index 0000000000000000000000000000000000000000..826c4dc7fcc93b28cfa0fdc2f41dfba9d3f3a304 GIT binary patch literal 1179 zcmZ?wbhEHb6k!ly_|59}^}jnb|LxHIztiCVK8tg6Oi$1A zIJZ3N+{)+&$EUu%yZ7D0V{acE{r>Ukm(|K|mnwZ-tMYca%7+zNzc%XLU2J)GiRHH) zuHSaLo|^0NU{B4XBfVeWJ-jWK{ zM*kOBJ)3IrbFuTki5~wuZU1%J{%W!L-)aA=!})8S&A)p4|1Hk{J3M~XI{vJ6{FmnP zKi&0zmdC$LkN+`l|6<(!$GZQEb^jmd`QP8;$&)9*=mSUNC_zpLDE?$&WMG)apaaqj z$`cG6{~2^SWo9rP?G#Y-Ti{{1;o$*Eqojrt1rMFr1PoKo6lfTD@C%EnC|DFQG_r83 zRk0LuupDFO5af{12spsd$RS{NfWb(Bi=UrY&O*Xr%Zg@pUYidMNuCY;;-Vr32?vuJ zud;?nYOMHhsGUL4+RSIcfki>8Vw^%#Y`qhi+SQ!uUR=1)n6;E4i;m5G^8QnF zc23&9;i0zAB%4B}W9Q{vbeJ9-ZBR6dbE*H+P}sDTU(tQCRA6b~q89E|y=s<9SJ=J9 zY`atfyGma8aSN$L-LVwu6k6g^y(PyoIOC$STl1AC5{63cvmATmbhTR2xWx@CStOZ` z96!Y+s1z1a@lg20gatN9i6-SCQBm2iaswH&_VB79II`OuF!dBfC2zBZD;nC~dK~ literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/shy.gif b/Upload/images/smilies/shy.gif new file mode 100644 index 0000000000000000000000000000000000000000..71f0c23ee85880aea5d9c06e985554eed95e6da5 GIT binary patch literal 1409 zcmeH`YfO`O6vp4u7AeIEu{v?4Yk|>1U=%3W7LeXcyHcT4hv1edyXbCV#0_E=hk!`r zRvAT@b#qWHIyHqcQxIk^fE1ciU@(T%^`^_rfI_&G0q=ih**@(1KJLlM`EpL4lRUp1 zfsjw5pTI#lXiWwA#GwX*Vy^l8i{|pssha(h^?2JCFPW8;x z4_TB+lX8Mh5oc?nSgxnc-lWf}>GmslS97fU>*TFV=}QXQQWI^hC2d`K(A$y*D;aY) z!sgTw^KG#%HGTQp@Rhp}p4(AyD;>1afhu+5PW)OYY2!ZmkFJ<4Z4}%c3wmSVjs&1N z2;Ywf50XGH1w5nxEdz9?4PVO``6|QO{F=2zJgR07w`LBj4v*gATGV-#Tlv!(&U7b# zwnq%gSa3NTuHXP)Rq{a%6Rzh0InUM2arbc7TbaODY5};-f$s{yJ%P824IZ*VAK&qP ziT%M@d*5e3PX$IQFwnpN4Gg9MQ>xo|c)`eD7|C=Qvlpzg6&-I?&)XUhf_@Pg6af

    K$20Nz%1qvxEq`N12LGH59!tTj6n=6P z{BqR$_}GRmchiv%+m8Wf-j?e)?0&;#tabL+y8G+wri(6}+^KJ{KTzlLxuxK-Qp6KW71M`kSkKMHB7+INjtSmTJJ&v`-r(Vxf@8UD>;;-JN=PJc{rZEl*?=&({vRWq`#ms!mqAG zUfM48+ZkFDBmCGnawYD~k5suQBaHrN#i1&?*6Kh8hEla>eluL~FWvnzLz#MOKv>kf_Kmk6%zQ-^<2EGIdBY@y!Dy`@Yx<`p?qhDQA^#|Tsvh5#fISExgvgLF{%H+Gtw)R@}9+gqRI#0U_G zzu4^9X5$Z`p#Uh*$0iOEBK)`_0xLZL8@9|**Ig_7^tlxS2_!6fp`Uy_x3J(*J%Mux zXX+?`YX9~?|J#EE3DE&e5kU{N@%MmDhK9ha-k12^tTu$nhww>q}iwXYSHsZ=ZXk9Uva}ndM3e}(p@V5)U zrZ=#iJp0{2X;dBW)k3U*3ujg%$gwx5l{UeyL1s-9!Iu`qpdp!qE!(mq*}*{Z$0GF7 zGLC~irg#K}UIg;YG1aLag(+Dw0000IbW%=J0K#E?YRQ2#4@@UOn5Fd>+>*czUETly z0USw0K~xyiMbOuFf zRaE<6nc5UwRB*X0cf&STzbsVHbueh4sy_`@I9L{<=jqw#cGa-O>_}8SppdF+>agGq zbpSem1UPZQ>kM^eYQ4b=fFVr)IO*KSuF(D%RpC7E+V5FcD9EH~n>CkakGi-)p#`Yl zB~}ksLJe?1$=B8yD=bOJAW@fe)4~^b>_v|jpmIPBof^Yb;{{!Tl*?*JpCj1b|K=B) xZyZ9AS~I?!uh+j*a(u3_dphNc>$;V4ZvU71EElSs7=Qo(002ovPDHLkV1lW-6cqpf literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/sleepy.gif b/Upload/images/smilies/sleepy.gif new file mode 100644 index 0000000000000000000000000000000000000000..bb688aa0c66f96982355bf2988c2c1e884972724 GIT binary patch literal 1144 zcmZ?wbhEHb6k!ly_|Cxa@8945kD~rOjQ;l|_V44E?{}lW-irEvC+PRBkpK6?{@n}v zbSe1XgUH`^Bi>&K`Efh)!{zY*H~fBF@%wix@cn7uCx`tX9}fI~(e>X2*T0uN|6lcb zf7I>I6`wo1eEy!W{(s8m-$|SQXC42Yar}PV@#{&~FDG0d?{t2$%jL!f=Np^c&aZTN zaI*dXVUs_H&Ho>>_`1*H%RUQd6M^rCZO<=vdUR&$+Xwr;eR%kPkIui{I=^=5{oil! zZ=b>UU55V-nY`a(^lr1!!&N2^*IC?NX?c5<<+%mcrxy91TH^oUspn!%T*pO(mFNQ9;)BZ*yUW_l220 z54To4J}}|gk*Oc=9{Tw3^p6iue|&oN|Nno6Q7{l8p!k!8k%6I!K?h_xC{HkO{AXb0 zl*w4k)+?%=ab<(yhKCL+?ma7BBph^N7j^4XDAW+(o+>G-AfXX(fT4xUctt{C#ZnJ0 zc77HC34?})26nz6k)1{bXGBD}r3^S6wrDi7aR>NFDswo9Dv1ba1WZ`4>gq}k4S|(R z3f&^YLTX1W3KDW6HyNsVSbS9No~j{j;nE?XeC*E7(&t4t1deviP*gR_knq{@;Q^0I zO9!WL3QHUJ1ZD5Goj?&?w6nqz3U({v&PHu*7Z13x#q;yx z*6!Ooitpz=boP}tFWU3r#lb~8K0Y$6`tsnRYM(Si@db;M8&K`Efh)!{zY*H~fBF@%wix@cn7uCx`tX9}fI~(e>X2*T0uN|6lcb zf7I>I6`wo1eEy!W{(s8m-$|SQXC42Yar}PV@#{&~FDG0d?{t2$%jL!f=Np^c&aZTN zaI*dXVUs_H&Ho>>_`1*H%RUQd6M^rCZO<=vdUR&$+Xwr;eR%kPkIui{I=^=5{o7~o zeV5_CLniOH7`@wU^l+8Q!*v$7S6bd)WqEFa^{GX^r?yUuS=jNE6p679HdDOX;(GQMKeS3HByNAc#J~;aQcQTcM@M?UzI%9gvh;)La##E1u1-)m)2VQ_Pwi~K+LI%F zj}P~LxOec!$7k1iq|P);o|$BOW{TaTgOffyIQiq_^D~X&XZkJA_1j#S;eBDI&%>=1 zj}J_Ec4X?uyN5nLJpJRt(;uH+{r~@;VH6Bd2q^w!VPs%vWY7WG56Tk^9RC@ZIb|{y zv-OHq%r0Fo>@^At1PD^Yim_T~GY@=-MkRp<2fWaC7(lm`E literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/szczerbol.gif b/Upload/images/smilies/szczerbol.gif new file mode 100644 index 0000000000000000000000000000000000000000..8cc3de2a912ec0db4d44b1ce2382a50a1d0c73e8 GIT binary patch literal 735 zcmV<50wDcINk%w1VH5xq0OkMy00030|Ns8}{r}=x{NY>vc-og0s=GKfF%!3)sl0D3nKH|ZW@Zib#@#oBe z7tD`2&W}9Mm`l)^OyRY7g!tvqD`0(ZU^6LNp{{R30A^8LW004dfEC2ui z02BZe000O7fPR95G&3?QD>5@QgN=hkLqaMa7#JTaLPJE3f>cm37ZL~u2M7`uF;G;F zQ$Z;Z5d;PW1qK8W5Gg@ZgI`Z54G#_j#KjH|4Jc1vegaWI777du3)R-s3Kl?70#!~X z6cq^o014*fhKCR% zKGZOxM;9(UV2BX$qNB%;8)5L^a%PE(5HH992oOLexfdW>FhP^1%nlYQ$+2_^-~|gE zX40r}qXkEfoIHExz@ep$8Ub&}D6w$^smd2OY$ze~Mu49vc-og0s=GKfF%!3)sl0D3nKH|ZW@Zib#@#oBe z7tD`2&W}9Mm`l)^OyRY7g!tvqD`0(ZU^6LNp{{R30A^8LW004dfEC2ui z02BZe000O7fPR95G&3?QD>5@QgN=hkLqaMa7#JTaLPJE3f>cm37ZL~u2M7`uF;G;F zQ$Z;Z5d;PW1qK8W5Gg@ZgI`Z54G#_j#KjH|4Jc1vegaWI777du3)R-s3Kl?70#!~X z6cq^o014*fhKCR% zKGZOxM;9(UV2BX$qNB%;8)5L^a%PE(5HH9D2%wTBfEOTIFhP^1%nlYQ0jz9E?ga}S zX40r}qXkEfoaB&K`Efh)!{zY*H~fBF@%wix@cn7uCx`tX9}fI~(e>X2*T0uN|6lcb zf7I>I6`wo1eEy!W{(s8m-$|SQXC42Yar}PV@#{&~FDG0d?{t2$%jL!f=Np^c&aZTN zaI*dXVUs_H&Ho>>_`1*H%RUQd6M^rCZO<=vdUR&$+Xwr;eR%kPkIui{I=^=5{oil! zZ=b>UU55V-nY`a(^lr1!!&N2^*IC?NX?c5<<+%mcrxy91TH^oUspn!%T*pO(mFNQ9;)BZ*yUW_l220 z54To4J}}|gk*Oc=9{Tw3^p6iue|&oNpMl~3e;_dm=p6!zKUo+V7@8S$Ko*1Y1Ovx^ z26j%FjKyrdqS_f(HW+Sr=%C`>v*Javo|zydX~H4r6H&k> z+uQ7_QwpAJR}SpQaU&e?%bSyPAP?faq}}y9s&8F)p2ug9p=`^xwYiy z#Y3(<;ya2T@4I`beU@3?lZuBIn^|u@K3@Ih!9&$PX@=qp7AH3*yYo2SNPe+m-eJyJ zmJDoHLoXJ$c?!#1-+ceT#g>zjwxw*Bb|x?Do}_Yox=P@sqi1BT`2J30mr2c8$SNL_ wvC&ns;K@gJ_hyzu>~dv$9N8rEZ#1&YH#%4dDAaw~cwDab2P20&BO`+~0HW5BPyhe` literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/undecided.gif b/Upload/images/smilies/undecided.gif new file mode 100644 index 0000000000000000000000000000000000000000..cb979bfa0c72d21ef829ab2b126c2776ac6aba80 GIT binary patch literal 1155 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 literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/wink.gif b/Upload/images/smilies/wink.gif new file mode 100644 index 0000000000000000000000000000000000000000..58ff449d349c75e0ce5ac1f7faeecee00e4a8882 GIT binary patch literal 1145 zcmZ?wbhEHb6k!ly_|Cxa@8945kD~rOjQ;l|_V44E?{}lW-irEvC+PRBkpK6?{@n}v zbSe1XgUH`^Bi>&K`Efh)!{zY*H~fBF@%wix@cn7uCx`tX9}fI~(e>X2*T0uN|6lcb zf7I>I6`wo1eEy!W{(s8m-$|SQXC42Yar}PV@#{&~FDG0d?{t2$%jL!f=Np^c&aZTN zaI*dXVUs_H&Ho>>_`1*H%RUQd6M^rCZO<=vdUR&$+Xwr;eR%kPkIui{I=^=5{o7~o zeV5_CLniOH7`@wU^l+8Q!*v$7S6bd)WqEFa^{GX^r?yUuS=jNE6p679HdDOX;(GQMKeS3HByNAc#J~;aQcQTcM@M?UzI%9gvh;)La##E1u1-)m)2VQ_Pwi~K+LI%F zj}P~LxOec!$7k1iq|P);o|$BOW{TaTgOffyIQiq_^D~X&XZkJA_1j#S;eBDI&%>=1 zj}J_Ec4X?uyN5nLJpJRt(;uH+{r~@;VH6Bd2q^w!VPs%vWY7WG56Tk^9RC@ZIb|{y zv-OHv*o?_z@R65cjU9K0)C%qtqQ+bIC8*fAM5e^=S0yZJXLk)~Z zOov;KPf)f$X28TTL*G87gX7@N&FSZqQvUo{bc~ZnKt5=7+}vA-yVbLAEckfwkSmY) zj^fAr?k;kdGRu8ba`RxbE05TT$;TfYOm-Ky$YnTTd0C~MPqu0E@g4IPpOmy@V7eG~ zGC7S?SjPO)>f;AfI%nFHu$|i&+~zH$;`K?}aZ-!7q;;{y6Lz`$2@74tqH`v;ilyvn qY?qf|WjY~Oe&yjYiR2xD$7QP-gdRH7e>vDLSM}lIaiA;2a4$c literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/wow.gif b/Upload/images/smilies/wow.gif new file mode 100644 index 0000000000000000000000000000000000000000..044772f02b20aa42a82e5ddbbaca1ad3477b11b3 GIT binary patch literal 715 zcmV;+0yO{;#&UXUH#)+_uX6d+FJ6`Q}57J@Y7fL)K2fq zP2|H*c-og0s=GKfF%!3)s zl0D3nKH|ZW@Zib#@#oBe7tD`2&W}9Mm`l)^OyRY7g!tvqD`0(ZU^6LKp z0RR9000030|Nj6000000000000000000000000000000000000A^8LW004CWEC2ui z02BZe000O7fOUd(B!ws^ARs4&B!iBGI5##Q6ATO!A2v6Qk99~yCJP7!1Ox>L3noNJ zk4H5gi~|A!j0YYyM}t#C9VBzVBmus_1|36FbpS;)!@qOQzzQ@)07*g{&2-M%zzG~r zNk%~t(9h1m5)na0QZpJ4%_I=<5DytLQc*D&4h@VA0RJ^`fFVW{C@@M~u)wgPLxvYh zz<{#l$A}7yGHRqC0tlBbSzd%7L8qk2lO#g8(9*?=7$+=RkUVLUL<<&9!gv8N28$0B zD`v`(Qc$1!Ew`O&6+lD;B*QE06WwTS55!` literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/wub.gif b/Upload/images/smilies/wub.gif new file mode 100644 index 0000000000000000000000000000000000000000..d8ec600589862ee5af70139b903042735c6c8404 GIT binary patch literal 1025 zcmV+c1pfO+Nk%w1VI=?*0Oo%H|HL=u)2i{*$NP3S|5il*-BkZbME-;;%A-!zm`Xz~ z5dPv@{&z$7@a4^fN$i|P;kb7HqdVcYmHxUb)nFaXa3AcYCfc<~@8HP(vQ+eWCjY)f z{)0s1!j=BGTl~{Z_3PpPl{@~TLi%et?Q1#F7s6@+RCE?1I_q1C2n>x;lB>uQP{eUssjzrCnJO7(O z{g6ce#Y*_>=Ks(`{)s-!f*AgoO3tWT&Wl^ncT4}-Pyb&-0002~{{75cAmEoC`0ncO z&{W{Ehwt9N;c71Ms#W2dc=xg=%Umaok-uN zUD|#o+OLvZB5kMj0F9Qn{>0WBX~#Ay&92RIiGc8DDLaikvw zJ9a#1;bNyBEn0jk`0#;6k1;@A!t~+BipiimtyG0V=SLKiOm{{Z%YsGfWvoW5ZJ;1%9F=WpfK37n1Ku#Q1r&w z9OEw(4p2n=fH20wgfn$`7$CraN{H7Xs4yU~dIT9F97HSuuo=J-5p_8vdDB6doC-vE z=-D!0O`6wf)(qI9hsOvb18PLreb{#dx>Wio86!xF5Hcgub3u`&eHs)@2BarrginMQ zE4l+%!6ibHBzZU?OBXPBLBaq`Fu}!oC^VSh03>)Z#|tm$u)>A>aiIf+7AVm{M&)He zfd)(*VB(1;GNAzlM%-|M4im&EV~jeSU`GP73?hIK6p)|+iY9760tG^J;Dj9(oB^X= zj5?fQfgMhq vlpq8QU_4@E6*sie#tl_C(Ls*0{2_$^FqmNm3<5}z2_zj9)`2CM1Ofm%E`Qo* literal 0 HcmV?d00001 diff --git a/Upload/images/smilies/xd.gif b/Upload/images/smilies/xd.gif new file mode 100644 index 0000000000000000000000000000000000000000..72fcff129c5452c090d123bceeee2036626ea1cf GIT binary patch literal 727 zcmV;|0x11QNk%w1VH5xq0OkMy00030|Ns8}{ruru_uX6d+FJkIQv2Fe{@zyd(o_E6 zS?|zP_}f|V(^vo4PWaSL{@PLR%T46NPvgT;|ItPM&_(^zN&nSK@5M&^)J)vEO#R3^ z{>eQ4%t80ZLG{T+^vFfyxkKc-MA)!H*s?~?sYKw(hy24g^}aatzBofP5ck79&!;KAk2v%&5kC` zk0#{Aj^o3P@ZQ1r@#fZy8q9+k%#uCKls@9YlJMZk`0?k=ffvk=InIwf(3nfmnM~oe zc;mp3=ERlp-NNzV%lPo+`10!i|Nj6000000000000000000000A^8LW004OaEC2ui z02BZe000O7fO&$0FD@-6CM_;6gN=hfK0PHG6B8OGJw88!XBMATs2*JV%00|>XT6qFYI}ry60K&r22N63=0#HdI4-f_p z01o2d;t&raR!~hy7#ZW_@ZuR5NKIKfAQl(<{QdhDA97^Dg2O`v3J4P_L|DNC4lGx0 ztmx1|g~f{)DXzG2MU0UY98>@p86d#OlPWf#I5LI|7#k-TC1O`TnFo+EC5{J#8HEz042?9ij zTOmL+f>7z=W{o2|aL#a%5@pJiC{nnbfn$eL9z1j2v@x?~iF7{_}rw{MqAdn^?TGVN^(w7}TqO{+3&F9nJ+R*E<<0&OXdX^es|GZF{4 zEl^%(9lp{U!Tk6YH4YyudgpHEiEi8)M~XPNk&IU z<2VigpuIfr-T(i>=Y2DhH)SO$HOVnigb(Dsi9bi^OfNlh;gy9lX!QL;2?>26z1K#P zV&uBmc3ztB!JQGe3%xin-RaY+qK3d98fkvdQN;t{oK0gq+21S5uC5%{i0Rkv4w<&D zJMjZD7~PJ7Ws}GES&9V@nF^RLDT|DSF@(;5sRA*CvH-&fm&e1b*w01Co_GW)!WWmq zeOZb@C}{*uR%lI>L5yacs>LSc&yub>OO|tgQr{&M!Pxk;eM1c&ROwWXCzb>?PAMLC z1GC6JXDUc(-m@u3aTC6;$74tGFI<-5LO#4LoR#vKh>|j7m0)u&+#r4f3us)g0tH^I zt;E*mux|86(!S&sVn}Jx(E{rR@KAZe3V3OQgh*I9umtZKPs|XRegw&V z*XWil!;da!)+BwsQ-QH9Pg^G5XT1P$nS_y40Tsy z{=wwwR=Ec@H0)=_Eu4eUa{DduV&e41fhwT}-kHt$uA zb}g8vv`P8=DavZKF<526AnGep^efD4R7poT41ZImDN+S_C?KFCwamgWUZJk`!~ zT#=Z`F1h2n%sgVJokp-VKc_!QT=Ag>&W4N}ZVs1IETePLkb?bUKWr#oNjnpyd9k)?!4M?%;92?~PwtjZ=-!&#>4sNe7_}r$O zson-Y-4)nvlJpZQC&U&6uKs?SCVNj09n8wAFu|P76)3h_vPe_N8`*{Q?^VX)r(?M%vvE=b?K;_!f8 z85)&S&2)|t3TrI%&F?Itlg^Dg1pG215&^1RM0`E5g%-D^w{1v;Ej@GFf#$mhQ?td50gdL-SzT{X6={H?<9MQh zTO&IDmziQe=nz0T8Ju01Xm47?mb69O*PU)%;OZFgx!P8>>(A#M=fWq3vBN`3q^FtF zv|HfcX=>^}AYVq9-PJrn@MXK6`Md#U4{x3jGJ<^XDaW#fs!Er#ODIP}1U_W7@EKVI zd^M_Eg2^QQ6DZ*yoe{9k_B%akiPtknp;_KPPaEMp_N?@h(ODHk$K`ainr|-+$frDT zQKU?@eheS0B!m-{o=?N*C;UFVSv* literal 0 HcmV?d00001 diff --git a/Upload/images/spinner_big.gif b/Upload/images/spinner_big.gif new file mode 100644 index 0000000000000000000000000000000000000000..0ca7ada960568fff04400cda966fbdcb106abfa2 GIT binary patch literal 6820 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 literal 0 HcmV?d00001 diff --git a/Upload/images/star.png b/Upload/images/star.png new file mode 100644 index 0000000000000000000000000000000000000000..c41a2f67bdf02ac234d1f1a463d38a66c2dc9fc9 GIT binary patch literal 648 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 literal 0 HcmV?d00001 diff --git a/Upload/images/tcat.png b/Upload/images/tcat.png new file mode 100644 index 0000000000000000000000000000000000000000..5b38340d95d22d35ba2116ec67a8dd019a7701b2 GIT binary patch literal 140 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 H`u_h1R*~a2 literal 0 HcmV?d00001 diff --git a/Upload/images/valid.png b/Upload/images/valid.png new file mode 100644 index 0000000000000000000000000000000000000000..dc4d4cdb3b95708156e5ff877c7e9216d4a3eca5 GIT binary patch literal 547 zcmV+;0^I$HP)A?A4^j+ZV^}OQ&+wS@)2K(;|Knd4{08#R5NiMN?g|2X8T)hz4<@B1@gCm^3@D8ATCB2Fp2+6%+uUo9v342 zM?B2@1L6a5F3VKm)5=>+ekg7-`p-XK{ytEwhhd5U6T?&i1`tLV(8uS&(93tm|7QG8 zr9H;~9WDg?0P&?ZX?>R7q4S@Ak=zp?e;z|WKL^kN222Bb`4|{Fcs&@}dCwT1a{eZ9 zSo6Qe8O#6Thcy24uabKO6ko^C#VY_bfC0Aw?Ys;O&Dkfz);HJ!BE70hHIJF3&t{zBS5|;LpcWnHjLeXB6bFbL}m|$ lc&0Nz+5*fcWWa#tMgX!8z-OC93i|*6002ovPDHLkV1ix}>8Ahy literal 0 HcmV?d00001 diff --git a/Upload/inc/3rdparty/ayah/ayah.php b/Upload/inc/3rdparty/ayah/ayah.php new file mode 100644 index 0000000..3d2acc6 --- /dev/null +++ b/Upload/inc/3rdparty/ayah/ayah.php @@ -0,0 +1,482 @@ +__load_config_file()) + { + $this->__log("DEBUG", __FUNCTION__, "The ayah_config.php file is missing."); + } + + // Get and use any valid parameters that were passed in via the $params array. + foreach ((array)$this->__valid_construct_params as $partial_variable_name) + { + // Build the full variable name...and create an upper case version. + $variable_name = "ayah_" . $partial_variable_name; + $uc_variable_name = strtoupper($variable_name); + + // Check to see if it was passed in via $params. + if (isset($params[$partial_variable_name])) + { + $this->{$variable_name} = $params[$partial_variable_name]; + } + // Check to see if it was defined in the ayah_config file. + elseif (defined($uc_variable_name)) + { + $this->{$variable_name} = constant($uc_variable_name); + } + } + + // Generate some warnings/errors if needed variables are not set. + if ($this->ayah_publisher_key == "") + { + $this->__log("ERROR", __FUNCTION__, "Warning: Publisher key is not defined. This won't work."); + } + else + { + $this->__log("DEBUG", __FUNCTION__, "Publisher key: '$this->ayah_publisher_key'"); + } + if ($this->ayah_scoring_key == "") + { + $this->__log("ERROR", __FUNCTION__, "Warning: Scoring key is not defined. This won't work."); + } + else + { + // For security reasons, don't output the scoring key as part of the debug info. + } + if ($this->ayah_web_service_host == "") + { + $this->__log("ERROR", __FUNCTION__, "Warning: Web service host is not defined. This won't work."); + } + else + { + $this->__log("DEBUG", __FUNCTION__, "AYAH Webservice host: '$this->ayah_web_service_host'"); + } + + // If available, set the session secret. + if(array_key_exists("session_secret", $_REQUEST)) { + $this->session_secret = $_REQUEST["session_secret"]; + } + } + + /** + * Returns the markup for the PlayThru + * + * @return string + */ + public function getPublisherHTML($config = array()) + { + // Initialize. + $session_secret = ""; + $fields = array('config' => $config); + $webservice_url = '/ws/setruntimeoptions/' . $this->ayah_publisher_key; + + // If necessary, process the config data. + if ( ! empty($config)) + { + // Log it. + $this->__log("DEBUG", __FUNCTION__, "Setting runtime options...config data='".implode(",", $config)."'"); + + // Add the gameid to the options url. + if (array_key_exists("gameid", $config)) + { + $webservice_url .= '/' . $config['gameid']; + } + } + + // Call the webservice and get the response. + $resp = $this->doHttpsPostReturnJSONArray($this->ayah_web_service_host, $webservice_url, $fields); + if ($resp) + { + // Get the session secret from the response. + $session_secret = $resp->session_secret; + + // Build the url to the AYAH webservice. + $url = 'https://'; // The AYAH webservice API requires https. + $url.= $this->ayah_web_service_host; // Add the host. + $url.= "/ws/script/"; // Add the path to the API script. + $url.= urlencode($this->ayah_publisher_key); // Add the encoded publisher key. + $url.= (empty($session_secret))? "" : "/".$session_secret; // If set, add the session_secret. + + // Build and return the needed HTML code. + return "

    "; + } + else + { + // Build and log a detailed message. + $url = "https://".$this->ayah_web_service_host.$webservice_url; + $message = "Unable to connect to the AYAH webservice server. url='$url'"; + $this->__log("ERROR", __FUNCTION__, $message); + + // Build and display a helpful message to the site user. + $style = "padding: 10px; border: 1px solid #EED3D7; background: #F2DEDE; color: #B94A48;"; + $message = "Unable to load the Are You a Human PlayThru™. Please contact the site owner to report the problem."; + echo "

    $message

    \n"; + } + } + + /** + * Check whether the user is a human + * Wrapper for the scoreGame API call + * + * @return boolean + */ + public function scoreResult() { + $result = false; + if ($this->session_secret) { + $fields = array( + 'session_secret' => urlencode($this->session_secret), + 'scoring_key' => $this->ayah_scoring_key + ); + $resp = $this->doHttpsPostReturnJSONArray($this->ayah_web_service_host, "/ws/scoreGame", $fields); + if ($resp) { + $result = ($resp->status_code == 1); + } + } + else + { + $this->__log("DEBUG", __FUNCTION__, "Unable to score the result. Please check that your ayah_config.php file contains your correct publisher key and scoring key."); + } + + return $result; + } + + /** + * Records a conversion + * Called on the goal page that A and B redirect to + * A/B Testing Specific Function + * + * @return boolean + */ + public function recordConversion() { + // Build the url to the AYAH webservice.. + $url = 'https://'; // The AYAH webservice API requires https. + $url.= $this->ayah_web_service_host; // Add the host. + $url.= "/ws/recordConversion/"; // Add the path to the API script. + $url.= urlencode($this->ayah_publisher_key); // Add the encoded publisher key. + + if( isset( $this->session_secret ) ){ + return ''; + } else { + $this->__log("ERROR", __FUNCTION__, 'AYAH Conversion Error: No Session Secret'); + return FALSE; + } + } + + /** + * Do a HTTPS POST, return some JSON decoded as array (Internal function) + * @param $host hostname + * @param $path path + * @param $fields associative array of fields + * return JSON decoded data structure or empty data structure + */ + protected function doHttpsPostReturnJSONArray($hostname, $path, $fields) { + $result = $this->doHttpsPost($hostname, $path, $fields); + + if ($result) { + $result = $this->doJSONArrayDecode($result); + } else { + $this->__log("ERROR", __FUNCTION__, "Post to https://$hostname$path returned no result."); + $result = array(); + } + + return $result; + } + + // Internal function; does an HTTPS post + protected function doHttpsPost($hostname, $path, $fields) { + $result = ""; + // URLencode the post string + $fields_string = ""; + foreach($fields as $key=>$value) { + if (is_array($value)) { + if ( ! empty($value)) { + foreach ($value as $k => $v) { + $fields_string .= $key . '['. $k .']=' . $v . '&'; + } + } else { + $fields_string .= $key . '=&'; + } + } else { + $fields_string .= $key.'='.$value.'&'; + } + } + rtrim($fields_string,'&'); + + // Use cURL? + if ($this->__use_curl()) + { + // Build the cURL url. + $curl_url = "https://" . $hostname . $path; + + // Log it. + $this->__log("DEBUG", __FUNCTION__, "Using cURl: url='$curl_url', fields='$fields_string'"); + + // Initialize cURL session. + if ($ch = curl_init($curl_url)) + { + // Set the cURL options. + curl_setopt($ch, CURLOPT_POST, count($fields)); + curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + + // Execute the cURL request. + $result = curl_exec($ch); + + // Close the curl session. + curl_close($ch); + } + else + { + // Log it. + $this->__log("DEBUG", __FUNCTION__, "Unable to initialize cURL: url='$curl_url'"); + } + } + else + { + // Log it. + $this->__log("DEBUG", __FUNCTION__, "Using fsockopen(): fields='$fields_string'"); + + // Build a header + $http_request = "POST $path HTTP/1.1\r\n"; + $http_request .= "Host: $hostname\r\n"; + $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n"; + $http_request .= "Content-Length: " . strlen($fields_string) . "\r\n"; + $http_request .= "User-Agent: AreYouAHuman/PHP " . $this->get_version_number() . "\r\n"; + $http_request .= "Connection: Close\r\n"; + $http_request .= "\r\n"; + $http_request .= $fields_string ."\r\n"; + + $result = ''; + $errno = $errstr = ""; + $fs = fsockopen("ssl://" . $hostname, 443, $errno, $errstr, 10); + if( false == $fs ) { + $this->__log("ERROR", __FUNCTION__, "Could not open socket"); + } else { + fwrite($fs, $http_request); + while (!feof($fs)) { + $result .= fgets($fs, 4096); + } + + $result = explode("\r\n\r\n", $result, 2); + $result = $result[1]; + } + } + + // Log the result. + $this->__log("DEBUG", __FUNCTION__, "result='$result'"); + + // Return the result. + return $result; + } + + // Internal function: does a JSON decode of the string + protected function doJSONArrayDecode($string) { + $result = array(); + + if (function_exists("json_decode")) { + try { + $result = json_decode( $string); + } catch (Exception $e) { + $this->__log("ERROR", __FUNCTION__, "Exception when calling json_decode: " . $e->getMessage()); + $result = null; + } + } elseif (file_Exists("json.php")) { + require_once('json.php'); + $json = new Services_JSON(); + $result = $json->decode($string); + + if (!is_array($result)) { + $this->__log("ERROR", __FUNCTION__, "Expected array; got something else: $result"); + $result = array(); + } + } else { + $this->__log("ERROR", __FUNCTION__, "No JSON decode function available."); + } + + return $result; + } + + /** + * Get the current debug mode (TRUE or FALSE) + * + * @return boolean + */ + public function debug_mode($mode=null) + { + // Set it if the mode is passed. + if (null !== $mode) + { + // Save it. + $this->ayah_debug_mode = $mode; + + // Display a message if debug_mode is TRUE. + if ($mode) + { + $version_number = $this->get_version_number(); + $this->__log("DEBUG", "", "Debug mode is now on. (ayah.php version=$version_number)"); + + // Flush the buffer. + $this->__flush_message_buffer(); + } + } + + // If necessary, set the default. + if ( ! isset($this->ayah_debug_mode) or (null == $this->ayah_debug_mode)) $this->ayah_debug_mode = FALSE; + + // Return TRUE or FALSE. + return ($this->ayah_debug_mode)? TRUE : FALSE; + } + + /** + * Get the current version number + * + * @return string + */ + public function get_version_number() + { + return (isset($this->__version_number))? $this->__version_number : FALSE; + } + + /** + * Determine whether or not cURL is available to use. + * + * @return boolean + */ + private function __use_curl() + { + if (FALSE === $this->ayah_use_curl) + { + return FALSE; + } + elseif (function_exists('curl_init') and function_exists('curl_exec')) + { + return TRUE; + } + return FALSE; + } + + /** + * Load the config file. + * + * @return boolean + */ + private function __load_config_file() + { + // Initialize. + $name = 'ayah_config.php'; + $locations = array( + './', + dirname(__FILE__)."/", + ); + + // Look for the config file in each location. + foreach ($locations as $location) + { + if (file_exists($location.$name)) + { + require_once($location.$name); + return TRUE; + } + } + + // Could not find the config file. + return FALSE; + } + + /** + * Log a message + * + * @return null + */ + protected function __log($type, $function, $message) + { + // Add a prefix to the message. + $message = __CLASS__ . "::$function: " . $message; + + // Is it an error message? + if (FALSE !== stripos($type, "error")) + { + error_log($message); + } + + // Build the full message. + $message_style = "padding: 10px; border: 1px solid #EED3D7; background: #F2DEDE; color: #B94A48;"; + $full_message = "

    $type: $message

    \n"; + + // Output to the screen too? + if ($this->debug_mode()) + { + echo "$full_message"; + } + else + { + // Add the message to the buffer in case we need it later. + $this->__message_buffer[] = $full_message; + } + } + + private function __flush_message_buffer() + { + // Flush the buffer. + if ( ! empty($this->__message_buffer)) + { + foreach ($this->__message_buffer as $buffered_message) + { + // Print the buffered message. + echo "$buffered_message"; + } + } + } +} + +endif; // if ( ! class_exists('AYAH')): diff --git a/Upload/inc/3rdparty/ayah/index.html b/Upload/inc/3rdparty/ayah/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/3rdparty/ayah/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/3rdparty/diff/Diff.php b/Upload/inc/3rdparty/diff/Diff.php new file mode 100644 index 0000000..2ce1329 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff.php @@ -0,0 +1,261 @@ +, and is used/adapted with his permission. + * + * Copyright 2004 Geoffrey T. Dairiki + * Copyright 2004-2011 Horde LLC (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you did + * not receive this file, see http://www.horde.org/licenses/lgpl21. + * + * @package Text_Diff + * @author Geoffrey T. Dairiki + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff +{ + /** + * Array of changes. + * + * @var array + */ + protected $_edits; + + /** + * Computes diffs between sequences of strings. + * + * @param string $engine Name of the diffing engine to use. 'auto' + * will automatically select the best. + * @param array $params Parameters to pass to the diffing engine. + * Normally an array of two arrays, each + * containing the lines from a file. + */ + public function __construct($engine, $params) + { + if ($engine == 'auto') { + $engine = extension_loaded('xdiff') ? 'Xdiff' : 'Native'; + } else { + $engine = Horde_String::ucfirst(basename($engine)); + } + + // Fugly; Include operational classes required for Text_Diff + $classes = array( + 'String.php', + "Engine/{$engine}.php", + 'Renderer/Inline.php', + 'Op/Base.php', + 'Op/Copy.php', + 'Op/Change.php', + 'Op/Add.php', + 'Op/Delete.php' + ); + + foreach($classes as $class) + { + require_once MYBB_ROOT."inc/3rdparty/diff/Diff/{$class}"; + } + + $class = 'Horde_Text_Diff_Engine_' . $engine; + $diff_engine = new $class(); + + $this->_edits = call_user_func_array(array($diff_engine, 'diff'), $params); + } + + /** + * Returns the array of differences. + */ + public function getDiff() + { + return $this->_edits; + } + + /** + * returns the number of new (added) lines in a given diff. + * + * @since Text_Diff 1.1.0 + * + * @return integer The number of new lines + */ + public function countAddedLines() + { + $count = 0; + foreach ($this->_edits as $edit) { + if ($edit instanceof Horde_Text_Diff_Op_Add || + $edit instanceof Horde_Text_Diff_Op_Change) { + $count += $edit->nfinal(); + } + } + return $count; + } + + /** + * Returns the number of deleted (removed) lines in a given diff. + * + * @since Text_Diff 1.1.0 + * + * @return integer The number of deleted lines + */ + public function countDeletedLines() + { + $count = 0; + foreach ($this->_edits as $edit) { + if ($edit instanceof Horde_Text_Diff_Op_Delete || + $edit instanceof Horde_Text_Diff_Op_Change) { + $count += $edit->norig(); + } + } + return $count; + } + + /** + * Computes a reversed diff. + * + * Example: + * + * $diff = new Horde_Text_Diff($lines1, $lines2); + * $rev = $diff->reverse(); + * + * + * @return Horde_Text_Diff A Diff object representing the inverse of the + * original diff. Note that we purposely don't return a + * reference here, since this essentially is a clone() + * method. + */ + public function reverse() + { + if (version_compare(zend_version(), '2', '>')) { + $rev = clone($this); + } else { + $rev = $this; + } + $rev->_edits = array(); + foreach ($this->_edits as $edit) { + $rev->_edits[] = $edit->reverse(); + } + return $rev; + } + + /** + * Checks for an empty diff. + * + * @return boolean True if two sequences were identical. + */ + public function isEmpty() + { + foreach ($this->_edits as $edit) { + if (!($edit instanceof Horde_Text_Diff_Op_Copy)) { + return false; + } + } + return true; + } + + /** + * Computes the length of the Longest Common Subsequence (LCS). + * + * This is mostly for diagnostic purposes. + * + * @return integer The length of the LCS. + */ + public function lcs() + { + $lcs = 0; + foreach ($this->_edits as $edit) { + if ($edit instanceof Horde_Text_Diff_Op_Copy) { + $lcs += count($edit->orig); + } + } + return $lcs; + } + + /** + * Gets the original set of lines. + * + * This reconstructs the $from_lines parameter passed to the constructor. + * + * @return array The original sequence of strings. + */ + public function getOriginal() + { + $lines = array(); + foreach ($this->_edits as $edit) { + if ($edit->orig) { + array_splice($lines, count($lines), 0, $edit->orig); + } + } + return $lines; + } + + /** + * Gets the final set of lines. + * + * This reconstructs the $to_lines parameter passed to the constructor. + * + * @return array The sequence of strings. + */ + public function getFinal() + { + $lines = array(); + foreach ($this->_edits as $edit) { + if ($edit->final) { + array_splice($lines, count($lines), 0, $edit->final); + } + } + return $lines; + } + + /** + * Removes trailing newlines from a line of text. This is meant to be used + * with array_walk(). + * + * @param string $line The line to trim. + * @param integer $key The index of the line in the array. Not used. + */ + static public function trimNewlines(&$line, $key) + { + $line = str_replace(array("\n", "\r"), '', $line); + } + + /** + * Checks a diff for validity. + * + * This is here only for debugging purposes. + */ + protected function _check($from_lines, $to_lines) + { + if (serialize($from_lines) != serialize($this->getOriginal())) { + trigger_error("Reconstructed original doesn't match", E_USER_ERROR); + } + if (serialize($to_lines) != serialize($this->getFinal())) { + trigger_error("Reconstructed final doesn't match", E_USER_ERROR); + } + + $rev = $this->reverse(); + if (serialize($to_lines) != serialize($rev->getOriginal())) { + trigger_error("Reversed original doesn't match", E_USER_ERROR); + } + if (serialize($from_lines) != serialize($rev->getFinal())) { + trigger_error("Reversed final doesn't match", E_USER_ERROR); + } + + $prevtype = null; + foreach ($this->_edits as $edit) { + if ($prevtype == get_class($edit)) { + trigger_error("Edit sequence is non-optimal", E_USER_ERROR); + } + $prevtype = get_class($edit); + } + + return true; + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Engine/Native.php b/Upload/inc/3rdparty/diff/Diff/Engine/Native.php new file mode 100644 index 0000000..e1db345 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Engine/Native.php @@ -0,0 +1,442 @@ + 2, and some optimizations) are from + * Geoffrey T. Dairiki . The original PHP version of this + * code was written by him, and is used/adapted with his permission. + * + * Copyright 2004-2011 Horde LLC (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you did + * not receive this file, see http://www.horde.org/licenses/lgpl21. + * + * @author Geoffrey T. Dairiki + * @package Text_Diff + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Engine_Native +{ + public function diff($from_lines, $to_lines) + { + array_walk($from_lines, array('Horde_Text_Diff', 'trimNewlines')); + array_walk($to_lines, array('Horde_Text_Diff', 'trimNewlines')); + + $n_from = count($from_lines); + $n_to = count($to_lines); + + $this->xchanged = $this->ychanged = array(); + $this->xv = $this->yv = array(); + $this->xind = $this->yind = array(); + unset($this->seq); + unset($this->in_seq); + unset($this->lcs); + + // Skip leading common lines. + for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) { + if ($from_lines[$skip] !== $to_lines[$skip]) { + break; + } + $this->xchanged[$skip] = $this->ychanged[$skip] = false; + } + + // Skip trailing common lines. + $xi = $n_from; $yi = $n_to; + for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) { + if ($from_lines[$xi] !== $to_lines[$yi]) { + break; + } + $this->xchanged[$xi] = $this->ychanged[$yi] = false; + } + + // Ignore lines which do not exist in both files. + for ($xi = $skip; $xi < $n_from - $endskip; $xi++) { + $xhash[$from_lines[$xi]] = 1; + } + for ($yi = $skip; $yi < $n_to - $endskip; $yi++) { + $line = $to_lines[$yi]; + if (($this->ychanged[$yi] = empty($xhash[$line]))) { + continue; + } + $yhash[$line] = 1; + $this->yv[] = $line; + $this->yind[] = $yi; + } + for ($xi = $skip; $xi < $n_from - $endskip; $xi++) { + $line = $from_lines[$xi]; + if (($this->xchanged[$xi] = empty($yhash[$line]))) { + continue; + } + $this->xv[] = $line; + $this->xind[] = $xi; + } + + // Find the LCS. + $this->_compareseq(0, count($this->xv), 0, count($this->yv)); + + // Merge edits when possible. + $this->_shiftBoundaries($from_lines, $this->xchanged, $this->ychanged); + $this->_shiftBoundaries($to_lines, $this->ychanged, $this->xchanged); + + // Compute the edit operations. + $edits = array(); + $xi = $yi = 0; + while ($xi < $n_from || $yi < $n_to) { + assert($yi < $n_to || $this->xchanged[$xi]); + assert($xi < $n_from || $this->ychanged[$yi]); + + // Skip matching "snake". + $copy = array(); + while ($xi < $n_from && $yi < $n_to + && !$this->xchanged[$xi] && !$this->ychanged[$yi]) { + $copy[] = $from_lines[$xi++]; + ++$yi; + } + if ($copy) { + $edits[] = new Horde_Text_Diff_Op_Copy($copy); + } + + // Find deletes & adds. + $delete = array(); + while ($xi < $n_from && $this->xchanged[$xi]) { + $delete[] = $from_lines[$xi++]; + } + + $add = array(); + while ($yi < $n_to && $this->ychanged[$yi]) { + $add[] = $to_lines[$yi++]; + } + + if ($delete && $add) { + $edits[] = new Horde_Text_Diff_Op_Change($delete, $add); + } elseif ($delete) { + $edits[] = new Horde_Text_Diff_Op_Delete($delete); + } elseif ($add) { + $edits[] = new Horde_Text_Diff_Op_Add($add); + } + } + + return $edits; + } + + /** + * Divides the Largest Common Subsequence (LCS) of the sequences (XOFF, + * XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized + * segments. + * + * Returns (LCS, PTS). LCS is the length of the LCS. PTS is an array of + * NCHUNKS+1 (X, Y) indexes giving the diving points between sub + * sequences. The first sub-sequence is contained in (X0, X1), (Y0, Y1), + * the second in (X1, X2), (Y1, Y2) and so on. Note that (X0, Y0) == + * (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM). + * + * This public function assumes that the first lines of the specified portions of + * the two files do not match, and likewise that the last lines do not + * match. The caller must trim matching lines from the beginning and end + * of the portions it is going to specify. + */ + protected function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks) + { + $flip = false; + + if ($xlim - $xoff > $ylim - $yoff) { + /* Things seems faster (I'm not sure I understand why) when the + * shortest sequence is in X. */ + $flip = true; + list ($xoff, $xlim, $yoff, $ylim) + = array($yoff, $ylim, $xoff, $xlim); + } + + if ($flip) { + for ($i = $ylim - 1; $i >= $yoff; $i--) { + $ymatches[$this->xv[$i]][] = $i; + } + } else { + for ($i = $ylim - 1; $i >= $yoff; $i--) { + $ymatches[$this->yv[$i]][] = $i; + } + } + + $this->lcs = 0; + $this->seq[0]= $yoff - 1; + $this->in_seq = array(); + $ymids[0] = array(); + + $numer = $xlim - $xoff + $nchunks - 1; + $x = $xoff; + for ($chunk = 0; $chunk < $nchunks; $chunk++) { + if ($chunk > 0) { + for ($i = 0; $i <= $this->lcs; $i++) { + $ymids[$i][$chunk - 1] = $this->seq[$i]; + } + } + + $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $chunk) / $nchunks); + for (; $x < $x1; $x++) { + $line = $flip ? $this->yv[$x] : $this->xv[$x]; + if (empty($ymatches[$line])) { + continue; + } + $matches = $ymatches[$line]; + reset($matches); + while (list(, $y) = each($matches)) { + if (empty($this->in_seq[$y])) { + $k = $this->_lcsPos($y); + assert($k > 0); + $ymids[$k] = $ymids[$k - 1]; + break; + } + } + while (list(, $y) = each($matches)) { + if ($y > $this->seq[$k - 1]) { + assert($y <= $this->seq[$k]); + /* Optimization: this is a common case: next match is + * just replacing previous match. */ + $this->in_seq[$this->seq[$k]] = false; + $this->seq[$k] = $y; + $this->in_seq[$y] = 1; + } elseif (empty($this->in_seq[$y])) { + $k = $this->_lcsPos($y); + assert($k > 0); + $ymids[$k] = $ymids[$k - 1]; + } + } + } + } + + $seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff); + $ymid = $ymids[$this->lcs]; + for ($n = 0; $n < $nchunks - 1; $n++) { + $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks); + $y1 = $ymid[$n] + 1; + $seps[] = $flip ? array($y1, $x1) : array($x1, $y1); + } + $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim); + + return array($this->lcs, $seps); + } + + protected function _lcsPos($ypos) + { + $end = $this->lcs; + if ($end == 0 || $ypos > $this->seq[$end]) { + $this->seq[++$this->lcs] = $ypos; + $this->in_seq[$ypos] = 1; + return $this->lcs; + } + + $beg = 1; + while ($beg < $end) { + $mid = (int)(($beg + $end) / 2); + if ($ypos > $this->seq[$mid]) { + $beg = $mid + 1; + } else { + $end = $mid; + } + } + + assert($ypos != $this->seq[$end]); + + $this->in_seq[$this->seq[$end]] = false; + $this->seq[$end] = $ypos; + $this->in_seq[$ypos] = 1; + return $end; + } + + /** + * Finds LCS of two sequences. + * + * The results are recorded in the vectors $this->{x,y}changed[], by + * storing a 1 in the element for each line that is an insertion or + * deletion (ie. is not in the LCS). + * + * The subsequence of file 0 is (XOFF, XLIM) and likewise for file 1. + * + * Note that XLIM, YLIM are exclusive bounds. All line numbers are + * origin-0 and discarded lines are not counted. + */ + protected function _compareseq ($xoff, $xlim, $yoff, $ylim) + { + /* Slide down the bottom initial diagonal. */ + while ($xoff < $xlim && $yoff < $ylim + && $this->xv[$xoff] == $this->yv[$yoff]) { + ++$xoff; + ++$yoff; + } + + /* Slide up the top initial diagonal. */ + while ($xlim > $xoff && $ylim > $yoff + && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) { + --$xlim; + --$ylim; + } + + if ($xoff == $xlim || $yoff == $ylim) { + $lcs = 0; + } else { + /* This is ad hoc but seems to work well. $nchunks = + * sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); $nchunks = + * max(2,min(8,(int)$nchunks)); */ + $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1; + list($lcs, $seps) + = $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks); + } + + if ($lcs == 0) { + /* X and Y sequences have no common subsequence: mark all + * changed. */ + while ($yoff < $ylim) { + $this->ychanged[$this->yind[$yoff++]] = 1; + } + while ($xoff < $xlim) { + $this->xchanged[$this->xind[$xoff++]] = 1; + } + } else { + /* Use the partitions to split this problem into subproblems. */ + reset($seps); + $pt1 = $seps[0]; + while ($pt2 = next($seps)) { + $this->_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]); + $pt1 = $pt2; + } + } + } + + /** + * Adjusts inserts/deletes of identical lines to join changes as much as + * possible. + * + * We do something when a run of changed lines include a line at one end + * and has an excluded, identical line at the other. We are free to + * choose which identical line is included. `compareseq' usually chooses + * the one at the beginning, but usually it is cleaner to consider the + * following identical line to be the "change". + * + * This is extracted verbatim from analyze.c (GNU diffutils-2.7). + */ + protected function _shiftBoundaries($lines, &$changed, $other_changed) + { + $i = 0; + $j = 0; + + assert('count($lines) == count($changed)'); + $len = count($lines); + $other_len = count($other_changed); + + while (1) { + /* Scan forward to find the beginning of another run of + * changes. Also keep track of the corresponding point in the + * other file. + * + * Throughout this code, $i and $j are adjusted together so that + * the first $i elements of $changed and the first $j elements of + * $other_changed both contain the same number of zeros (unchanged + * lines). + * + * Furthermore, $j is always kept so that $j == $other_len or + * $other_changed[$j] == false. */ + while ($j < $other_len && $other_changed[$j]) { + $j++; + } + + while ($i < $len && ! $changed[$i]) { + assert('$j < $other_len && ! $other_changed[$j]'); + $i++; $j++; + while ($j < $other_len && $other_changed[$j]) { + $j++; + } + } + + if ($i == $len) { + break; + } + + $start = $i; + + /* Find the end of this run of changes. */ + while (++$i < $len && $changed[$i]) { + continue; + } + + do { + /* Record the length of this run of changes, so that we can + * later determine whether the run has grown. */ + $runlength = $i - $start; + + /* Move the changed region back, so long as the previous + * unchanged line matches the last changed one. This merges + * with previous changed regions. */ + while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) { + $changed[--$start] = 1; + $changed[--$i] = false; + while ($start > 0 && $changed[$start - 1]) { + $start--; + } + assert('$j > 0'); + while ($other_changed[--$j]) { + continue; + } + assert('$j >= 0 && !$other_changed[$j]'); + } + + /* Set CORRESPONDING to the end of the changed run, at the + * last point where it corresponds to a changed run in the + * other file. CORRESPONDING == LEN means no such point has + * been found. */ + $corresponding = $j < $other_len ? $i : $len; + + /* Move the changed region forward, so long as the first + * changed line matches the following unchanged one. This + * merges with following changed regions. Do this second, so + * that if there are no merges, the changed region is moved + * forward as far as possible. */ + while ($i < $len && $lines[$start] == $lines[$i]) { + $changed[$start++] = false; + $changed[$i++] = 1; + while ($i < $len && $changed[$i]) { + $i++; + } + + assert('$j < $other_len && ! $other_changed[$j]'); + $j++; + if ($j < $other_len && $other_changed[$j]) { + $corresponding = $i; + while ($j < $other_len && $other_changed[$j]) { + $j++; + } + } + } + } while ($runlength != $i - $start); + + /* If possible, move the fully-merged run of changes back to a + * corresponding run in the other file. */ + while ($corresponding < $i) { + $changed[--$start] = 1; + $changed[--$i] = 0; + assert('$j > 0'); + while ($other_changed[--$j]) { + continue; + } + assert('$j >= 0 && !$other_changed[$j]'); + } + } + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Engine/Shell.php b/Upload/inc/3rdparty/diff/Diff/Engine/Shell.php new file mode 100644 index 0000000..601b965 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Engine/Shell.php @@ -0,0 +1,165 @@ + + * @package Text_Diff + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Engine_Shell +{ + /** + * Path to the diff executable + * + * @var string + */ + protected $_diffCommand = 'diff'; + + /** + * Returns the array of differences. + * + * @param array $from_lines lines of text from old file + * @param array $to_lines lines of text from new file + * + * @return array all changes made (array with Horde_Text_Diff_Op_* objects) + */ + public function diff($from_lines, $to_lines) + { + array_walk($from_lines, array('Horde_Text_Diff', 'trimNewlines')); + array_walk($to_lines, array('Horde_Text_Diff', 'trimNewlines')); + + // Execute gnu diff or similar to get a standard diff file. + $from_file = Horde_Util::getTempFile('Horde_Text_Diff'); + $to_file = Horde_Util::getTempFile('Horde_Text_Diff'); + $fp = fopen($from_file, 'w'); + fwrite($fp, implode("\n", $from_lines)); + fclose($fp); + $fp = fopen($to_file, 'w'); + fwrite($fp, implode("\n", $to_lines)); + fclose($fp); + $diff = shell_exec($this->_diffCommand . ' ' . $from_file . ' ' . $to_file); + unlink($from_file); + unlink($to_file); + + if (is_null($diff)) { + // No changes were made + return array(new Horde_Text_Diff_Op_Copy($from_lines)); + } + + $from_line_no = 1; + $to_line_no = 1; + $edits = array(); + + // Get changed lines by parsing something like: + // 0a1,2 + // 1,2c4,6 + // 1,5d6 + preg_match_all('#^(\d+)(?:,(\d+))?([adc])(\d+)(?:,(\d+))?$#m', $diff, + $matches, PREG_SET_ORDER); + + foreach ($matches as $match) { + if (!isset($match[5])) { + // This paren is not set every time (see regex). + $match[5] = false; + } + + if ($match[3] == 'a') { + $from_line_no--; + } + + if ($match[3] == 'd') { + $to_line_no--; + } + + if ($from_line_no < $match[1] || $to_line_no < $match[4]) { + // copied lines + assert('$match[1] - $from_line_no == $match[4] - $to_line_no'); + array_push($edits, + new Horde_Text_Diff_Op_Copy( + $this->_getLines($from_lines, $from_line_no, $match[1] - 1), + $this->_getLines($to_lines, $to_line_no, $match[4] - 1))); + } + + switch ($match[3]) { + case 'd': + // deleted lines + array_push($edits, + new Horde_Text_Diff_Op_Delete( + $this->_getLines($from_lines, $from_line_no, $match[2]))); + $to_line_no++; + break; + + case 'c': + // changed lines + array_push($edits, + new Horde_Text_Diff_Op_Change( + $this->_getLines($from_lines, $from_line_no, $match[2]), + $this->_getLines($to_lines, $to_line_no, $match[5]))); + break; + + case 'a': + // added lines + array_push($edits, + new Horde_Text_Diff_Op_Add( + $this->_getLines($to_lines, $to_line_no, $match[5]))); + $from_line_no++; + break; + } + } + + if (!empty($from_lines)) { + // Some lines might still be pending. Add them as copied + array_push($edits, + new Horde_Text_Diff_Op_Copy( + $this->_getLines($from_lines, $from_line_no, + $from_line_no + count($from_lines) - 1), + $this->_getLines($to_lines, $to_line_no, + $to_line_no + count($to_lines) - 1))); + } + + return $edits; + } + + /** + * Get lines from either the old or new text + * + * @access private + * + * @param array &$text_lines Either $from_lines or $to_lines + * @param int &$line_no Current line number + * @param int $end Optional end line, when we want to chop more + * than one line. + * + * @return array The chopped lines + */ + protected function _getLines(&$text_lines, &$line_no, $end = false) + { + if (!empty($end)) { + $lines = array(); + // We can shift even more + while ($line_no <= $end) { + array_push($lines, array_shift($text_lines)); + $line_no++; + } + } else { + $lines = array(array_shift($text_lines)); + $line_no++; + } + + return $lines; + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Engine/String.php b/Upload/inc/3rdparty/diff/Diff/Engine/String.php new file mode 100644 index 0000000..38d942c --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Engine/String.php @@ -0,0 +1,254 @@ + + * $patch = file_get_contents('example.patch'); + * $diff = new Horde_Text_Diff('string', array($patch)); + * $renderer = new Horde_Text_Diff_Renderer_inline(); + * echo $renderer->render($diff); + * + * + * Copyright 2005 Örjan Persson + * Copyright 2005-2011 Horde LLC (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you did + * not receive this file, see http://www.horde.org/licenses/lgpl21. + * + * @author Örjan Persson + * @package Text_Diff + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Engine_String +{ + /** + * Parses a unified or context diff. + * + * First param contains the whole diff and the second can be used to force + * a specific diff type. If the second parameter is 'autodetect', the + * diff will be examined to find out which type of diff this is. + * + * @param string $diff The diff content. + * @param string $mode The diff mode of the content in $diff. One of + * 'context', 'unified', or 'autodetect'. + * + * @return array List of all diff operations. + * @throws Horde_Text_Diff_Exception + */ + public function diff($diff, $mode = 'autodetect') + { + // Detect line breaks. + $lnbr = "\n"; + if (strpos($diff, "\r\n") !== false) { + $lnbr = "\r\n"; + } elseif (strpos($diff, "\r") !== false) { + $lnbr = "\r"; + } + + // Make sure we have a line break at the EOF. + if (substr($diff, -strlen($lnbr)) != $lnbr) { + $diff .= $lnbr; + } + + if ($mode != 'autodetect' && $mode != 'context' && $mode != 'unified') { + throw new Horde_Text_Diff_Exception('Type of diff is unsupported'); + } + + if ($mode == 'autodetect') { + $context = strpos($diff, '***'); + $unified = strpos($diff, '---'); + if ($context === $unified) { + throw new Horde_Text_Diff_Exception('Type of diff could not be detected'); + } elseif ($context === false || $unified === false) { + $mode = $context !== false ? 'context' : 'unified'; + } else { + $mode = $context < $unified ? 'context' : 'unified'; + } + } + + // Split by new line and remove the diff header, if there is one. + $diff = explode($lnbr, $diff); + if (($mode == 'context' && strpos($diff[0], '***') === 0) || + ($mode == 'unified' && strpos($diff[0], '---') === 0)) { + array_shift($diff); + array_shift($diff); + } + + if ($mode == 'context') { + return $this->parseContextDiff($diff); + } else { + return $this->parseUnifiedDiff($diff); + } + } + + /** + * Parses an array containing the unified diff. + * + * @param array $diff Array of lines. + * + * @return array List of all diff operations. + */ + public function parseUnifiedDiff($diff) + { + $edits = array(); + $end = count($diff) - 1; + for ($i = 0; $i < $end;) { + $diff1 = array(); + switch (substr($diff[$i], 0, 1)) { + case ' ': + do { + $diff1[] = substr($diff[$i], 1); + } while (++$i < $end && substr($diff[$i], 0, 1) == ' '); + $edits[] = new Horde_Text_Diff_Op_Copy($diff1); + break; + + case '+': + // get all new lines + do { + $diff1[] = substr($diff[$i], 1); + } while (++$i < $end && substr($diff[$i], 0, 1) == '+'); + $edits[] = new Horde_Text_Diff_Op_Add($diff1); + break; + + case '-': + // get changed or removed lines + $diff2 = array(); + do { + $diff1[] = substr($diff[$i], 1); + } while (++$i < $end && substr($diff[$i], 0, 1) == '-'); + + while ($i < $end && substr($diff[$i], 0, 1) == '+') { + $diff2[] = substr($diff[$i++], 1); + } + if (count($diff2) == 0) { + $edits[] = new Horde_Text_Diff_Op_Delete($diff1); + } else { + $edits[] = new Horde_Text_Diff_Op_Change($diff1, $diff2); + } + break; + + default: + $i++; + break; + } + } + + return $edits; + } + + /** + * Parses an array containing the context diff. + * + * @param array $diff Array of lines. + * + * @return array List of all diff operations. + */ + public function parseContextDiff(&$diff) + { + $edits = array(); + $i = $max_i = $j = $max_j = 0; + $end = count($diff) - 1; + while ($i < $end && $j < $end) { + while ($i >= $max_i && $j >= $max_j) { + // Find the boundaries of the diff output of the two files + for ($i = $j; + $i < $end && substr($diff[$i], 0, 3) == '***'; + $i++); + for ($max_i = $i; + $max_i < $end && substr($diff[$max_i], 0, 3) != '---'; + $max_i++); + for ($j = $max_i; + $j < $end && substr($diff[$j], 0, 3) == '---'; + $j++); + for ($max_j = $j; + $max_j < $end && substr($diff[$max_j], 0, 3) != '***'; + $max_j++); + } + + // find what hasn't been changed + $array = array(); + while ($i < $max_i && + $j < $max_j && + strcmp($diff[$i], $diff[$j]) == 0) { + $array[] = substr($diff[$i], 2); + $i++; + $j++; + } + + while ($i < $max_i && ($max_j-$j) <= 1) { + if ($diff[$i] != '' && substr($diff[$i], 0, 1) != ' ') { + break; + } + $array[] = substr($diff[$i++], 2); + } + + while ($j < $max_j && ($max_i-$i) <= 1) { + if ($diff[$j] != '' && substr($diff[$j], 0, 1) != ' ') { + break; + } + $array[] = substr($diff[$j++], 2); + } + if (count($array) > 0) { + $edits[] = new Horde_Text_Diff_Op_Copy($array); + } + + if ($i < $max_i) { + $diff1 = array(); + switch (substr($diff[$i], 0, 1)) { + case '!': + $diff2 = array(); + do { + $diff1[] = substr($diff[$i], 2); + if ($j < $max_j && substr($diff[$j], 0, 1) == '!') { + $diff2[] = substr($diff[$j++], 2); + } + } while (++$i < $max_i && substr($diff[$i], 0, 1) == '!'); + $edits[] = new Horde_Text_Diff_Op_Change($diff1, $diff2); + break; + + case '+': + do { + $diff1[] = substr($diff[$i], 2); + } while (++$i < $max_i && substr($diff[$i], 0, 1) == '+'); + $edits[] = new Horde_Text_Diff_Op_Add($diff1); + break; + + case '-': + do { + $diff1[] = substr($diff[$i], 2); + } while (++$i < $max_i && substr($diff[$i], 0, 1) == '-'); + $edits[] = new Horde_Text_Diff_Op_Delete($diff1); + break; + } + } + + if ($j < $max_j) { + $diff2 = array(); + switch (substr($diff[$j], 0, 1)) { + case '+': + do { + $diff2[] = substr($diff[$j++], 2); + } while ($j < $max_j && substr($diff[$j], 0, 1) == '+'); + $edits[] = new Horde_Text_Diff_Op_Add($diff2); + break; + + case '-': + do { + $diff2[] = substr($diff[$j++], 2); + } while ($j < $max_j && substr($diff[$j], 0, 1) == '-'); + $edits[] = new Horde_Text_Diff_Op_Delete($diff2); + break; + } + } + } + + return $edits; + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Engine/Xdiff.php b/Upload/inc/3rdparty/diff/Diff/Engine/Xdiff.php new file mode 100644 index 0000000..949e71d --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Engine/Xdiff.php @@ -0,0 +1,74 @@ + + * @package Text_Diff + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Engine_Xdiff +{ + /** + */ + public function diff($from_lines, $to_lines) + { + if (!extension_loaded('xdiff')) { + throw new Horde_Text_Diff_Exception('The xdiff extension is required for this diff engine'); + } + + array_walk($from_lines, array('Horde_Text_Diff', 'trimNewlines')); + array_walk($to_lines, array('Horde_Text_Diff', 'trimNewlines')); + + /* Convert the two input arrays into strings for xdiff processing. */ + $from_string = implode("\n", $from_lines); + $to_string = implode("\n", $to_lines); + + /* Diff the two strings and convert the result to an array. */ + $diff = xdiff_string_diff($from_string, $to_string, count($to_lines)); + $diff = explode("\n", $diff); + + /* Walk through the diff one line at a time. We build the $edits + * array of diff operations by reading the first character of the + * xdiff output (which is in the "unified diff" format). + * + * Note that we don't have enough information to detect "changed" + * lines using this approach, so we can't add Horde_Text_Diff_Op_Changed + * instances to the $edits array. The result is still perfectly + * valid, albeit a little less descriptive and efficient. */ + $edits = array(); + foreach ($diff as $line) { + if (!strlen($line)) { + continue; + } + switch ($line[0]) { + case ' ': + $edits[] = new Horde_Text_Diff_Op_Copy(array(substr($line, 1))); + break; + + case '+': + $edits[] = new Horde_Text_Diff_Op_Add(array(substr($line, 1))); + break; + + case '-': + $edits[] = new Horde_Text_Diff_Op_Delete(array(substr($line, 1))); + break; + } + } + + return $edits; + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Engine/index.html b/Upload/inc/3rdparty/diff/Diff/Engine/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Engine/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/3rdparty/diff/Diff/Exception.php b/Upload/inc/3rdparty/diff/Diff/Exception.php new file mode 100644 index 0000000..48ea410 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Exception.php @@ -0,0 +1,24 @@ + + * @category Horde + * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 + * @package Text_Diff + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Exception extends Horde_Exception_Wrapped +{ +} diff --git a/Upload/inc/3rdparty/diff/Diff/Mapped.php b/Upload/inc/3rdparty/diff/Diff/Mapped.php new file mode 100644 index 0000000..36a6cdc --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Mapped.php @@ -0,0 +1,59 @@ + + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Mapped extends Horde_Text_Diff +{ + /** + * Computes a diff between sequences of strings. + * + * This can be used to compute things like case-insensitve diffs, or diffs + * which ignore changes in white-space. + * + * @param array $from_lines An array of strings. + * @param array $to_lines An array of strings. + * @param array $mapped_from_lines This array should have the same size + * number of elements as $from_lines. The + * elements in $mapped_from_lines and + * $mapped_to_lines are what is actually + * compared when computing the diff. + * @param array $mapped_to_lines This array should have the same number + * of elements as $to_lines. + */ + public function __construct($from_lines, $to_lines, + $mapped_from_lines, $mapped_to_lines) + { + assert(count($from_lines) == count($mapped_from_lines)); + assert(count($to_lines) == count($mapped_to_lines)); + + parent::__construct($mapped_from_lines, $mapped_to_lines); + + $xi = $yi = 0; + for ($i = 0; $i < count($this->_edits); $i++) { + $orig = &$this->_edits[$i]->orig; + if (is_array($orig)) { + $orig = array_slice($from_lines, $xi, count($orig)); + $xi += count($orig); + } + + $final = &$this->_edits[$i]->final; + if (is_array($final)) { + $final = array_slice($to_lines, $yi, count($final)); + $yi += count($final); + } + } + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Op/Add.php b/Upload/inc/3rdparty/diff/Diff/Op/Add.php new file mode 100644 index 0000000..c8c26b5 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Op/Add.php @@ -0,0 +1,34 @@ +, and is used/adapted with his permission. + * + * Copyright 2004 Geoffrey T. Dairiki + * Copyright 2004-2011 Horde LLC (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you did + * not receive this file, see http://www.horde.org/licenses/lgpl21. + * + * @package Text_Diff + * @author Geoffrey T. Dairiki + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Op_Add extends Horde_Text_Diff_Op_Base +{ + public function __construct($lines) + { + $this->final = $lines; + $this->orig = false; + } + + public function reverse() + { + return new Horde_Text_Diff_Op_Delete($this->final); + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Op/Base.php b/Upload/inc/3rdparty/diff/Diff/Op/Base.php new file mode 100644 index 0000000..3a63c4b --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Op/Base.php @@ -0,0 +1,38 @@ +, and is used/adapted with his permission. + * + * Copyright 2004 Geoffrey T. Dairiki + * Copyright 2004-2011 Horde LLC (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you did + * not receive this file, see http://www.horde.org/licenses/lgpl21. + * + * @package Text_Diff + * @author Geoffrey T. Dairiki + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +abstract class Horde_Text_Diff_Op_Base +{ + public $orig; + public $final; + + abstract public function reverse(); + + public function norig() + { + return $this->orig ? count($this->orig) : 0; + } + + public function nfinal() + { + return $this->final ? count($this->final) : 0; + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Op/Change.php b/Upload/inc/3rdparty/diff/Diff/Op/Change.php new file mode 100644 index 0000000..6512989 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Op/Change.php @@ -0,0 +1,34 @@ +, and is used/adapted with his permission. + * + * Copyright 2004 Geoffrey T. Dairiki + * Copyright 2004-2011 Horde LLC (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you did + * not receive this file, see http://www.horde.org/licenses/lgpl21. + * + * @package Text_Diff + * @author Geoffrey T. Dairiki + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Op_Change extends Horde_Text_Diff_Op_Base +{ + public function __construct($orig, $final) + { + $this->orig = $orig; + $this->final = $final; + } + + public function reverse() + { + return new Horde_Text_Diff_Op_Change($this->final, $this->orig); + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Op/Copy.php b/Upload/inc/3rdparty/diff/Diff/Op/Copy.php new file mode 100644 index 0000000..a3e8f4a --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Op/Copy.php @@ -0,0 +1,37 @@ +, and is used/adapted with his permission. + * + * Copyright 2004 Geoffrey T. Dairiki + * Copyright 2004-2011 Horde LLC (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you did + * not receive this file, see http://www.horde.org/licenses/lgpl21. + * + * @package Text_Diff + * @author Geoffrey T. Dairiki + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Op_Copy extends Horde_Text_Diff_Op_Base +{ + public function __construct($orig, $final = false) + { + if (!is_array($final)) { + $final = $orig; + } + $this->orig = $orig; + $this->final = $final; + } + + public function reverse() + { + return new Horde_Text_Diff_Op_Copy($this->final, $this->orig); + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Op/Delete.php b/Upload/inc/3rdparty/diff/Diff/Op/Delete.php new file mode 100644 index 0000000..3fbf3b9 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Op/Delete.php @@ -0,0 +1,34 @@ +, and is used/adapted with his permission. + * + * Copyright 2004 Geoffrey T. Dairiki + * Copyright 2004-2011 Horde LLC (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you did + * not receive this file, see http://www.horde.org/licenses/lgpl21. + * + * @package Text_Diff + * @author Geoffrey T. Dairiki + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Op_Delete extends Horde_Text_Diff_Op_Base +{ + public function __construct($lines) + { + $this->orig = $lines; + $this->final = false; + } + + public function reverse() + { + return new Horde_Text_Diff_Op_Add($this->orig); + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Op/index.html b/Upload/inc/3rdparty/diff/Diff/Op/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Op/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/3rdparty/diff/Diff/Renderer.php b/Upload/inc/3rdparty/diff/Diff/Renderer.php new file mode 100644 index 0000000..3afcf6c --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Renderer.php @@ -0,0 +1,241 @@ +
    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Renderer +{ + /** + * Number of leading context "lines" to preserve. + * + * This should be left at zero for this class, but subclasses may want to + * set this to other values. + */ + protected $_leading_context_lines = 0; + + /** + * Number of trailing context "lines" to preserve. + * + * This should be left at zero for this class, but subclasses may want to + * set this to other values. + */ + protected $_trailing_context_lines = 0; + + /** + * Constructor. + */ + public function __construct($params = array()) + { + foreach ($params as $param => $value) { + $v = '_' . $param; + if (isset($this->$v)) { + $this->$v = $value; + } + } + } + + /** + * Get any renderer parameters. + * + * @return array All parameters of this renderer object. + */ + public function getParams() + { + $params = array(); + foreach (get_object_vars($this) as $k => $v) { + if ($k[0] == '_') { + $params[substr($k, 1)] = $v; + } + } + + return $params; + } + + /** + * Renders a diff. + * + * @param Horde_Text_Diff $diff A Horde_Text_Diff object. + * + * @return string The formatted output. + */ + public function render($diff) + { + $xi = $yi = 1; + $block = false; + $context = array(); + + $nlead = $this->_leading_context_lines; + $ntrail = $this->_trailing_context_lines; + + $output = $this->_startDiff(); + + $diffs = $diff->getDiff(); + foreach ($diffs as $i => $edit) { + /* If these are unchanged (copied) lines, and we want to keep + * leading or trailing context lines, extract them from the copy + * block. */ + if ($edit instanceof Horde_Text_Diff_Op_Copy) { + /* Do we have any diff blocks yet? */ + if (is_array($block)) { + /* How many lines to keep as context from the copy + * block. */ + $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail; + if (count($edit->orig) <= $keep) { + /* We have less lines in the block than we want for + * context => keep the whole block. */ + $block[] = $edit; + } else { + if ($ntrail) { + /* Create a new block with as many lines as we need + * for the trailing context. */ + $context = array_slice($edit->orig, 0, $ntrail); + $block[] = new Horde_Text_Diff_Op_Copy($context); + } + /* @todo */ + $output .= $this->_block($x0, $ntrail + $xi - $x0, + $y0, $ntrail + $yi - $y0, + $block); + $block = false; + } + } + /* Keep the copy block as the context for the next block. */ + $context = $edit->orig; + } else { + /* Don't we have any diff blocks yet? */ + if (!is_array($block)) { + /* Extract context lines from the preceding copy block. */ + $context = array_slice($context, count($context) - $nlead); + $x0 = $xi - count($context); + $y0 = $yi - count($context); + $block = array(); + if ($context) { + $block[] = new Horde_Text_Diff_Op_Copy($context); + } + } + $block[] = $edit; + } + + if ($edit->orig) { + $xi += count($edit->orig); + } + if ($edit->final) { + $yi += count($edit->final); + } + } + + if (is_array($block)) { + $output .= $this->_block($x0, $xi - $x0, + $y0, $yi - $y0, + $block); + } + + return $output . $this->_endDiff(); + } + + protected function _block($xbeg, $xlen, $ybeg, $ylen, &$edits) + { + $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen)); + + foreach ($edits as $edit) { + switch (get_class($edit)) { + case 'Horde_Text_Diff_Op_Copy': + $output .= $this->_context($edit->orig); + break; + + case 'Horde_Text_Diff_Op_Add': + $output .= $this->_added($edit->final); + break; + + case 'Horde_Text_Diff_Op_Delete': + $output .= $this->_deleted($edit->orig); + break; + + case 'Horde_Text_Diff_Op_Change': + $output .= $this->_changed($edit->orig, $edit->final); + break; + } + } + + return $output . $this->_endBlock(); + } + + protected function _startDiff() + { + return ''; + } + + protected function _endDiff() + { + return ''; + } + + protected function _blockHeader($xbeg, $xlen, $ybeg, $ylen) + { + if ($xlen > 1) { + $xbeg .= ',' . ($xbeg + $xlen - 1); + } + if ($ylen > 1) { + $ybeg .= ',' . ($ybeg + $ylen - 1); + } + + // this matches the GNU Diff behaviour + if ($xlen && !$ylen) { + $ybeg--; + } elseif (!$xlen) { + $xbeg--; + } + + return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg; + } + + protected function _startBlock($header) + { + return $header . "\n"; + } + + protected function _endBlock() + { + return ''; + } + + protected function _lines($lines, $prefix = ' ') + { + return $prefix . implode("\n$prefix", $lines) . "\n"; + } + + protected function _context($lines) + { + return $this->_lines($lines, ' '); + } + + protected function _added($lines) + { + return $this->_lines($lines, '> '); + } + + protected function _deleted($lines) + { + return $this->_lines($lines, '< '); + } + + protected function _changed($orig, $final) + { + return $this->_deleted($orig) . "---\n" . $this->_added($final); + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Renderer/Context.php b/Upload/inc/3rdparty/diff/Diff/Renderer/Context.php new file mode 100644 index 0000000..6fc37ad --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Renderer/Context.php @@ -0,0 +1,75 @@ +
    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Renderer_Context extends Horde_Text_Diff_Renderer +{ + /** + * Number of leading context "lines" to preserve. + */ + protected $_leading_context_lines = 4; + + /** + * Number of trailing context "lines" to preserve. + */ + protected $_trailing_context_lines = 4; + + protected $_second_block = ''; + + protected function _blockHeader($xbeg, $xlen, $ybeg, $ylen) + { + if ($xlen != 1) { + $xbeg .= ',' . $xlen; + } + if ($ylen != 1) { + $ybeg .= ',' . $ylen; + } + $this->_second_block = "--- $ybeg ----\n"; + return "***************\n*** $xbeg ****"; + } + + protected function _endBlock() + { + return $this->_second_block; + } + + protected function _context($lines) + { + $this->_second_block .= $this->_lines($lines, ' '); + return $this->_lines($lines, ' '); + } + + protected function _added($lines) + { + $this->_second_block .= $this->_lines($lines, '+ '); + return ''; + } + + protected function _deleted($lines) + { + return $this->_lines($lines, '- '); + } + + protected function _changed($orig, $final) + { + $this->_second_block .= $this->_lines($final, '! '); + return $this->_lines($orig, '! '); + } + +} diff --git a/Upload/inc/3rdparty/diff/Diff/Renderer/Inline.php b/Upload/inc/3rdparty/diff/Diff/Renderer/Inline.php new file mode 100644 index 0000000..cf829c8 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Renderer/Inline.php @@ -0,0 +1,200 @@ +
    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Renderer_Inline extends Horde_Text_Diff_Renderer +{ + /** + * Number of leading context "lines" to preserve. + * + * @var integer + */ + protected $_leading_context_lines = 10000; + + /** + * Number of trailing context "lines" to preserve. + * + * @var integer + */ + protected $_trailing_context_lines = 10000; + + /** + * Prefix for inserted text. + * + * @var string + */ + protected $_ins_prefix = ''; + + /** + * Suffix for inserted text. + * + * @var string + */ + protected $_ins_suffix = ''; + + /** + * Prefix for deleted text. + * + * @var string + */ + protected $_del_prefix = ''; + + /** + * Suffix for deleted text. + * + * @var string + */ + protected $_del_suffix = ''; + + /** + * Header for each change block. + * + * @var string + */ + protected $_block_header = ''; + + /** + * Whether to split down to character-level. + * + * @var boolean + */ + protected $_split_characters = false; + + /** + * What are we currently splitting on? Used to recurse to show word-level + * or character-level changes. + * + * @var string + */ + protected $_split_level = 'lines'; + + protected function _blockHeader($xbeg, $xlen, $ybeg, $ylen) + { + return $this->_block_header; + } + + protected function _startBlock($header) + { + return $header; + } + + protected function _lines($lines, $prefix = ' ', $encode = true) + { + if ($encode) { + array_walk($lines, array(&$this, '_encode')); + } + + if ($this->_split_level == 'lines') { + return implode("\n", $lines) . "\n"; + } else { + return implode('', $lines); + } + } + + protected function _added($lines) + { + array_walk($lines, array(&$this, '_encode')); + $lines[0] = $this->_ins_prefix . $lines[0]; + $lines[count($lines) - 1] .= $this->_ins_suffix; + return $this->_lines($lines, ' ', false); + } + + protected function _deleted($lines, $words = false) + { + array_walk($lines, array(&$this, '_encode')); + $lines[0] = $this->_del_prefix . $lines[0]; + $lines[count($lines) - 1] .= $this->_del_suffix; + return $this->_lines($lines, ' ', false); + } + + protected function _changed($orig, $final) + { + /* If we've already split on characters, just display. */ + if ($this->_split_level == 'characters') { + return $this->_deleted($orig) + . $this->_added($final); + } + + /* If we've already split on words, just display. */ + if ($this->_split_level == 'words') { + $prefix = ''; + while ($orig[0] !== false && $final[0] !== false && + substr($orig[0], 0, 1) == ' ' && + substr($final[0], 0, 1) == ' ') { + $prefix .= substr($orig[0], 0, 1); + $orig[0] = substr($orig[0], 1); + $final[0] = substr($final[0], 1); + } + return $prefix . $this->_deleted($orig) . $this->_added($final); + } + + $text1 = implode("\n", $orig); + $text2 = implode("\n", $final); + + /* Non-printing newline marker. */ + $nl = "\0"; + + if ($this->_split_characters) { + $diff = new Horde_Text_Diff('native', + array(preg_split('//', $text1), + preg_split('//', $text2))); + } else { + /* We want to split on word boundaries, but we need to preserve + * whitespace as well. Therefore we split on words, but include + * all blocks of whitespace in the wordlist. */ + $diff = new Horde_Text_Diff('native', + array($this->_splitOnWords($text1, $nl), + $this->_splitOnWords($text2, $nl))); + } + + /* Get the diff in inline format. */ + $renderer = new Horde_Text_Diff_Renderer_inline + (array_merge($this->getParams(), + array('split_level' => $this->_split_characters ? 'characters' : 'words'))); + + /* Run the diff and get the output. */ + return str_replace($nl, "\n", $renderer->render($diff)) . "\n"; + } + + protected function _splitOnWords($string, $newlineEscape = "\n") + { + // Ignore \0; otherwise the while loop will never finish. + $string = str_replace("\0", '', $string); + + $words = array(); + $length = strlen($string); + $pos = 0; + + while ($pos < $length) { + // Eat a word with any preceding whitespace. + $spaces = strspn(substr($string, $pos), " \n"); + $nextpos = strcspn(substr($string, $pos + $spaces), " \n"); + $words[] = str_replace("\n", $newlineEscape, substr($string, $pos, $spaces + $nextpos)); + $pos += $spaces + $nextpos; + } + + return $words; + } + + protected function _encode(&$string) + { + $string = htmlspecialchars($string); + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Renderer/Unified.php b/Upload/inc/3rdparty/diff/Diff/Renderer/Unified.php new file mode 100644 index 0000000..d19f2ce --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Renderer/Unified.php @@ -0,0 +1,64 @@ +
    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_Renderer_Unified extends Horde_Text_Diff_Renderer +{ + /** + * Number of leading context "lines" to preserve. + */ + protected $_leading_context_lines = 4; + + /** + * Number of trailing context "lines" to preserve. + */ + protected $_trailing_context_lines = 4; + + protected function _blockHeader($xbeg, $xlen, $ybeg, $ylen) + { + if ($xlen != 1) { + $xbeg .= ',' . $xlen; + } + if ($ylen != 1) { + $ybeg .= ',' . $ylen; + } + return "@@ -$xbeg +$ybeg @@"; + } + + protected function _context($lines) + { + return $this->_lines($lines, ' '); + } + + protected function _added($lines) + { + return $this->_lines($lines, '+'); + } + + protected function _deleted($lines) + { + return $this->_lines($lines, '-'); + } + + protected function _changed($orig, $final) + { + return $this->_deleted($orig) . $this->_added($final); + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/Renderer/index.html b/Upload/inc/3rdparty/diff/Diff/Renderer/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/Renderer/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/3rdparty/diff/Diff/String.php b/Upload/inc/3rdparty/diff/Diff/String.php new file mode 100644 index 0000000..a6101ca --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/String.php @@ -0,0 +1,778 @@ + + * @category Horde + * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 + * @package Util + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_String +{ + /** + * lower() cache. + * + * @var array + */ + static protected $_lowers = array(); + + /** + * upper() cache. + * + * @var array + */ + static protected $_uppers = array(); + + /** + * Converts a string from one charset to another. + * + * Uses the iconv or the mbstring extensions. + * The original string is returned if conversion failed or none + * of the extensions were available. + * + * @param mixed $input The data to be converted. If $input is an an + * array, the array's values get converted + * recursively. + * @param string $from The string's current charset. + * @param string $to The charset to convert the string to. + * @param boolean $force Force conversion? + * + * @return mixed The converted input data. + */ + static public function convertCharset($input, $from, $to, $force = false) + { + /* Don't bother converting numbers. */ + if (is_numeric($input)) { + return $input; + } + + /* If the from and to character sets are identical, return now. */ + if (!$force && $from == $to) { + return $input; + } + $from = self::lower($from); + $to = self::lower($to); + if (!$force && $from == $to) { + return $input; + } + + if (is_array($input)) { + $tmp = array(); + reset($input); + while (list($key, $val) = each($input)) { + $tmp[self::_convertCharset($key, $from, $to)] = self::convertCharset($val, $from, $to, $force); + } + return $tmp; + } + + if (is_object($input)) { + // PEAR_Error/Exception objects are almost guaranteed to contain + // recursion, which will cause a segfault in PHP. We should never + // reach this line, but add a check. + if (($input instanceof Exception) || + ($input instanceof PEAR_Error)) { + return ''; + } + + $input = Horde_Util::cloneObject($input); + $vars = get_object_vars($input); + while (list($key, $val) = each($vars)) { + $input->$key = self::convertCharset($val, $from, $to, $force); + } + return $input; + } + + if (!is_string($input)) { + return $input; + } + + return self::_convertCharset($input, $from, $to); + } + + /** + * Internal function used to do charset conversion. + * + * @param string $input See self::convertCharset(). + * @param string $from See self::convertCharset(). + * @param string $to See self::convertCharset(). + * + * @return string The converted string. + */ + static protected function _convertCharset($input, $from, $to) + { + /* Use utf8_[en|de]code() if possible and if the string isn't too + * large (less than 16 MB = 16 * 1024 * 1024 = 16777216 bytes) - these + * functions use more memory. */ + if (Horde_Util::extensionExists('xml') && + ((strlen($input) < 16777216) || + !Horde_Util::extensionExists('iconv') || + !Horde_Util::extensionExists('mbstring'))) { + if (($to == 'utf-8') && + in_array($from, array('iso-8859-1', 'us-ascii', 'utf-8'))) { + return utf8_encode($input); + } + + if (($from == 'utf-8') && + in_array($to, array('iso-8859-1', 'us-ascii', 'utf-8'))) { + return utf8_decode($input); + } + } + + /* Try UTF7-IMAP conversions. */ + if (($from == 'utf7-imap') || ($to == 'utf7-imap')) { + try { + if ($from == 'utf7-imap') { + return self::convertCharset(Horde_Imap_Client_Utf7imap::Utf7ImapToUtf8($input), 'UTF-8', $to); + } else { + if ($from == 'utf-8') { + $conv = $input; + } else { + $conv = self::convertCharset($input, $from, 'UTF-8'); + } + return Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($conv); + } + } catch (Horde_Imap_Client_Exception $e) { + return $input; + } + } + + /* Try iconv with transliteration. */ + if (Horde_Util::extensionExists('iconv')) { + unset($php_errormsg); + ini_set('track_errors', 1); + $out = @iconv($from, $to . '//TRANSLIT', $input); + $errmsg = isset($php_errormsg); + ini_restore('track_errors'); + if (!$errmsg) { + return $out; + } + } + + /* Try mbstring. */ + if (Horde_Util::extensionExists('mbstring')) { + $out = @mb_convert_encoding($input, $to, self::_mbstringCharset($from)); + if (!empty($out)) { + return $out; + } + } + + return $input; + } + + /** + * Makes a string lowercase. + * + * @param string $string The string to be converted. + * @param boolean $locale If true the string will be converted based on + * a given charset, locale independent else. + * @param string $charset If $locale is true, the charset to use when + * converting. + * + * @return string The string with lowercase characters. + */ + static public function lower($string, $locale = false, $charset = null) + { + if ($locale) { + if (Horde_Util::extensionExists('mbstring')) { + if (is_null($charset)) { + throw new InvalidArgumentException('$charset argument must not be null'); + } + $ret = @mb_strtolower($string, self::_mbstringCharset($charset)); + if (!empty($ret)) { + return $ret; + } + } + return strtolower($string); + } + + if (!isset(self::$_lowers[$string])) { + $language = setlocale(LC_CTYPE, 0); + setlocale(LC_CTYPE, 'C'); + self::$_lowers[$string] = strtolower($string); + setlocale(LC_CTYPE, $language); + } + + return self::$_lowers[$string]; + } + + /** + * Makes a string uppercase. + * + * @param string $string The string to be converted. + * @param boolean $locale If true the string will be converted based on a + * given charset, locale independent else. + * @param string $charset If $locale is true, the charset to use when + * converting. If not provided the current charset. + * + * @return string The string with uppercase characters. + */ + static public function upper($string, $locale = false, $charset = null) + { + if ($locale) { + if (Horde_Util::extensionExists('mbstring')) { + if (is_null($charset)) { + throw new InvalidArgumentException('$charset argument must not be null'); + } + $ret = @mb_strtoupper($string, self::_mbstringCharset($charset)); + if (!empty($ret)) { + return $ret; + } + } + return strtoupper($string); + } + + if (!isset(self::$_uppers[$string])) { + $language = setlocale(LC_CTYPE, 0); + setlocale(LC_CTYPE, 'C'); + self::$_uppers[$string] = strtoupper($string); + setlocale(LC_CTYPE, $language); + } + + return self::$_uppers[$string]; + } + + /** + * Returns a string with the first letter capitalized if it is + * alphabetic. + * + * @param string $string The string to be capitalized. + * @param boolean $locale If true the string will be converted based on a + * given charset, locale independent else. + * @param string $charset The charset to use, defaults to current charset. + * + * @return string The capitalized string. + */ + static public function ucfirst($string, $locale = false, $charset = null) + { + if ($locale) { + if (is_null($charset)) { + throw new InvalidArgumentException('$charset argument must not be null'); + } + $first = self::substr($string, 0, 1, $charset); + if (self::isAlpha($first, $charset)) { + $string = self::upper($first, true, $charset) . self::substr($string, 1, null, $charset); + } + } else { + $string = self::upper(substr($string, 0, 1), false) . substr($string, 1); + } + + return $string; + } + + /** + * Returns a string with the first letter of each word capitalized if it is + * alphabetic. + * + * Sentences are splitted into words at whitestrings. + * + * @param string $string The string to be capitalized. + * @param boolean $locale If true the string will be converted based on a + * given charset, locale independent else. + * @param string $charset The charset to use, defaults to current charset. + * + * @return string The capitalized string. + */ + static public function ucwords($string, $locale = false, $charset = null) + { + $words = preg_split('/(\s+)/', $string, -1, PREG_SPLIT_DELIM_CAPTURE); + for ($i = 0, $c = count($words); $i < $c; $i += 2) { + $words[$i] = self::ucfirst($words[$i], $locale, $charset); + } + return implode('', $words); + } + + /** + * Returns part of a string. + * + * @param string $string The string to be converted. + * @param integer $start The part's start position, zero based. + * @param integer $length The part's length. + * @param string $charset The charset to use when calculating the part's + * position and length, defaults to current + * charset. + * + * @return string The string's part. + */ + static public function substr($string, $start, $length = null, + $charset = 'UTF-8') + { + if (is_null($length)) { + $length = self::length($string, $charset) - $start; + } + + if ($length == 0) { + return ''; + } + + /* Try mbstring. */ + if (Horde_Util::extensionExists('mbstring')) { + $ret = @mb_substr($string, $start, $length, self::_mbstringCharset($charset)); + + /* mb_substr() returns empty string on failure. */ + if (strlen($ret)) { + return $ret; + } + } + + /* Try iconv. */ + if (Horde_Util::extensionExists('iconv')) { + $ret = @iconv_substr($string, $start, $length, $charset); + + /* iconv_substr() returns false on failure. */ + if ($ret !== false) { + return $ret; + } + } + + return substr($string, $start, $length); + } + + /** + * Returns the character (not byte) length of a string. + * + * @param string $string The string to return the length of. + * @param string $charset The charset to use when calculating the string's + * length. + * + * @return integer The string's length. + */ + static public function length($string, $charset = 'UTF-8') + { + $charset = self::lower($charset); + + if ($charset == 'utf-8' || $charset == 'utf8') { + return strlen(utf8_decode($string)); + } + + if (Horde_Util::extensionExists('mbstring')) { + $ret = @mb_strlen($string, self::_mbstringCharset($charset)); + if (!empty($ret)) { + return $ret; + } + } + + return strlen($string); + } + + /** + * Returns the numeric position of the first occurrence of $needle + * in the $haystack string. + * + * @param string $haystack The string to search through. + * @param string $needle The string to search for. + * @param integer $offset Allows to specify which character in haystack + * to start searching. + * @param string $charset The charset to use when searching for the + * $needle string. + * + * @return integer The position of first occurrence. + */ + static public function pos($haystack, $needle, $offset = 0, + $charset = 'UTF-8') + { + if (Horde_Util::extensionExists('mbstring')) { + $track_errors = ini_set('track_errors', 1); + $ret = @mb_strpos($haystack, $needle, $offset, self::_mbstringCharset($charset)); + ini_set('track_errors', $track_errors); + if (!isset($php_errormsg)) { + return $ret; + } + } + + return strpos($haystack, $needle, $offset); + } + + /** + * Returns the numeric position of the last occurrence of $needle + * in the $haystack string. + * + * @param string $haystack The string to search through. + * @param string $needle The string to search for. + * @param integer $offset Allows to specify which character in haystack + * to start searching. + * @param string $charset The charset to use when searching for the + * $needle string. + * + * @return integer The position of first occurrence. + */ + static public function rpos($haystack, $needle, $offset = 0, + $charset = 'UTF-8') + { + if (Horde_Util::extensionExists('mbstring')) { + $track_errors = ini_set('track_errors', 1); + $ret = @mb_strrpos($haystack, $needle, $offset, self::_mbstringCharset($charset)); + ini_set('track_errors', $track_errors); + if (!isset($php_errormsg)) { + return $ret; + } + } + + return strrpos($haystack, $needle, $offset); + } + + /** + * Returns a string padded to a certain length with another string. + * This method behaves exactly like str_pad() but is multibyte safe. + * + * @param string $input The string to be padded. + * @param integer $length The length of the resulting string. + * @param string $pad The string to pad the input string with. Must + * be in the same charset like the input string. + * @param const $type The padding type. One of STR_PAD_LEFT, + * STR_PAD_RIGHT, or STR_PAD_BOTH. + * @param string $charset The charset of the input and the padding + * strings. + * + * @return string The padded string. + */ + static public function pad($input, $length, $pad = ' ', + $type = STR_PAD_RIGHT, $charset = 'UTF-8') + { + $mb_length = self::length($input, $charset); + $sb_length = strlen($input); + $pad_length = self::length($pad, $charset); + + /* Return if we already have the length. */ + if ($mb_length >= $length) { + return $input; + } + + /* Shortcut for single byte strings. */ + if ($mb_length == $sb_length && $pad_length == strlen($pad)) { + return str_pad($input, $length, $pad, $type); + } + + switch ($type) { + case STR_PAD_LEFT: + $left = $length - $mb_length; + $output = self::substr(str_repeat($pad, ceil($left / $pad_length)), 0, $left, $charset) . $input; + break; + + case STR_PAD_BOTH: + $left = floor(($length - $mb_length) / 2); + $right = ceil(($length - $mb_length) / 2); + $output = self::substr(str_repeat($pad, ceil($left / $pad_length)), 0, $left, $charset) . + $input . + self::substr(str_repeat($pad, ceil($right / $pad_length)), 0, $right, $charset); + break; + + case STR_PAD_RIGHT: + $right = $length - $mb_length; + $output = $input . self::substr(str_repeat($pad, ceil($right / $pad_length)), 0, $right, $charset); + break; + } + + return $output; + } + + /** + * Wraps the text of a message. + * + * @param string $string String containing the text to wrap. + * @param integer $width Wrap the string at this number of + * characters. + * @param string $break Character(s) to use when breaking lines. + * @param boolean $cut Whether to cut inside words if a line + * can't be wrapped. + * @param boolean $line_folding Whether to apply line folding rules per + * RFC 822 or similar. The correct break + * characters including leading whitespace + * have to be specified too. + * + * @return string String containing the wrapped text. + */ + static public function wordwrap($string, $width = 75, $break = "\n", + $cut = false, $line_folding = false) + { + $wrapped = ''; + + while (self::length($string, 'UTF-8') > $width) { + $line = self::substr($string, 0, $width, 'UTF-8'); + $string = self::substr($string, self::length($line, 'UTF-8'), null, 'UTF-8'); + + // Make sure we didn't cut a word, unless we want hard breaks + // anyway. + if (!$cut && preg_match('/^(.+?)((\s|\r?\n).*)/us', $string, $match)) { + $line .= $match[1]; + $string = $match[2]; + } + + // Wrap at existing line breaks. + if (preg_match('/^(.*?)(\r?\n)(.*)$/su', $line, $match)) { + $wrapped .= $match[1] . $match[2]; + $string = $match[3] . $string; + continue; + } + + // Wrap at the last colon or semicolon followed by a whitespace if + // doing line folding. + if ($line_folding && + preg_match('/^(.*?)(;|:)(\s+.*)$/u', $line, $match)) { + $wrapped .= $match[1] . $match[2] . $break; + $string = $match[3] . $string; + continue; + } + + // Wrap at the last whitespace of $line. + $sub = $line_folding + ? '(.+[^\s])' + : '(.*)'; + + if (preg_match('/^' . $sub . '(\s+)(.*)$/u', $line, $match)) { + $wrapped .= $match[1] . $break; + $string = ($line_folding ? $match[2] : '') . $match[3] . $string; + continue; + } + + // Hard wrap if necessary. + if ($cut) { + $wrapped .= $line . $break; + continue; + } + + $wrapped .= $line; + } + + return $wrapped . $string; + } + + /** + * Wraps the text of a message. + * + * @param string $text String containing the text to wrap. + * @param integer $length Wrap $text at this number of characters. + * @param string $break_char Character(s) to use when breaking lines. + * @param boolean $quote Ignore lines that are wrapped with the '>' + * character (RFC 2646)? If true, we don't + * remove any padding whitespace at the end of + * the string. + * + * @return string String containing the wrapped text. + */ + static public function wrap($text, $length = 80, $break_char = "\n", + $quote = false) + { + $paragraphs = array(); + + foreach (preg_split('/\r?\n/', $text) as $input) { + if ($quote && (strpos($input, '>') === 0)) { + $line = $input; + } else { + /* We need to handle the Usenet-style signature line + * separately; since the space after the two dashes is + * REQUIRED, we don't want to trim the line. */ + if ($input != '-- ') { + $input = rtrim($input); + } + $line = self::wordwrap($input, $length, $break_char); + } + + $paragraphs[] = $line; + } + + return implode($break_char, $paragraphs); + } + + /** + * Return a truncated string, suitable for notifications. + * + * @param string $text The original string. + * @param integer $length The maximum length. + * + * @return string The truncated string, if longer than $length. + */ + static public function truncate($text, $length = 100) + { + return (self::length($text) > $length) + ? rtrim(self::substr($text, 0, $length - 3)) . '...' + : $text; + } + + /** + * Return an abbreviated string, with characters in the middle of the + * excessively long string replaced by '...'. + * + * @param string $text The original string. + * @param integer $length The length at which to abbreviate. + * + * @return string The abbreviated string, if longer than $length. + */ + static public function abbreviate($text, $length = 20) + { + return (self::length($text) > $length) + ? rtrim(self::substr($text, 0, round(($length - 3) / 2))) . '...' . ltrim(self::substr($text, (($length - 3) / 2) * -1)) + : $text; + } + + /** + * Returns the common leading part of two strings. + * + * @param string $str1 A string. + * @param string $str2 Another string. + * + * @return string The start of $str1 and $str2 that is identical in both. + */ + static public function common($str1, $str2) + { + for ($result = '', $i = 0; + isset($str1[$i]) && isset($str2[$i]) && $str1[$i] == $str2[$i]; + $i++) { + $result .= $str1[$i]; + } + return $result; + } + + /** + * Returns true if the every character in the parameter is an alphabetic + * character. + * + * @param string $string The string to test. + * @param string $charset The charset to use when testing the string. + * + * @return boolean True if the parameter was alphabetic only. + */ + static public function isAlpha($string, $charset) + { + if (!Horde_Util::extensionExists('mbstring')) { + return ctype_alpha($string); + } + + $charset = self::_mbstringCharset($charset); + $old_charset = mb_regex_encoding(); + + if ($charset != $old_charset) { + @mb_regex_encoding($charset); + } + $alpha = !@mb_ereg_match('[^[:alpha:]]', $string); + if ($charset != $old_charset) { + @mb_regex_encoding($old_charset); + } + + return $alpha; + } + + /** + * Returns true if ever character in the parameter is a lowercase letter in + * the current locale. + * + * @param string $string The string to test. + * @param string $charset The charset to use when testing the string. + * + * @return boolean True if the parameter was lowercase. + */ + static public function isLower($string, $charset) + { + return ((self::lower($string, true, $charset) === $string) && + self::isAlpha($string, $charset)); + } + + /** + * Returns true if every character in the parameter is an uppercase letter + * in the current locale. + * + * @param string $string The string to test. + * @param string $charset The charset to use when testing the string. + * + * @return boolean True if the parameter was uppercase. + */ + static public function isUpper($string, $charset) + { + return ((self::upper($string, true, $charset) === $string) && + self::isAlpha($string, $charset)); + } + + /** + * Performs a multibyte safe regex match search on the text provided. + * + * @param string $text The text to search. + * @param array $regex The regular expressions to use, without perl + * regex delimiters (e.g. '/' or '|'). + * @param string $charset The character set of the text. + * + * @return array The matches array from the first regex that matches. + */ + static public function regexMatch($text, $regex, $charset = null) + { + if (!empty($charset)) { + $regex = self::convertCharset($regex, $charset, 'utf-8'); + $text = self::convertCharset($text, $charset, 'utf-8'); + } + + $matches = array(); + foreach ($regex as $val) { + if (preg_match('/' . $val . '/u', $text, $matches)) { + break; + } + } + + if (!empty($charset)) { + $matches = self::convertCharset($matches, 'utf-8', $charset); + } + + return $matches; + } + + /** + * Check to see if a string is valid UTF-8. + * + * @since 1.1.0 + * + * @param string $text The text to check. + * + * @return boolean True if valid UTF-8. + */ + static public function validUtf8($text) + { + /* Regex from: + * http://stackoverflow.com/questions/1523460/ensuring-valid-utf-8-in-php + */ + return preg_match('/^(?: + [\x09\x0A\x0D\x20-\x7E] # ASCII + | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 + )*$/xs', $text); + } + + /** + * Workaround charsets that don't work with mbstring functions. + * + * @param string $charset The original charset. + * + * @return string The charset to use with mbstring functions. + */ + static protected function _mbstringCharset($charset) + { + /* mbstring functions do not handle the 'ks_c_5601-1987' & + * 'ks_c_5601-1989' charsets. However, these charsets are used, for + * example, by various versions of Outlook to send Korean characters. + * Use UHC (CP949) encoding instead. See, e.g., + * http://lists.w3.org/Archives/Public/ietf-charsets/2001AprJun/0030.html */ + if ($charset == 'UTF-8' || $charset == 'utf-8') { + return $charset; + } + if (in_array(self::lower($charset), array('ks_c_5601-1987', 'ks_c_5601-1989'))) { + $charset = 'UHC'; + } + + return $charset; + } + +} diff --git a/Upload/inc/3rdparty/diff/Diff/ThreeWay.php b/Upload/inc/3rdparty/diff/Diff/ThreeWay.php new file mode 100644 index 0000000..83560ff --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/ThreeWay.php @@ -0,0 +1,150 @@ + + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_ThreeWay +{ + /** + * Array of changes. + * + * @var array + */ + protected $_edits; + + /** + * Conflict counter. + * + * @var integer + */ + protected $_conflictingBlocks = 0; + + /** + * Computes diff between 3 sequences of strings. + * + * @param array $orig The original lines to use. + * @param array $final1 The first version to compare to. + * @param array $final2 The second version to compare to. + */ + public function __construct($orig, $final1, $final2) + { + if (extension_loaded('xdiff')) { + $engine = new Horde_Text_Diff_Engine_Xdiff(); + } else { + $engine = new Horde_Text_Diff_Engine_Native(); + } + + $this->_edits = $this->_diff3($engine->diff($orig, $final1), + $engine->diff($orig, $final2)); + } + + /** + */ + public function mergedOutput($label1 = false, $label2 = false) + { + $lines = array(); + foreach ($this->_edits as $edit) { + if ($edit->isConflict()) { + /* FIXME: this should probably be moved somewhere else. */ + $lines = array_merge($lines, + array('<<<<<<<' . ($label1 ? ' ' . $label1 : '')), + $edit->final1, + array("======="), + $edit->final2, + array('>>>>>>>' . ($label2 ? ' ' . $label2 : ''))); + $this->_conflictingBlocks++; + } else { + $lines = array_merge($lines, $edit->merged()); + } + } + + return $lines; + } + + /** + */ + protected function _diff3($edits1, $edits2) + { + $edits = array(); + $bb = new Horde_Text_Diff_ThreeWay_BlockBuilder(); + + $e1 = current($edits1); + $e2 = current($edits2); + while ($e1 || $e2) { + if ($e1 && $e2 && + $e1 instanceof Horde_Text_Diff_Op_Copy && + $e2 instanceof Horde_Text_Diff_Op_Copy) { + /* We have copy blocks from both diffs. This is the (only) + * time we want to emit a diff3 copy block. Flush current + * diff3 diff block, if any. */ + if ($edit = $bb->finish()) { + $edits[] = $edit; + } + + $ncopy = min($e1->norig(), $e2->norig()); + assert($ncopy > 0); + $edits[] = new Horde_Text_Diff_ThreeWay_Op_Copy(array_slice($e1->orig, 0, $ncopy)); + + if ($e1->norig() > $ncopy) { + array_splice($e1->orig, 0, $ncopy); + array_splice($e1->final, 0, $ncopy); + } else { + $e1 = next($edits1); + } + + if ($e2->norig() > $ncopy) { + array_splice($e2->orig, 0, $ncopy); + array_splice($e2->final, 0, $ncopy); + } else { + $e2 = next($edits2); + } + } else { + if ($e1 && $e2) { + if ($e1->orig && $e2->orig) { + $norig = min($e1->norig(), $e2->norig()); + $orig = array_splice($e1->orig, 0, $norig); + array_splice($e2->orig, 0, $norig); + $bb->input($orig); + } + + if ($e1 instanceof Horde_Text_Diff_Op_Copy) { + $bb->out1(array_splice($e1->final, 0, $norig)); + } + + if ($e2 instanceof Horde_Text_Diff_Op_Copy) { + $bb->out2(array_splice($e2->final, 0, $norig)); + } + } + + if ($e1 && ! $e1->orig) { + $bb->out1($e1->final); + $e1 = next($edits1); + } + if ($e2 && ! $e2->orig) { + $bb->out2($e2->final); + $e2 = next($edits2); + } + } + } + + if ($edit = $bb->finish()) { + $edits[] = $edit; + } + + return $edits; + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/ThreeWay/BlockBuilder.php b/Upload/inc/3rdparty/diff/Diff/ThreeWay/BlockBuilder.php new file mode 100644 index 0000000..639c59e --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/ThreeWay/BlockBuilder.php @@ -0,0 +1,71 @@ + + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_ThreeWay_BlockBuilder +{ + public function __construct() + { + $this->_init(); + } + + public function input($lines) + { + if ($lines) { + $this->_append($this->orig, $lines); + } + } + + public function out1($lines) + { + if ($lines) { + $this->_append($this->final1, $lines); + } + } + + public function out2($lines) + { + if ($lines) { + $this->_append($this->final2, $lines); + } + } + + public function isEmpty() + { + return !$this->orig && !$this->final1 && !$this->final2; + } + + public function finish() + { + if ($this->isEmpty()) { + return false; + } else { + $edit = new Horde_Text_Diff_ThreeWay_Op_Base($this->orig, $this->final1, $this->final2); + $this->_init(); + return $edit; + } + } + + protected function _init() + { + $this->orig = $this->final1 = $this->final2 = array(); + } + + protected function _append(&$array, $lines) + { + array_splice($array, sizeof($array), 0, $lines); + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/ThreeWay/Op/Base.php b/Upload/inc/3rdparty/diff/Diff/ThreeWay/Op/Base.php new file mode 100644 index 0000000..c10466c --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/ThreeWay/Op/Base.php @@ -0,0 +1,48 @@ + + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_ThreeWay_Op_Base +{ + public function __construct($orig = false, $final1 = false, $final2 = false) + { + $this->orig = $orig ? $orig : array(); + $this->final1 = $final1 ? $final1 : array(); + $this->final2 = $final2 ? $final2 : array(); + } + + public function merged() + { + if (!isset($this->_merged)) { + if ($this->final1 === $this->final2) { + $this->_merged = &$this->final1; + } elseif ($this->final1 === $this->orig) { + $this->_merged = &$this->final2; + } elseif ($this->final2 === $this->orig) { + $this->_merged = &$this->final1; + } else { + $this->_merged = false; + } + } + + return $this->_merged; + } + + public function isConflict() + { + return $this->merged() === false; + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/ThreeWay/Op/Copy.php b/Upload/inc/3rdparty/diff/Diff/ThreeWay/Op/Copy.php new file mode 100644 index 0000000..15f7a83 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/ThreeWay/Op/Copy.php @@ -0,0 +1,36 @@ + + */ + +// Disallow direct access to this file for security reasons +if(!defined("IN_MYBB")) +{ + die("Direct initialization of this file is not allowed.

    Please make sure IN_MYBB is defined."); +} + +class Horde_Text_Diff_ThreeWay_Op_Copy extends Horde_Text_Diff_ThreeWay_Op_Base +{ + public function __construct($lines = false) + { + $this->orig = $lines ? $lines : array(); + $this->final1 = &$this->orig; + $this->final2 = &$this->orig; + } + + public function merged() + { + return $this->orig; + } + + public function isConflict() + { + return false; + } +} diff --git a/Upload/inc/3rdparty/diff/Diff/ThreeWay/Op/index.html b/Upload/inc/3rdparty/diff/Diff/ThreeWay/Op/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/ThreeWay/Op/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/3rdparty/diff/Diff/ThreeWay/index.html b/Upload/inc/3rdparty/diff/Diff/ThreeWay/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/ThreeWay/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/3rdparty/diff/Diff/index.html b/Upload/inc/3rdparty/diff/Diff/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/3rdparty/diff/Diff/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/3rdparty/diff/index.html b/Upload/inc/3rdparty/diff/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/3rdparty/diff/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/3rdparty/index.html b/Upload/inc/3rdparty/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/3rdparty/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/3rdparty/json/index.html b/Upload/inc/3rdparty/json/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/3rdparty/json/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/3rdparty/json/json.php b/Upload/inc/3rdparty/json/json.php new file mode 100644 index 0000000..3550fd4 --- /dev/null +++ b/Upload/inc/3rdparty/json/json.php @@ -0,0 +1,816 @@ + + * @author Matt Knapp + * @author Brett Stimmerman + * @copyright 2005 Michal Migurski + * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_SLICE', 1); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_STR', 2); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_ARR', 3); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_OBJ', 4); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_CMT', 5); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_LOOSE_TYPE', 16); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_SUPPRESS_ERRORS', 32); + +/** + * Converts to and from JSON format. + * + * Brief example of use: + * + * + * // create a new instance of Services_JSON + * $json = new Services_JSON(); + * + * // convert a complexe value to JSON notation, and send it to the browser + * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); + * $output = $json->encode($value); + * + * print($output); + * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] + * + * // accept incoming POST data, assumed to be in JSON notation + * $input = file_get_contents('php://input', 1000000); + * $value = $json->decode($input); + * + */ +class Services_JSON +{ + /** + * constructs a new JSON instance + * + * @param int $use object behavior flags; combine with boolean-OR + * + * possible values: + * - SERVICES_JSON_LOOSE_TYPE: loose typing. + * "{...}" syntax creates associative arrays + * instead of objects in decode(). + * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. + * Values which can't be encoded (e.g. resources) + * appear as NULL instead of throwing errors. + * By default, a deeply-nested resource will + * bubble up with an error, so all return values + * from encode() should be checked with isError() + */ + function Services_JSON($use = 0) + { + $this->use = $use; + } + + /** + * convert a string from one UTF-16 char to one UTF-8 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf16 UTF-16 character + * @return string UTF-8 character + * @access private + */ + function utf162utf8($utf16) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + } + + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch(true) { + case ((0x7F & $bytes) == $bytes): + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) + . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) + . chr(0x80 | (($bytes >> 6) & 0x3F)) + . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + function utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + function encode($var) + { + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + $properties = array_map(array($this, 'name_value'), + array_keys($var), + array_values($var)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + } + + // treat it like a regular array + $elements = array_map(array($this, 'encode'), $var); + + foreach($elements as $element) { + if(Services_JSON::isError($element)) { + return $element; + } + } + + return '[' . join(',', $elements) . ']'; + + case 'object': + $vars = get_object_vars($var); + + $properties = array_map(array($this, 'name_value'), + array_keys($vars), + array_values($vars)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + + default: + return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) + ? 'null' + : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + function name_value($name, $value) + { + $encoded_value = $this->encode($value); + + if(Services_JSON::isError($encoded_value)) { + return $encoded_value; + } + + return $this->encode((string)$name) . ':' . $encoded_value; + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to Services_JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) { + case 'true': + return true; + + case 'false': + return false; + + case 'null': + return null; + + default: + $m = array(); + + if (is_numeric($str)) { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) + ? (integer)$str + : (float)$str; + + } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = substr($str, 0, 1); + $chrs = substr($str, 1, -1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = substr($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { + $utf8 .= $chrs{++$c}; + } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) + . chr(hexdec(substr($chrs, ($c + 4), 2))); + $utf8 .= $this->utf162utf8($utf16); + $c += 5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 6); + $c += 5; + break; + + } + + } + + return $utf8; + + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { + // array, or object notation + + if ($str{0} == '[') { + $stk = array(SERVICES_JSON_IN_ARR); + $arr = array(); + } else { + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = array(); + } else { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => SERVICES_JSON_SLICE, + 'where' => 0, + 'delim' => false)); + + $chrs = substr($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') { + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } else { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = substr($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = substr($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + $parts = array(); + + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } + + } + + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { + // found a quote, and we are not inside a string + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); + + } elseif (($chrs{$c} == $top['delim']) && + ($top['what'] == SERVICES_JSON_IN_STR) && + ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) { + // found a quote, we're in a string, and it's not escaped + // we know that it's not escaped becase there is _not_ an + // odd number of backslashes at the end of the string so far + array_pop($stk); + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '[') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); + + } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '{') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); + + } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($substr_chrs_c_2 == '/*') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); + + } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { + // found a comment end, and we're in one now + array_pop($stk); + $c++; + + for ($i = $top['where']; $i <= $c; ++$i) + $chrs = substr_replace($chrs, ' ', $i, 1); + + //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + + } + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + return $obj; + + } + + } + } + } + + /** + * @todo Ultimately, this should just call PEAR::isError() + */ + function isError($data, $code = null) + { + if (class_exists('pear')) { + return PEAR::isError($data, $code); + } elseif (is_object($data) && (get_class($data) == 'services_json_error' || + is_subclass_of($data, 'services_json_error'))) { + return true; + } + + return false; + } +} + +if (class_exists('PEAR_Error')) { + + class Services_JSON_Error extends PEAR_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + parent::PEAR_Error($message, $code, $mode, $options, $userinfo); + } + } + +} else { + + /** + * @todo Ultimately, this class shall be descended from PEAR_Error + */ + class Services_JSON_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + + } + } + +} + +function json_encode($var) +{ + $JSON = new Services_JSON; + return $JSON->encode($var); +} + +function json_decode($var) +{ + $JSON = new Services_JSON; + return $JSON->decode($var); +} \ No newline at end of file diff --git a/Upload/inc/adminfunctions_templates.php b/Upload/inc/adminfunctions_templates.php new file mode 100644 index 0000000..d9e422a --- /dev/null +++ b/Upload/inc/adminfunctions_templates.php @@ -0,0 +1,108 @@ +\'0\''; + + $template_sets = array(-2, -1); + + // Select all global with that title if not working on a specific template set + if($sid !== false) + { + $sqlwhere = '=\''.(int)$sid.'\''; + + $query = $db->simple_select("templates", "tid, template", "title = '".$db->escape_string($title)."' AND sid='-1'"); + while($template = $db->fetch_array($query)) + { + // Update the template if there is a replacement term or a change + $new_template = preg_replace($find, $replace, $template['template'], $limit); + if($new_template == $template['template']) + { + continue; + } + + // The template is a custom template. Replace as normal. + $updated_template = array( + "template" => $db->escape_string($new_template) + ); + $db->update_query("templates", $updated_template, "tid='{$template['tid']}'"); + } + } + + // Select all other modified templates with that title + $query = $db->simple_select("templates", "tid, sid, template", "title = '".$db->escape_string($title)."' AND sid{$sqlwhere}"); + while($template = $db->fetch_array($query)) + { + // Keep track of which templates sets have a modified version of this template already + $template_sets[] = $template['sid']; + + // Update the template if there is a replacement term or a change + $new_template = preg_replace($find, $replace, $template['template'], $limit); + if($new_template == $template['template']) + { + continue; + } + + // The template is a custom template. Replace as normal. + $updated_template = array( + "template" => $db->escape_string($new_template) + ); + $db->update_query("templates", $updated_template, "tid='{$template['tid']}'"); + + $return = true; + } + + // Add any new templates if we need to and are allowed to + if($autocreate != 0) + { + // Select our master template with that title + $query = $db->simple_select("templates", "title, template", "title='".$db->escape_string($title)."' AND sid='-2'", array('limit' => 1)); + $master_template = $db->fetch_array($query); + $master_template['new_template'] = preg_replace($find, $replace, $master_template['template'], $limit); + + if($master_template['new_template'] != $master_template['template']) + { + // Update the rest of our template sets that are currently inheriting this template from our master set + $query = $db->simple_select("templatesets", "sid", "sid NOT IN (".implode(',', $template_sets).") AND sid{$sqlwhere}"); + while($template = $db->fetch_array($query)) + { + $insert_template = array( + "title" => $db->escape_string($master_template['title']), + "template" => $db->escape_string($master_template['new_template']), + "sid" => $template['sid'], + "version" => $mybb->version_code, + "status" => '', + "dateline" => TIME_NOW + ); + $db->insert_query("templates", $insert_template); + + $return = true; + } + } + } + + return $return; +} diff --git a/Upload/inc/cachehandlers/apc.php b/Upload/inc/cachehandlers/apc.php new file mode 100644 index 0000000..315d09f --- /dev/null +++ b/Upload/inc/cachehandlers/apc.php @@ -0,0 +1,108 @@ +trigger_generic_error("apc_load_error"); + die; + } + } + + return false; + } + + /** + * Connect and initialize this handler. + * + * @return boolean True if successful, false on failure + */ + function connect() + { + global $mybb; + + // Set a unique identifier for all queries in case other forums on this server also use this cache handler + $this->unique_id = md5(MYBB_ROOT); + + return true; + } + + /** + * Connect and initialize this handler. + * + * @return boolean True if successful, false on failure + */ + function fetch($name, $hard_refresh=false) + { + if(apc_exists($this->unique_id."_".$name)) + { + $data = apc_fetch($this->unique_id."_".$name); + return my_unserialize($data); + } + + return false; + } + + /** + * Write an item to the cache. + * + * @param string The name of the cache + * @param mixed The data to write to the cache item + * @return boolean True on success, false on failure + */ + function put($name, $contents) + { + $status = apc_store($this->unique_id."_".$name, serialize($contents)); + return $status; + } + + /** + * Delete a cache + * + * @param string The name of the cache + * @return boolean True on success, false on failure + */ + function delete($name) + { + return apc_delete($this->unique_id."_".$name); + } + + /** + * Disconnect from the cache + */ + function disconnect() + { + return true; + } + + function size_of($name) + { + global $lang; + + return $lang->na; + } +} diff --git a/Upload/inc/cachehandlers/disk.php b/Upload/inc/cachehandlers/disk.php new file mode 100644 index 0000000..db8c5f2 --- /dev/null +++ b/Upload/inc/cachehandlers/disk.php @@ -0,0 +1,133 @@ +cache[$name]) || $hard_refresh == true) + { + @include(MYBB_ROOT."/cache/{$name}.php"); + } + else + { + @include_once(MYBB_ROOT."/cache/{$name}.php"); + } + + // Return data + return $$name; + } + + /** + * Write an item to the cache. + * + * @param string The name of the cache + * @param mixed The data to write to the cache item + * @return boolean True on success, false on failure + */ + function put($name, $contents) + { + global $mybb; + if(!is_writable(MYBB_ROOT."cache")) + { + $mybb->trigger_generic_error("cache_no_write"); + return false; + } + + $cache_file = fopen(MYBB_ROOT."cache/{$name}.php", "w") or $mybb->trigger_generic_error("cache_no_write"); + flock($cache_file, LOCK_EX); + $cache_contents = ""; + fwrite($cache_file, $cache_contents); + flock($cache_file, LOCK_UN); + fclose($cache_file); + + return true; + } + + /** + * Delete a cache + * + * @param string The name of the cache + * @return boolean True on success, false on failure + */ + function delete($name) + { + return @unlink(MYBB_ROOT."/cache/{$name}.php"); + } + + /** + * Disconnect from the cache + */ + function disconnect() + { + return true; + } + + /** + * Select the size of the disk cache + * + * @param string The name of the cache + * @return integer the size of the disk cache + */ + function size_of($name='') + { + if($name != '') + { + return @filesize(MYBB_ROOT."/cache/{$name}.php"); + } + else + { + $total = 0; + $dir = opendir(MYBB_ROOT."/cache"); + while(($file = readdir($dir)) !== false) + { + if($file == "." || $file == ".." || $file == ".svn" || !is_file(MYBB_ROOT."/cache/{$file}")) + { + continue; + } + + $total += filesize(MYBB_ROOT."/cache/{$file}"); + } + return $total; + } + } +} diff --git a/Upload/inc/cachehandlers/eaccelerator.php b/Upload/inc/cachehandlers/eaccelerator.php new file mode 100644 index 0000000..adae3c1 --- /dev/null +++ b/Upload/inc/cachehandlers/eaccelerator.php @@ -0,0 +1,112 @@ +trigger_generic_error("eaccelerator_load_error"); + die; + } + } + return false; + } + + /** + * Connect and initialize this handler. + * + * @return boolean True if successful, false on failure + */ + function connect() + { + global $mybb; + + // Set a unique identifier for all queries in case other forums on this server also use this cache handler + $this->unique_id = md5(MYBB_ROOT); + + return true; + } + + /** + * Retrieve an item from the cache. + * + * @param string The name of the cache + * @param boolean True if we should do a hard refresh + * @return mixed Cache data if successful, false if failure + */ + + function fetch($name, $hard_refresh=false) + { + $data = eaccelerator_get($this->unique_id."_".$name); + if($data === false) + { + return false; + } + + return my_unserialize($data); + } + + /** + * Write an item to the cache. + * + * @param string The name of the cache + * @param mixed The data to write to the cache item + * @return boolean True on success, false on failure + */ + function put($name, $contents) + { + eaccelerator_lock($this->unique_id."_".$name); + $status = eaccelerator_put($this->unique_id."_".$name, serialize($contents)); + eaccelerator_unlock($this->unique_id."_".$name); + return $status; + } + + /** + * Delete a cache + * + * @param string The name of the cache + * @return boolean True on success, false on failure + */ + function delete($name) + { + return eaccelerator_rm($this->unique_id."_".$name); + } + + /** + * Disconnect from the cache + */ + function disconnect() + { + return true; + } + + function size_of($name) + { + global $lang; + + return $lang->na; + } +} diff --git a/Upload/inc/cachehandlers/index.html b/Upload/inc/cachehandlers/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/cachehandlers/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/cachehandlers/memcache.php b/Upload/inc/cachehandlers/memcache.php new file mode 100644 index 0000000..c1d4be3 --- /dev/null +++ b/Upload/inc/cachehandlers/memcache.php @@ -0,0 +1,150 @@ +trigger_generic_error("memcache_load_error"); + die; + } + } + } + + /** + * Connect and initialize this handler. + * + * @return boolean True if successful, false on failure + */ + function connect() + { + global $mybb, $error_handler; + + $this->memcache = new Memcache; + + if($mybb->config['memcache']['host']) + { + $mybb->config['memcache'][0] = $mybb->config['memcache']; + unset($mybb->config['memcache']['host']); + unset($mybb->config['memcache']['port']); + } + + foreach($mybb->config['memcache'] as $memcache) + { + if(!$memcache['host']) + { + $message = "Please configure the memcache settings in inc/config.php before attempting to use this cache handler"; + $error_handler->trigger($message, MYBB_CACHEHANDLER_LOAD_ERROR); + die; + } + + if(!isset($memcache['port'])) + { + $memcache['port'] = "11211"; + } + + $this->memcache->addServer($memcache['host'], $memcache['port']); + + if(!$this->memcache) + { + $message = "Unable to connect to the memcache server on {$memcache['memcache_host']}:{$memcache['memcache_port']}. Are you sure it is running?"; + $error_handler->trigger($message, MYBB_CACHEHANDLER_LOAD_ERROR); + die; + } + } + + // Set a unique identifier for all queries in case other forums are using the same memcache server + $this->unique_id = md5(MYBB_ROOT); + + return true; + } + + /** + * Retrieve an item from the cache. + * + * @param string The name of the cache + * @param boolean True if we should do a hard refresh + * @return mixed Cache data if successful, false if failure + */ + + function fetch($name, $hard_refresh=false) + { + $data = $this->memcache->get($this->unique_id."_".$name); + + if($data === false) + { + return false; + } + else + { + return $data; + } + } + + /** + * Write an item to the cache. + * + * @param string The name of the cache + * @param mixed The data to write to the cache item + * @return boolean True on success, false on failure + */ + function put($name, $contents) + { + return $this->memcache->set($this->unique_id."_".$name, $contents); + } + + /** + * Delete a cache + * + * @param string The name of the cache + * @return boolean True on success, false on failure + */ + function delete($name) + { + return $this->memcache->delete($this->unique_id."_".$name); + } + + /** + * Disconnect from the cache + */ + function disconnect() + { + @$this->memcache->close(); + } + + function size_of($name) + { + global $lang; + + return $lang->na; + } +} + diff --git a/Upload/inc/cachehandlers/memcached.php b/Upload/inc/cachehandlers/memcached.php new file mode 100644 index 0000000..655c20d --- /dev/null +++ b/Upload/inc/cachehandlers/memcached.php @@ -0,0 +1,150 @@ +trigger_generic_error("memcached_load_error"); + die; + } + } + } + + /** + * Connect and initialize this handler. + * + * @return boolean True if successful, false on failure + */ + function connect() + { + global $mybb, $error_handler; + + $this->memcached = new Memcached; + + if($mybb->config['memcache']['host']) + { + $mybb->config['memcache'][0] = $mybb->config['memcache']; + unset($mybb->config['memcache']['host']); + unset($mybb->config['memcache']['port']); + } + + foreach($mybb->config['memcache'] as $memcached) + { + if(!$memcached['host']) + { + $message = "Please configure the memcache settings in inc/config.php before attempting to use this cache handler"; + $error_handler->trigger($message, MYBB_CACHEHANDLER_LOAD_ERROR); + die; + } + + if(!isset($memcached['port'])) + { + $memcached['port'] = "11211"; + } + + $this->memcached->addServer($memcached['host'], $memcached['port']); + + if(!$this->memcached) + { + $message = "Unable to connect to the memcached server on {$memcached['memcache_host']}:{$memcached['memcache_port']}. Are you sure it is running?"; + $error_handler->trigger($message, MYBB_CACHEHANDLER_LOAD_ERROR); + die; + } + } + + // Set a unique identifier for all queries in case other forums are using the same memcache server + $this->unique_id = md5(MYBB_ROOT); + + return true; + } + + /** + * Retrieve an item from the cache. + * + * @param string The name of the cache + * @param boolean True if we should do a hard refresh + * @return mixed Cache data if successful, false if failure + */ + + function fetch($name, $hard_refresh=false) + { + $data = $this->memcached->get($this->unique_id."_".$name); + + if($data === false) + { + return false; + } + else + { + return $data; + } + } + + /** + * Write an item to the cache. + * + * @param string The name of the cache + * @param mixed The data to write to the cache item + * @return boolean True on success, false on failure + */ + function put($name, $contents) + { + return $this->memcached->set($this->unique_id."_".$name, $contents); + } + + /** + * Delete a cache + * + * @param string The name of the cache + * @return boolean True on success, false on failure + */ + function delete($name) + { + return $this->memcached->delete($this->unique_id."_".$name); + } + + /** + * Disconnect from the cache + */ + function disconnect() + { + @$this->memcached->close(); + } + + function size_of($name) + { + global $lang; + + return $lang->na; + } +} + diff --git a/Upload/inc/cachehandlers/xcache.php b/Upload/inc/cachehandlers/xcache.php new file mode 100644 index 0000000..7d74a7e --- /dev/null +++ b/Upload/inc/cachehandlers/xcache.php @@ -0,0 +1,106 @@ +trigger_generic_error("xcache_load_error"); + die; + } + } + } + + /** + * Connect and initialize this handler. + * + * @return boolean True if successful, false on failure + */ + function connect() + { + global $mybb; + + // Set a unique identifier for all queries in case other forums on this server also use this cache handler + $this->unique_id = md5(MYBB_ROOT); + + return true; + } + + /** + * Retrieve an item from the cache. + * + * @param string The name of the cache + * @param boolean True if we should do a hard refresh + * @return mixed Cache data if successful, false if failure + */ + + function fetch($name, $hard_refresh=false) + { + if(!xcache_isset($this->unique_id."_".$name)) + { + return false; + } + return xcache_get($this->unique_id."_".$name); + } + + /** + * Write an item to the cache. + * + * @param string The name of the cache + * @param mixed The data to write to the cache item + * @return boolean True on success, false on failure + */ + function put($name, $contents) + { + return xcache_set($this->unique_id."_".$name, $contents); + } + + /** + * Delete a cache + * + * @param string The name of the cache + * @return boolean True on success, false on failure + */ + function delete($name) + { + return xcache_set($this->unique_id."_".$name, "", 1); + } + + /** + * Disconnect from the cache + */ + function disconnect() + { + return true; + } + + function size_of($name) + { + global $lang; + + return $lang->na; + } +} diff --git a/Upload/inc/captcha_fonts/MINYN___.ttf b/Upload/inc/captcha_fonts/MINYN___.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0ab1fea16e801a19075061c089bb1f885a8c0be4 GIT binary patch literal 84264 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 literal 0 HcmV?d00001 diff --git a/Upload/inc/captcha_fonts/edmunds.ttf b/Upload/inc/captcha_fonts/edmunds.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5258ef512dd1e0f69938cbb65fb67f2f1e18c665 GIT binary patch literal 48092 zcmeFacbr^DmFQn}Z|9uT%=C1a?w*`yTB9(^qbvu-k#W>mHqJp{W8&Jt1MdP$FmZpt zE@82OT`w3Ti^XOaurMNsC9?)hhR6PvWX!@^Gr#Yt+dY=`%nQHA@1Ni2wNz7e>sB~* z>YP)jPKB$qQYyh8mn!YtyJu_H54(S(l;=LB^vF4TM#e9jzw}YU?<3VE`#0@6c>Bv= z`Dvv-@}yGk#|~e6=?(Wh^7pS(s_<`0d2c`b+@mG^F86~<^;|;w;*lG!xORNg%@-0hGMZM|16Tzl&enyY#C{!po;@5;+B zUHIBf-})YT2T4DDB@zBxJcoE*;JN3@YmeS~xUX@pQkIVfeBkQKZ@R8>N9Bb|{WY)M zKfUJq!4;ehoYW5~Bz7jjE)sr7xr= zr2AjnE(623 zeL@eGlz#m#-s{KhF}#w5oaDy;3C~4U)UQ!l{RI`Z)~JZ}JXNsnR~ywSl~*5CQT4Fu z;eA+_R9O8^<@Mb>Yy3NuWxZDA^aZNR+M=q~2GwH)mCu?`6>CHltznh7HsMB9hjyzD z^?Q|5r7lLn&(Me_ZMca>K96yYA_*FRKM{R?n4t^8J5g{_22+7aL=sJdxy z3>aUlK8<@P?gO}ExKD@!*LPU2)j8``>Ki=2UmS5Sz-@59T+Qk`mi`l5m&ED3is(-* zJ)ylSii@c8RnhYfE&WzkcdHnEkk-Fe8PgX(r5%r}A=*&4K7{)_;_p^*gU{!yKC4rW z7+3|*Z6~-EJmU<0!7=dUmYv{G+y>eT-j*G>Gk6o+C83Ap(vyPEWd~iDy1vCg~&7&qBL371uG`eQ+K$ZMleh8Ew8x4I5f&(-X8~=tufp+@5hV@=GqOVsQtw(6%rOIXf74BX&qJ9m{2t0A% z838Ba!;jK0!Y`(N2}^sVT`gKNJPV(ibkfdt|F!!~cue4K!D@J~M!Ghi2~XkZBQ3ba z6_HK@y7kNCwa&I5w9fM{N)$i&i%Xja6VB_D^N^Ed@-|LXM&~6uC;t=9`_^BloTo+c zkRj!nzs#8r|EuA%%KBf;Zqg_J2f0MB$H3XBKk9}6Y?sUJ^;-D0<+5y#?dIokdps6# zmWQ8L{@5;$TLNA$uRK1F$L;dC+%8gEE|2Zy$>WkIuZP^`XFRt%Y)jderK4_(3S9Eq zqRdt*+jdgB%#RfO-0pyv(%iPB@p^#isYG5EWw}iv$`g>OT0ka_>TM6Xq)C$3RN)n< zod-!Gd)MZGkRolk8Fy<+>!9 zU|D{)^cDaHedMG#-uS#O5;b+dWKw7E`x19%Q9Jf4u>2doB5euFQ8 z!$+JOCp5uZYUW3sf^kX%(L_YfVJH|r@v{C0mesle*SWNkRg*+awnBNGrj(G$ay`9&kyTpdXmrre>jC94u@Sc|{tD z?4)hLYY^@73wljnpI|}?=PwjNS!6TigQI19xdjND1YW<$UU>p2()<0A*1;EOg&!k1 zgD)5)5TL6(;LGLUi{_9VRJtU05En4`l7K;A*dK841+0Rvpy@su2u>X!1z-HU-W2pe z*)E*}Utaiy+AOjgz*_hU1e_MM@a6Nxf&oBvNt%$smy{I<0DVC4CD^4NnqlxIbT7RO zH8}Vpom=qZWduV~(;&@72)iN|9SJ1ubV1?m%_AP8|wnlSkCcqob=%?t^?1iRG3aBuKs7=RK$ zv>Wyf2!qn(prAVt0(?S2Uoa>T8hnXhF)SzeqG(qLF-gmPJPC&3IBJt_F|_H24B^Lk zmtPTtL4qNe4;>2h2R)|S1?kdx zkig=QE@LYAN_4mJ6>8xN^oKyPP*5NUG+wtfB@zmS!d^HnDgmkwg$nzX>d7pPA~7*QZB-b6#*b|Omi zhb56vBlU=G-~(TPL?4;z-67B`Qb_WeR)@nBBFKW!z$ZCFyM>Yz*jiz^@jt3uL#r@4#mM6 z;{c-={Rx0kAs2vzQ^`&;e#Q#~3W6_2II9#8pS}o(?NAu9H7zmtB19AUnb8se(^2?3 z;2~)^wv4Z^@OnfN(Qu(1xCxL024B)Oh;(;2=m~)@!FAX`5RvYdhj3W%Woik722%p~ ziqJTB1bl_PLBCg!OJm7NENLCmb?7Tq0beMq;41?2q0WK+Fenz93<3!D z6?{bmUqT)s!Iy_u;aDUbiTVPOV4R02-4%%>!5iZM6@)?_csM511i(l(vPaC%c)?)N z;EOq0PtYa!3QBFDTV4Z{&u0=#kMl#Y)APY#HU@5jUXn)Q5nnrz!IvbW;j}g+vmhjv z&j<`k5PU^K-f#H|V4Kj0Dcm=YKyqX6NKLLU*vf1iK^PzH8MOKYgf z!B?hc@Z|^jQG}Hre0ls4pRfr%FVN5vQNdRv3cjMD1Vw?oP&AT?LZX@NQ6Hm@ zAeY9{glJT{MG~5dps#Erq(Z1>LCFEWyfn)n6?_?@1Q@|rG!h5um@gO&CCvi}jHaUy z0Q8QI5%$2t@vxA;;449P((^N3C{$|Ws}T}yB^V0FVlL24$x#8#haZaxzWAAe5Jt`? z;A<#_cgZL)Ng`5_A})y}H83K506F9bBVgX(%Nvb&BhZ<_wP|%+zz;=ZAyWyjC_pf2 zN&Gg(8A4BpW=O2qV4Kecrz!?2j246@xkJSgh5H6u` zJm!L+Bo#pU{U))n6yTwc!YSc!M-q)C?2|O9n4d(XPHrgm+7fs+uO=Z!^t zQM!%1QK6hzOz;(J;R^^UKj;-fO!*}D`QtRs6Bnrc$YcQtpvWAH$v6V(f-jUd@WoHe z6gby?treC|o>*(qKUN<7S>Bb@W5l>vXYsJ=;!}Ps!9f*bjU&RE2ex5_y;@=W$D*EP zNtYLJjF07K>O<<)>NV;< z^%3=#>b2^A^*YuSj;YtH2h`s~gl!>W#d4P`!=6&r{c{TU+@)p+2QpWmGRxf2&@oZddP7cc_=Lg7H4}GWBxe z->+Vw{$Bl^dPvQygX#ixsk(^R3)RKyGIa^|>M!uL9sIfJJ;CE4VsE3g_prX=)k)o< zyLA;C@|bSwS-n;7(iiB<_0{@j{UYmx^-b&BrBtaEx%wh~mA+2jYCUXy!}`}!vXm=zw#u4u%3At? zQcK^*v9|g@|9k8*N&DFD$IgFj3;vGp?lV-pmB=~VZYbed>M|he0h&=gt|#?My;{%d zy?VdCM&G7ipkJU z4(ljbtFQpjtK;-%L_Nf!LREcN{hCFBKJ_j2uj*ga*VT{JA9O+YsGq3+gobMBr|L;V z(cf0TgsNidzp|3~i28#1iu$JdjQYI#h1Tk`>WjKdH`LG7qWZtplJ3-X=>2o*OX_Rt zQFW5_)On~=DEKmH`C`KrpECUMX~Pl!hnoKnHUIyInqgWsxPw3E9{dNbUp;?JFTL!T z+SK&`GRVI8qM>7K^(d7#KYP=?`Vtf?)-z*`O=-GJGU*|S(+60T~MfN!Ek zPLs$zxTAEhT|f8Wc?a)($)=8b*KL~bD3?o{@BPHN2k-sFrjGLbJgGd(kOJ`wpPg&L z>;+~|Kkt1`DSIe`BIfVBQ_9?Puv)(N6L;R(aVPC)Js;ER?1*)(2pUcn8ov3Me#yDy z#jBP(B%)fbmH}&i6IJ;KckDU18NkZ(LrQQwfK=3IGS+}Tjyhuk4-!~`9#TbXi7MZ~ zgN%=pPkZ*DzvR(wqUb%o0S0D`YV%aYgX~6`ep&__HK&Lg)XH!ioyn!V0|4M)gkDXV zapjGS7gsZavl7W36xp>9vWIz+jVrRAtLzGTRR_A(F%=y-rcxuLW6jA~Yht`;rBe~B zS{b(NiFDQGUp>}YPp9jhv9|B~ezUl$IC*)xCULcNy4Dekb=0hXd1Ud!dY7pqtN&de zwYP%^FZBQ)b+~XA&O=?v2};I&>#fbvCvf)m#dqsxExudei>j0QA#0wz-Hb_s*POBk zjvF0N{2*y;+N@)gdFq%-$ER4|^HaZ)FEBc-J9 zGx!Dk9DZl(xk!#~YS-itn448Et~t@1z{h!c##M>Oz31|t%ip)XXM1vcd1d+XaXg2WIC+j?LlwEJUxY+H| zZ_|J&9Ag^&dsuY(5GK?BbTbta42>b!#NQ0Vil1j%B?LD{LWiKF(5f0UMV&)z zKO|I36%jJC*3{%MLMCGAvz}`cx@w;#i1gXd*G2P{RH~YfM)TEFs*;Z`{_EK>`l0&b zhM~SpW3pJBYGkvGsbX=mkWzpV zwwtqdvpx$?7B!YyCS#j?g|s(lha)l1`dC+z70p7Wkq9Irert@V*-cQ)uR zui4$xXl7(+%Ikku$IRFvqmzsrR%^t_zoR)NBZZ7(T1A)sP5rgK8oR(n$1xqGL8Rdb znHTxs2p=5bgCl%!gb$AJwK>8ENBH0f9~|L>BYbd#ugwuYIKl@zfItuAZE;4C%cG+*V6V+GDAH2Phu>Qg>Wp^KW-iDWb z(Sf&T>F4Txdlm2=k-^L-@QN_-Aq=EOfPV{tyKxWT9>IMR_cPq@aV=rsgVB62mJeaz zLm2oF1_Hb@4(1;{1Ma5BJ2l;$)l-uqq^B}aOgiP6&v%{$cc9b0>nX5bWtZDvYxaS? zMc-~`%;@Cwg`Y7-qpv8aRaBjJ$h#a0EQi9&p;#*fGPBLBH|uTi-`i+5n%Ty&?gK-Y zy)yRlku}|y4_^10*sF%^%8>xpjssrqr)I= zT(FB5c9CJ+FXN!k(2IyEk4fO>g(86mKOke+1e^k|q^nca@WK5D4(vauAHMR+BiCGG zXm9CV%vet{<_qlwC@TX2Ovo@cWuy=|WDJ9o8q-%)JFp(28x0g$^3)Rgb%+ukgdn%n#OwoaE8M$f-~?b_?l zA8q^kbptzAl*=o24D|05f9LSNH(tMf{q=9$xBsr|*R8w$F8Y+Z@r*MQ*k2(snGhh$#CQYq=-uihfs&Ti7gbX#i%vj^F zjBtc9oZO>aa58j=M%UKn8+^|3;7psy0#ZRgVXYJp(!G8hM#UUZ#8hM#E@-jpyM{~gk!|}My$AbstfQLp1ybGVfuSRTR4JYAP6eD^q3en>=S}2RPWF2Jz2nW? z#NJh|Cy<#<)! zz4+Lg4IAd?2CUv%&lSVNtGibB$HrD~taPs&>a@?<(Wq4eK1(m?A6{t9e_$Xnyz@m@ z)N1u;xU2ttp+Y+BOIJH*C#`fc8qxZ@i>IVdic3#eDdcvB3Ck;vvlz14fY&c_2$WZ7 zi-Q59X@uaMP@8i?a83x$3BfrbI41<>gy5V|n{zlhz(XHy2Dc42j}uL!pJI1P7jFP_ zY~nX{R`6?J5K)3kTEx&V6GRYFMPc>UhV81shSw1@UP#y(NF!SGskjl%Mn$>PN_98V z(P~d6(qY>J%nYKfz7L$CFer1dsQHyy|F^#gX6skS1?#A-#%Q)jqjfBXpRp=yIIC| zxpgcwv~KUD_BD^}9_i~%4K_CoLSKx>Ru1|qsP5w^2Ey|+T_~GVLI%x3GFj0r%IOK2 z9%okRw9vw^Ac6nobTzLR^-qWT!{MIiUNyEcm(2w>%ycbmU3~bkUH;5JZrxI@oXmA} z%w2bMrfcua>xJ4>o>LV4c0XvXvI2GbI7?xD2GeU`#g?v{U^GrJ8YdWy6O6_QM&ksd zaiTpMCm@Xkk}APyoM1FgFd8S?qj7@KIAKQPgdvnasXFST$O7y>1k?$`SyIU) zUt?k<%{I7k4gNVYFG{!OL*dpi>I`6DHYF3A5oaQRgF4`WE!78WFX>m>E@mV zE8a5_$`%u`VkR8U6c>N{^v7?O*Iux)x?yX=pD%QVI z;a|~ef|RD4nc%oETT?{PFj#WPZkDB$Y$hE~8AfvmvZ>!=1)}LtzB5uuH99(MSD}9_ zl^W-ji( z0*4sf`9gnXtQ^(8L}%)QT|Mj*4+Jvl+eaJu6}vWUylO)%8sT_CsIz19D;FQ@ni}tI z4EHvAuUsd%pz%M`zccL<4OO(=s!X}g($pOB@RV(`qpkJ+F<-y-EbHXr&(4aVX3=}! zrG9Mc9|Q&@8}+;Cl&CQS{kL!=pK&ITI~$7K&pb8wZ-IL0ADJ!4xaQVr^?fVD_?ZSW z$8stokjD&Ez&6!Pd$Vcxx8L+8eRSi+YuB$|XWG=GWBO|HIkwlflxok2$cJVZH?xi{ ziw|gV&po0&N60I46wc;Y=trhb57@B4h6_x2jA++s?^LrfrL|Ogf4frf2r`T4a!CfD zmmEhW9u)~Cv)fU|oYD4}Gs>7V%9u0Cm@~?lGs>7V%9u0S9&<*KwxbA)QO2B6#+*^c zoKZ98biop{GUh}9DAzJ>im}$2pNQy~QaJ%1NU{ zHF##WON^ec&fK;5xw#cr>e5>eEk3?E`MKoW?++yhtoiSJ=QF3@d*a0Q?KmJyF8zmf zlRZX%_MlnpIL@YuUIUa2{i0EbFO@s`lk;3dl1uy+;#2rr@nr_N?G&x-V-PZPGAvSv zr)d#mGLQCn(G{{8N8KeNs+kmtzDp{sEk%yzkZPKc#>b|m8#Lxyo_wV*-LuBS{=QmI zr98^^L7h5hs$--ljT$`FRo|97yl^61OodmBjt%zoB`j}v)0(+MiGUsINSF3sbaCGa zeM_pCO9f(+)m*XL<4qwe!i1J>^xSRsTV&ck{(7hxTllj%TgPx`EQp^A8Lhw&LR@t>dBk z*s5|r6VgPfKey^R7p~B{w&8*mJKpi~t7;u3yQ4_e7W(kx)&uB-X?DQ;qwocy0P-q} zvhDC>5T0Ze#j!XA;mII88H6W;@MI9448oJaHctkj(;)p9geQaWWDuSV8lIHVStg=F zp?Q3H7A0GrWpP5*RAeS4@k0(Jlu*sqw|dK`!y1v6Z`HOMiPV-@m29=RI*Ex%;Wf{O;t51&)0AT%Au%=R19Y zttYmWhuib{!P;hK-$o9C$eZBNyt)G|2FN;a1t8Txs^yumhbGC)M@&vKxe4$rcBl}3 zl=uK)nPD95*|igxh6>N*GJHK7b#=cP9Br?1?G3+1RYmF!9B7 zAk(Aj{K$f}TOVHh_BXzvs|%+;v@oI{e#40q7hUv*BX?b}_^p#~5}Dp=OIGGbVl&9& zL~^#YKy?07T6R2ldwBo`V6o;6T9l3sb$D7Tm1UM)KhSu1ZwGnEcWyl*h4Hd zTzH%a5g#%Xx$zw%hAh_=%xJ(&9Ev&4P~n7}_Y-|%Qx@*;a`_JtxGL?v=58XPqW$WRyn0eyd zLe%$Z{n1x0{>zr0Oxl-U(cgE?bB>Om|Kjy7*TmrBZ=TN3z1@jKo9^BM-E|Ayi4CNT zD*S{Dmkly zV%u@-cy&-=?8=IcC{l-~MSzakV|1)f8#A78=PcTo%yn5MXtGKmD=^qG^iHwu(T>V+ zwX;~C-Z3?~b!M`Ays`ee`}&J3l70CF)4coazO_4dZXQmAPlUQ=wwAiiy|ZvKdhDfB ziO5~1-SDyg1MLp0RkAK2nvf$V&ZLbf@CFTSfRoUF7r!Dy91MTx!o~g;iuW#luSJKp zkGe+GVVHz^#&DyQ-L6Yk`Lfj0i4(dT6tOOXWtckM^n}n|sAX|9CZSUf#|gm-=gC^M z_yg@eN2a@w^)8t^JA@XmL|n{gT;>r-Uoo?$7zlTkD_xO5am~tCKpCg!Itr0MroS;T znDK}59dnDPr6F@y-FDTS`D3V1zoxnO(mgXP_FT4S1yt$Kqjf3m8x*^$*i^-CBz7S; zV96vzEUCg%S;7h81=L8v zOfQ47I%VcHZgeQ<+|i-j=umESC^tHk8y(7x4&_FNa<_FTH=2YS9m{Je%aFJ-L??2%CPXKKCxUg)DA0~+ZCE2|8Ys$^nH97BK`1F+{Z`kZ zeQRy2I5xXxI(FhjZQq_e;oi70kBATJ>g#TH7*`%EnP<(`+Nk< zMB12%fSCxGiGZ01n2CUy2$+eqF%tnZ5ik=0GZ8Qo0W%SUnIaYBoJFS`X09A&t{i5r z9A>T@X09A&uAEbfhd>5b$4%qraQktsMW-BQt{eb4h#dz0VX^JXY*i47X|gFhSe&I& zXHJ-wm806S5yH$t4BpcoOidoKvgn=O2xoeyJUyvgn*GKtvXdpH#jm#4k4E}E0at9Y zITq?WXY1PR$h0gj{ZpuSbRsjlD;vvnE-x(g%RQ zSo{Q}h(6p5ZX0eMC-f;rj)AfWro19!Zr=qsWEVW|I>XA;ZOJi$RPeRFk2mAZ# z%`J^}dj{gYgM;Z0unu?C;@)7nGBzGdT(ocB>e*Og)6n8? zhD+SX;PTC7vdKjMzvzU^NZJ>IH6yE zko+wDT5qKOwA#^{(SbfUM4?*ZOp2AIP*d;I^)*M42$Dbm3*(DoVOE9OdYmV(onVSC z&|ehA^U+5abZGPQZn0Vl-5=Nw=Fxjm?mjy|k8qOJCS~0MOcAshCOQ!0Gu7*B)hhr> zy&*GpGut$KAZ7NI)Stpw@|Ksq^^jC3)t!E?sZYmY7A1L3(e7HKWie`qDW;lrb{BcGgs1d9moKdT{laTs zyYTzf3zxS-C-1!T3-RhR7&t+UxDIkfSTBgbjem5?P zi0Oa?WrHSE*@e&+s&rP&g`6F&l44cZNFkY6`zcI(X@}6QSjOa8+MyBD@z&Hig?x8{ zac4d-G2PT(m^k=ZA)hN=X$dWzo|+lh_-0Grc0jwwPnb&np){U>$lTby}*h^tk@4eiBJNs}jfAY3DZ`xr#E^JxW6( zVj7bvPPSTM+9Ad@9-L(W!U&>iXZt0`W<+2$jX_N;Z{E}@F6;_-#VdtMPc`z6zYuRv-P^yRT!GiRr3Wd6>>^Im5Iqwe$xo z2tEVMz}_tSgd?qTh~k#L>QAL>iB2xY8R-g{=gPCQD>!IO$4-oBU}7GrifD`?He~E- z7OiQ9E>Bb&jXmB{yDUb4boJx8bGA=vdwlb*uDj>v?yl_Ev1y{aYi#58-L<=)7@O2n zGqWqL@uA&l=!?%E9B@_VuGlbjaBa75a`GzL3pM1I{!`z>W}R^we;hd_!#R9Nw=#sZ z)^x;XZ7gEh43V4=S!|SmTmXhV+j;`sk{&>A^S)HBHu0oRI zm$}l4!EP^S`HS7P`atF%d>yIY!GYe*7f$tVUo*-vPj5Qhy|trr-0#tx9ZauC#C5ij zDGd#D7UEGui|(aA=qKqf(UIvdw=pir+OwFk%^o2)>Y5vM&5gR|MqP8GuDMayTI#S& zp+%#ve*6V2LTD(NR-t||-_C0o@nl*EYET*a6Es^Ft3%XaOOK^>+X z!3;W^1y4*xEVC?Tfj^m!#V7Qhu3ekQZJp~KpB#zZeRpm5_Kjm*-4mO3?5NO(IzKdS zt(>ioWp#F_{KT@Je8pVVH87}O#VScx4-+fZtV%1{uEe=E`@ZP5P|9ygSKN6iHm$=hpNQrwX3x*kFV}p z`2!^C#KJk_dfkssj?b>PM~BWgmXF03ZzxT_^sq1FLEDfqGRI$$OE#Lq7GXtaP9#u@ z_9?ztuY|}&*%PaMThR@OW+)udwh}v^$CM1IXEG8i{GwWFecAw(FMe6*{(BTHqx}}M8dbNmS`;#|9trH zVR!$?1rrm^4eRW4KTQ3nAA0`U&ARc)b>YyV-=1jonI9NB)XicicT{@WOe%dQs=Oaa zr0+yek!Mi>WwItJlbH1*)-WySv&~pF+3 zfw1EzBjQ7EUO(zJ9a-J?sXw16Z|S-Dlkc35W_vBulc%4USaH*dNNSyQq@g|Sr5%3N z5Lw|&NdzL9M+n?rkzukf&8BEmcau6C68gNU#cZO)7-r<5^_YbWQm+*HbXLOTn7QzM z-O#hB#eU^8bSv7Mtc1u;6|ruL0Y(7 z8H$WwwqwAh*L~^a_-(#R_MU_<)_6vS4v6?YFgD<8j%*zrdf7Dv2cIdJBc+$%<-`9U z@v@-S+1z**S1-4z&DA5q)njYU=IW=Q-%y&o;|!jb@%6)u9c(RApLfg+VpR~FJ5($D zWps`|)kxByXfbO09Anm>W^+D+kd1aL6p=M1MHI@XZ(%xnYx4CQCh`O2WU@TK?wV43 zzbFB1WkCG@99k3W!kpl2Ys!cg&^LF{)bxd$d(jGvOiC|)#R{>vC5El~?b1cgKE2MC zTojuA6WfYv6e;sCDY^$gj^EpQ?gyuxJP(VOCRa6xRFZxaBYBhioF`;g0BTadC~n5E z*V)kb-%*LGCqela)quS4V7)kJ;EU#aeuiNr7F`UVDjdrQNkA#d;MEu-W0zO9jQ?a9~jA-!T|?TpsrgS!`RI&tD( zcc;@jUbuZ>V*k3Dwo+-UB<(Z%$MrX8UqQz46cGYsidM*|B)(0nYy_5^r*QU=i!x}m z#4OQ{rNnvt)b>~pEsT>vVi>PPa51A4HCD`B^(NYn(_hb?dtcwC&9!;V|H(XP4OlLKN5Ss6=@wbX6cf0k zQltP}r0qE14iJ{z+M}c!cd%YHvtDC}11u=YOp0Zg0NuuRR}oN|9T<^2HK9LycyM~E zt0R%T{M^2Nt_B;d^_)A<-+B1(;M9sjS2FRe`GG!(iOfKuz zrP9VqWjYe(e%sE@6DtD#Otz4>N~LmT({!hWJt`Vu(~q>zzqF_;*4OEZAu(*o(CKI) zvi2m}i0zDR%ui`g5V~yPIKvpnh`>~jvq)7z^HkM;LulxN3#`7rQrE~xf4^%^KcT<> zy+^JNht_|pZf)H3Jal2|3@`o43UdNDug-Z&E0Vgz{vy*W2@BhbhSVX{-Buce?7h5@ z!T+iGL7N?<=Y_1Bj+MytxGbTIwdmKYqm`bWgW3$oqgNlPgx38?4_|oD?YsE!!w(-m zd0>0z>btIa*uck{3!7sfr>*}R_Bn8q)jNt`I&|=5hYtO$vKksYvG`^A`$fS)4rc!? zb)^5dY;z5-*yg0FwR$3JZ7|iX9&>7(@?R&EO|7R-n|i<4`#aM70aP^OeJ3<4u|m{;3_gj^h;44!t|)gpqw6+d%O>d6m4VsSVD`f5 z>`IlB z3>w=%<5E-qL+G)%eOYhkHc9tRdxid_{g?2wq-&p~PtMB5B@ydcndgfrdS`696ysk{ zqT!C^y5i-PnRJJ}ty1HDM{fK|$AXzuC}q1^a^eH_tbWLTJI#qwu536G7~Hb{!11|; z_XB_NU(z?f(B8X!TehPE0y<{T=m+h)fI>zdX|*%;7gN7XIK%{y7OYQlSRsQpCQzLb z)|Yi8lO5vjX$R~poQU=_TXnViguPS0-+rONOMB)5Ot8c!e*Sa&g-rM*%}V`&W!%ZW z2|2%srLm#k7Jn>czhhfxucW(U>4o|xCgV{Ap)i6`14K@v4WJ2FjYlt9(b;j$&Pr{P z+d1>K%+B8Zy}i0Rl5od->?!teLw(Mk&^Oz!rrqs+@=IN3wk%h0T2`0B zk(}A4e$eTlS2!Ki%CnL@@1sV6RSe*!CQlvG$9DJNwwKPOXP&>>e%(Q9Uv@y7^_&+h zU8pZXH;F9c$SvlEtd}8{t%X@#J3QBW^?8NHRKOkTXk_1&-F_&UnGCrSVg$gTNLx2> zx6VD*ixDji(V=^(xDVG0Nwf#iKd}zoN6~-!vwgzcRm02wv*-H`%UB)BD4-rwD=qJc_!Vc7#4Z{sva}`tGFadp1ZiHNrbKp2G%Jv zIo4vt`zWKzF)eD6qvsJOg_jgw;zUOJQROb-Vy&j6RF@EY_oK)3rKfO&cM;x%mLL`b zIq(uvyYwcLau<0;XNZlEf^dtHB&@fROQujV+_0-tkMdr&#z;DuO|wl%%l;ub9r7hw zc)*nSC1Uqtj@<{qo z!m@YibA+AcTPJ=R_|7A4hW9g4E8&%dR}z-^wY(q0Uq{?J;spMUgg3Urn+b2G+^-V9 zg|za1dn?Zl-tFL>;OADtw-VlozZ3r);`V@9>4S?&FaBk;;comJ@fS|vNOvR8R}#LG z`kI8V1uM^K_mRo4&hJOqG8}Z+Ye;@vRqbSlPTDV(quP-C!eY|~NEA>5u?;(6I@gF06AO3^*4-zMR@EJ<` z1kchh|J?GwjsI=le-i(b_@Ck3rwD%q{|oriFQ>o<(?UH!8@~(tIEO8N1RtC*aLAPL zC#3xe`K9cCBm8ebJV5wY)cGGgf1U6m{^H1S(UMe`p`PuODhkpTe6e)F8(LNxe}ykp zh-RfbPT`yuXqFSST#nLDeDTray2@2%gOqe!_ri@|Hf476ZisZUW9(YOYhk&`8Vs}%;3}GRdJ%lBG zAK`s8{#?QbXab#~FCgv$8vZP9`n%TvDX|w4dm*{rOZZ|^LSp(badfL*z=zEAR>GGP zzMSx-gs*@kCGOe8J)5{I313C{3jC`n;}ZO9@uiIG@w@PE5*6!n$RCkHa`0b#xs*u! zQ(Vc0kE{~u=J1q7Mt{ticd&=i@L7VmL@S&o9N>MnDh>8Fape*f~B1{za{L=>(zoOYudrN*?JDY1{S0UEgZQ&4h1m zg`Z1U+IAcMZ7tYeMEFI#mpbksd!_-|;H`9{L>?#=j8$J<)|JMks{Z(7gq!I!fC z4qx#0A^Z=u>itLyt_O&FfH;BsA;J$4{ygD-BK%K;rEcMEDfiR(Qs0Tz^OsuBU&fbo zUu`{qt@Zp3e98AMe1St`h4|mY{~jaFkDwuQM%rNLXT<)D8U@l{5dH;W>D50F{sUpj z=|}(*))p<`z?9_G9>TI2gSOFm?S$x}Xc zOmnIm+0cScYSwjPTXd-V2urQdp?N2CD76i@{3+f~wV;_H%=lw!m?b>hf@}lf4XyY& z!gHuqYLFWXEnec5JqQ_fYV zV0g-r_-hGYOIXUkj_`FT#d39qSafmaG|ORW*@ctlkhVDXFicHi@F(6o#oUUx>eS@K zco!QST7j%YPGosbS8M5s=2T+}=T2uOSd~(+ahS*vGO_Ar3Y@BDDOc)p^RntqcQbXQ z2+1|V=4-c!Y~|&(glZGhYuHkes#c5#n5h9xb^|;qxWlU*29PO%h~%b8Sx?%m_f?r9 zO--)SQ{u5kJ5g&TpfKm1M6w-;MwR)46-<&f>kZTX2@pfcZl+rTMx)6elfV>9LN{QF zqXlVB@=at(Eq`S#V~rU9iJ#RQ6N!ZWs5d^$(tJ)ox1z87!xQ#3BRQ`>84r|_bID|M z0(ahulI>qvvQPi#Iecg!sM(1T3T`@mvL5W?lIe@eQa~i0``705bkq8DJ+L7dss$Rs z^}%p8@Z=?hzHBZ0AGyA4J+!!#ZkAKY(r_f$8P%r?g~GaZg==!T+}eiDG}7lSzBL-m z3}mu;Fq7x1fmDjC`BQOURKG12N{mnR_+xe^o6TCWC(p^$SL<&z-YWMZ^ZAB!AUSw4 zS~)%IiKa6V&tGNI>CE+>NIDbtEN1wEU+~GVB%kN8+z;~!qYJrm_}f8U8|ggQT^kPX z+L??WD-=#YuJ>Lv4Jg@LIy={7v-6#6GMV{pAHVH3`JbMR*pX%`^@eo%4XKas*|U>t zhQ?Bb6``FwQ;8kBckg^Lr&>3p{PoU(bb4#rSAN^(TW{Um)8qX8x@Z0KFDMi)*tgD? zeRsLq`|Ogz1^0*n2e|l1Ny!}Pzp8KN48XJSx)5>B^&B@}-7Bpp;rDM<5O zO1F+$-zRO}%-LnCAv0&O5Hs6kSd^UEDweWqoztP#_czx*?cSz>&h3pVu5Hr7mm$r-mzt6qMlf_Wyj_fv2Fgrl^fPh$6`}!H>?`; zOM9sASIKkli^HJ(6nEDD?I~ZF*g{!D=B^Az?3OBBu zTCUJ^V{z#LwTkmEoU&}2^_Fod*o#+-U0wFTldtBS3mM#R=PsbS>9mH5b2E^9Z`9U5 zHGbT}yeZGvjm3|o>C`=d8=T|Skr9^cj zu{X9-+(P&k!V>>k!k=x0KTr7c4Emxz{+#g7Tj75v{O?X!dl|}@`pP6q278^wbnNa^~<4M%b|VCp{tieH|)s|Pb1|K<6@IhD$6K0 z%)Q!aF_>kzm5~boypzp_*dF<}ioJdfO0^qY1J;;geXSvmG*hfGOF(Wko3drdZZJ@> zi<#>`8HVI+G%F13Y+=t!I+c|jOOtD<6QdJj83$QpMT^W60tI_xMp}DS8{e{R+4T(3rXC| zW&U0_S0?Z&BJJr;1_FidRH~i=bUqsh%=IpdZ^gygAjy~3{O(#d-)|4HH%xXk>y6$B z<0D_ndadRHZTZHWuLqQ*q_~|HpM2EX_6BIU<^Ed=^SZPZ;-VOvqWxR`g@ zz4?w*T)vh=H`(D_c;O4T`g~WMyrQew#m7gqmCbb&xM+xRQN_6b;0@ekFsHgBs=jia z#HFoC^&|UI#>%K#vh4>y_2B~6U@bQ&ulfX33CZcIM*gY zzGeq36qxmR|46)kc~1wQI_PYqhn6pQtHx_d?~b4Uu@|-->r5sxa#1cfzhz3f;YKYL zh`19CF3^4E7fw6#R-HEOw)oO8O}WFghd6!G-p$A-XYieNRB4YKk{*%vIP4`m&d#`z z&YVa1Z|f_F`eb#`nrEkzZvZn5+Uqj~hQ?Y@_{jux+bT_lEmrFE?9Ofx9yi)F42;7Z( z0QU&)o4B9hevfM%<|(3_6*!#qWX{GyE10@V=X{1D^(5aaw1-jIx`Y#bW1_N!vI-N zRL&O2=2?3vYYabTEMbtzGDtWZb)oCN!5v3tW{&I_Z2RTLhC>q*hc-4E8^zzy(4&P~ zwSS1YXK1{>qsaYF$)3s5?wU@YnT_l#B(;-!Q=_rzP_k#`#OUgHq%vC=SzD{E8!2p* z{&lGl^=kbaOJqoc+Y?r+AIPGEvz1FeBqHsq!lr-Hea@zbqx5jJ-NR9OI7$yk>ES3n z9Hob&^e`)B&T%b{Ve!z1o55|v&Ew>_7PbdtGatuqqIj($rL$$aN(>jM2#Jc)C#SiD zbVc!qaObz2YH}`Gu$Q~Qxo^i#o0+(mSvv}XEFOBZRUPTyIFiqgZ0v7rne6VG*wQz4 z{_1jh_4#9Cd)HK|YxZud=W>zU(D|iCBGor)g^HuI-KE*lA_(v4#$UX>x^id#z^;`Q zE)yK;-?_4?QJuV%Z#7XTc57+!jb>|KBl&m+R4E_;2|#5;GWyn}e2iGLP< zCA|~>_T~8bADkI~*K+)!R{Gr13+2uZ;vGJ}Q0RbioI4Yw{00$}&xGKqcqzw;KP3F` zr00CQq#tn7zv9ezfyarT|1&4vxo=a_%N}XUmnjbAIPsF+iJxaf_fzpwuM>Z$HAXt; zt)!f$Qx1nyB)t
    7DpPvZVugSTuJo4ibCMarm@p2qA5j)tn2eWj>gOQi7*&BZf4q zkY=?_npH@%3Taj$%_^i>g*2;>X0=V4a@&0s(yT(7RYu^jiKg>{X|b9t7la zR*#n%)TMg;x;=XahZ@V5AJ%&IH~ni9$xztR)0+qTA|;p3*2X%reBSkwC-u&Eu3G7F z)oags+UuP zhnM5$mp-)k>E-xKmg5gCy>sy-@p;z5IsZZYTFUXT#>mgabH2cozrI!eF;l)dcVIn> z^iKStrN3W1LHaPMo;2xy*Gj)j(l0$p=SQst(mV0Mw983>@bu%w&kMY=H_5taIsVYnS55oi1J{5pcLoW)dsRa}(8h=L2lj)u>t8S58=xHL zteMdJD$;w@ArWq-9Us*9*xkghW#sbm&8GX89)}M~;NxTLG0v!_Z02+JwOf#)8?sE` zM`a&Y8gg{*GT?=Y#NL4)mo1CtNQBU(oQPny#(oyAtfOE z3U=kbpED7)f1FL+!WjwSL$l|}?nVaxxtKSkepy{*6T6u~%2787p~zAlYapgtbGL`= zpw~1`GOz{N_*ic6pW58*BU6M-Viu3#%X0$XgP+2;@iX{hM9SeS{DQPeETL0;mI2#i z`_!L&1tKl3I<@!OYme-b%~exu&)Ip!_19njn)i%vnbs~gS$&bcIZsY+8Gp}v4Bl5* zSL&F34f@y`HDFy=N`i3F({sq5BDOBMC+t?)uqP`=MlTsfFBwHI8AUG{MK2jeFBwHI zXvapH-Q<12==7Ga$!T7xG5t~bn7ri`@}|k zO6H)B-ob>GErJLcnW{QtqTJ8>vH#@@!mN*H0Sk^kWhVT->Mnmv1LJ0K>X<@mpZ zmYp&0prCX){={wun$Pb*Avi9C-C7q7EZGfKu5r}3C{a$9iqPf@Z&0EnZdVc`Y>`1Mg%WlVmfbIs z#zR;ZXH3O}JBbrYWjRo>*xKG!V6MOsN|iWSlqs~{R|rd<9@*QpeD9f|R)=aa?mIUn zwNA8F_3b-nUbgrscc58!>BE1$fB#=EEFP%-^%?h|aeLDDk8F|Kljh8AXoBOj^??H| z+*kC^^!fH3&^a6T^e>!w$8vfZ#~nRko=t$Qa?a2byz0QxOU{TF`Q_*dhhDmzp7Z|F z=c7b;ILPG0pRGT%;c?<6y`v`_%$=FOuNCh_?K3h=?$>d) zsn77d&xpW%^zSzMc^gd3HW(9YX24>F62p->`MTCj@#SQloSBsGABa(jKY#2XtT{i4 z{1!_YRscfIT-rL|oW#3v`AqCp!J%q(R!-z~7JCwvN^fqoJa+rQA3GzP>Pm%dcd6Go zB%9_7&iQI>VE>wEI>>QZbB51eJ}~R840+sfPV-fJlKvoe6mNZi?|}Z16SQ_PU5r=e zoFlZsJfDZ`PNdIEjZaNwo&It3f}6m%qZb@lx@Ymr^n(*GYG`icG>c9u9pu-xCnP1byuE{u)IgXYv= z@DLg0$B9e|LvQWdHf1mNS@&+Tcq!L!z7o^HlVUz-UBP*A>rzZ9JEd)7dvMBj%52x+ zteD8Hno{;z_iJWb*KFDpoH@fb(Jma=<-UOf`Y!9m3~YNG!;sun#I6>lVHVlYD0}>~ zJj?w>=0$(?A%G>ajY1x_>oY2^rz`I0+$~ zJQV^7CPD&)N2@%{NpkYQ77&AL_6l>aZW``t650 z?1wt-*O*5Ao76P9fz@}$$g0uDDRl9Ay3D6n@Y09im)C#c5p*=FyXoI=?^Yd8S@kl40e*B0+6EZ}7_Qu#21Nu* zjElM&^79+ItFcd?EbFWG#>RprOS;_8AviU;YaOXXkS@HyP~>KVG~ zYYcsn{a)XT(6Iv~HWl<5^7F=4TqtLZIx?(?bE)=R71xz>%07$W%b;nz^HlUTD!vSK zql?Ak!nBUEWFx)LE}CM@5VmMdQF=4=T}NJ1-z9L;`lQ^fbIMJTh2uUOzJ+U&?IkKU z1lOoB86Qa-y*l)C=9KKEfv$9Pc222mnUat)=<17b5zIArxsH-w)$N9mLUg3+rszqo z_n{jdwUXcHVu}5N9@{YquuasxDboD=?@cQ7>qG8?ZtPSqXO%pP|7o3Hm5a~g7DG3_ zR>jBoVEXwOx@r@K-k9R>u@|e@oY0MJ)zo~3KXjGf&>J0_%fv%fbVZ=ejW_w7IH?Xj zLM*he>nk*JI`uL(SHC<;Z(hyc&>NY=sd^ck>u&fMo9lAORFz*F)zCRH!A){&q{uy=f*@+ zE(c=mD7)X-Xh+m=N&mSiBvvj8d6shZmyy)2Y-f)3?}-*q-x$rHqkX#r_QppHSaknJ zLQG6zVoXeeXHs_dB=tX}D<(k`W6f{%C{Q<32cB|{P;=e zKh(YVKsei`X=!r5OW7Iq(2XDFW%wKWQ~4c?z3RnZ@icU00Yrq{1l_dtMfMz9Jp;;4 z+N|xK$qt{L+Lkc%Hu4*Kqy3=chgq!RKR~b4@-&^~;PCmSYq3LD{nJBzPtYbDn}qoi zBN>x-v}mU1YHza|dd-B0_A>BWF?w6I+GQ2@CA;U?e$EDGXX`m-5s$<5SV(}@Jw?kL zEnji{+@XhRT^ag9acSQp(2Wh(g>1%#TV(IoJ{&_=wxFRm+HdtK9jdxN>{r$} zLR?8-_8Fd`@C-7yRy;H15Bqs?5~*aP;i+UL-?hX=Z$qZha=n&`vYF(mvTqb3^VG|~}fL-W5YE?hQjbwJ=8jLH7J#V)-;Q+c$^Cbd{HDgR3*$1xn$ ztJpY}4D?5IjtDWqUK5ym^#}JSUYZIs`%z-*NOu-r`E!p9>2Q%9zZuP@8YEUOn+5dn|!m_?`nBN_j8Lw-$!tM~vm!nDiU& z^d$YnO+uc2_k=}ys)}r&LJ1e*?^8zKB#zEbQfL3JdQq%aEvTS?9JRc$D#izk7xZ`b zRIDyF>Ev}5?jyNjur)R>K4ofRLbzw_*tFcKVSU%K9w2Juy!!gqvJo=-qWYYonPZYl zM~B2m=a*GwjbD%=7KM2>1{?8@j32 zV%3FGuTjv6aSUABbgPd?pw^ z82pNVA~qXw0im05zNyEd(^!9^>t*N*(+xezUd;LqmA_i^X}Z(U&3Il9-Hhi8?faC! z!trlh3|)=Gs-JwUZ}%Cx8gmSN3Hd*SZtkPH@8&)(7V)k{&_`1*W8Yt_%k8gMJal4c zkYA0BXYCF%Hr7BlW8*@5yY{OLrM~C9x8y3N2QxO-l3yua$+=(K7m{CJx~idn?$9gs z7>GPFMe9M?DU^FZ2cB=##Cp(w{DyPf*Ie6bZ+;wqr@rpLcD~{Kk6vo`^Rlk*VO2{1 zze2{}UGh7wEg`c*T0$NVO$=QWx-Rtb(3e6_vSjDJuzlfG5vdXF5$_MWWzgQiPex9U zTpPJJ^4O4JLvn{a88tj=OVqKU>xZ5iHgDLT=(6a>=o_Qoh#4NUCgxb|I#xHo6?c8y z(Rg?K%J?nu#}kSYHY6NKtV!HG!Wyw@#L=XZk;6xJj@&%*Nb>CD<;kZ~7Nnd=U7LC` ztv+o>+Nt!K^wsH)Wn^cxXROcIl<{)LhgP~(U{zVI)*9<>>v3zJb!yZtW1kzlckJn$ z^qh*E`kb{nPv-2)IXQ0LxFzG3j(cw0%XztZv-2*?Ysp)lw?6NV@$1|R+)Zx3d$oJ5 zd%gP(_h$EY_fGd7_W}3&?&I#h{7v~=^LOO$&fk}RF#l-&>4NZr;RWdhxdmkf(+e63 zmJ}>4SYEKEVCRIw2^URxX~G*54o^5ycx&ON!mWin3U?RoD?C_uwD9!A@QK4Grccae zW!%(>M<<>x3NIR7lwOouxyqKzODGa;%&wIiw_kaE16!>P_m?CY02`EH6`mxZY|kVvbAJK$>EX{rJ^*dlmV%< zptPd2rgUCuV`*pU%F-K4?=Ib5y1R5=>A|w)Wyj0cmai|rqkMDu_VS(Od&&=#zh8d5 zyssj%BC#T~!d+2TF}x*iVA>_Cau#y#s8pk2BSXv)=+o*y|X@^?9S9KqRx7$ecplc1;=2r4~Nr;|x;+>rX4ywcmqX8iz5tBXn8o*QbHs&cBS%!CjT|vUV?F$HDCH$^zP(v3 z3xP8>kH$=Dlnea?J^M6`v+X^&8=`F$!#q}F7Fx=K^9x|5y&J5ykAX9EdJb3R!C?<$ z#(d~*^sohtw6}tp_8XuF4sP_Y8!X{Iy3vEea_*xW*-n6SktAPBQlR-vK!$yc6Y5U! zF=;qYApc2lI%O4dHWiH3m_;3l2?C!&Bs>Jp&^QaqL}YjY^l;TgWKiErF5!+$LBulipY=e0f!Sq@{SFwb(`oi$(&_exU>5rKAjunG zrN(MFctkCddyq=e>vjIQnm*s&4`l&$FNX70FxGw$%pzwoe4YlUkf)ftvkk08&SEiB z<1Bk8=>~o6eET^*4j*k_2gX1zfsab3!J!1%c7a*wyab-xz)CEZ67J)1a0acS1gTyC z=WwS=sOb*1bO;Wmnp>&nRtmRWP|_)j)f<#s3b*ax6rI14`(6sq6JRa!m%>?5>d|~D zt^F{l^jr%6CwUVe%~Mbg|J`7$PNyM5IsEs4N(1F$40md~SG_HCF z%;XuzO^wc{an*<5G@YKI)9N{$rrTJR&RGSYeb_gd$WTrCU1ooo)TjnL0eUpfrY^Nm z_JZokt)<)(SRt8QdkK`+!8vfagjyfL3Q_&i3^CRIipUC?+>tu)5LRh4eOEnlDpd4Y z;QNg1ndof}cpQg!G%d4%JPH+ME|kq+tVSim*QX`*S$g-&{q7$TdT z^kC9mPCAn1=PR8wQJGwiIBC9S>3WH|y$l_U0p)Rh;H23D5~k+-itZvk-bsgu!Z1E) zuj!%CyPR~G7#((%lMaV|r<3NR;$dv&*ZKM0O4w6QI?}Z|?9Wbmi0}-W>!hPZ;h^u` zZxt346j%-3Rn|;zz}wW}b6fM;J9@0vZhz2H$AHhb!W)3x;PbXv-eAz%-0o|!g1(hO ztF@!kN6vuN;tP5^I(yt!t-rO~%C>r!wRnTR9&33=Pe;&Nv0{b0({NX8d)&?4U2dzY z+wTo_bo+a(wg8!1dpkQEPm-?AY5z30Cyzs0%A-5%`fbX%33J>5A$1GMb$vZgD2C_Q_dP-U>&>TYfI1*~3w z$CbUvkMi}M=&^$Bf$rY6c8)%)&FA;=tH_)=iY5r4O$G^1^UmTd+~}@P-b!r@V`lP2p=YbMF-PPx`$M&=oWr9 z6s#T_$uGk*z_Ep2Dz~Ed=yGc* zOO-Tt*(n)2C%wu4U-Z+*TmL3a;to{8`!irB&RT;nStLR_Qt@J{>xx>eZ&N zQk+{Ur;|UW2_<rC$#wU$@q2fbu%vF;EBRyQAtJDqRfJv#N6k zrS!LxBDhq;wToP;>>gT;5A7+PDb1TUbZ!eOw4iw#RRP96YReY3YR4Y|aWgQy7 zg5Q3)pDTr_i)lyw?Rh-cb#UJlm!*`}#L=top#^O@|4lpkdW+2?pJ@Rqw`plzx`wJB zP-j)m`t_zHHf0$7saCA=DGo+&0gitD`sMz5&CW{Ij6|v@F;}ZPDh;mSIPkf)Fus)L zR%w~k6QDHQN!zr*4m6}{Y^3?R&i`3^82Ci?KUJoU_xFqgr7%yck?eeZnR@Dj-0d)sdJ=QVJT{M+sGG_aFjp*O zZdb(IO)X|GVdhcBOrZknzlw);eH;pftGSt*z`Od=PokQ0#mw{$J@3X%lzRCLZ z%fv#Kk}SqL|FhW74v-LWlX#1mPH&69h}XqC;#!)L_;A@p>B1Kw)!AL1^eQ+!y$GOMi7~1 zka$lHmXWN78X^wLC^?kfcEiNGgdL8Nu|%?pW9?FcOcY-UoA+Nya->X_DTL=q6USI* zmm%JimiS1Hl9@6~juw4V$T3*^ugS48M_wRvS(=|G$4j?3BJ;&@@tOFWED$GHjq@qn z1wIxZilgF`oFKj+R@Owx_YtH=7RwS@D$9tSRe=S6k(?~2$VxetNLp30T27Z2%NkiL zFOf6E#xS=ZD=NIp+Z^cjM@*ktP*63!eb_QzprgB`+2;@X0=|~;x!&g9pf7x0vzJWa zmziHZ<`6W*)%sUNWp`V*-*-jSTxGv{l?m(*Mqbv^jj64Y5nktf&w%scGYyMQeTZCr zCU&Dr(+9c>;!q*A&}niuF0g`b@Dcrq~vzSiiZ%Z;I_6$U8h>itW|K_6|H1 z6&z6P&{oRTvxrV_PkUtT88t)&2IPvUHF88$nv$a$2A-@o#K`Ki7hgQ!eAJ8qKO$-! z4l@T3qv{9zh?r$^M9g=}obUYZaDIE8-#&AU^qnoXZ2+IBD+d1X5BL$$?QrOIIQI6J zV2)9p12U^#(M7N4!uOB6les9Hd8MTPJ2l9LK7@JtU=amI@@_zVBO#i-8d3O6zNCkY z1&4{@M2LvyD=B}cw@d()|MN7xW)c{O7xXl}XEK<8|MLra(KK)bK9(=&O)dKrJ?bbh znR)stde+hQ=k%^)z%-E!ri-y)20I&1GI-^Jqr^BcQ;fI&MvvhJM~i%LjP}xGi$Z4l zW5q-;M-+h<;HmhGez_PNhv)4x`sXq{0Bnf_*+mEDi;L_}>8~e)go6SL@lkwA-#rb# zABGkL1#W{oYx$~?$O@?HE_tzs?MCawqD!FL!< zZUC2x?}Jx}oA5bzigjR@_yOn_H-p_`JzlS6;z!_>;>TbBe3S9#r(jUr0``hq@yIO~ zKLb~Y+rX9Lc5s!r6ED+hu>rhF+znn09$=ig2mF?}7yP#PInheKBklvQ5%+^@#AfhX zu?7Ftb>f%ccg3&3wcu-vmk)v0i>=`I#5R0cH;6~T@3TK=ALHnw;7#J!_N!u@_zn02 z@i=%hxR;S{2e@850sct*9*^IDiJjn&#Z%x<#53Se#V-6{w}|J!{}#`Kw~F2P@qQ-$ z0Ny742;MIC;5ocQyae89A9#;=4bR)XVn4V^8~}eVUbp`! z?h|i<_iNlN-X{GE@eUrsE#e^fOYtuFfH;IN@mJzK@Imoc@F8&+kLXtMA^5PyZQ=;& zN5seW^H>z0fRBn}Ai?VJ#Qs_w2Y(|@fWH-gv!4}@i_gK|Y1|>cApL|mjpz1B@g?|s z@fEmJ^x4mdr+Df3jCfi~@EPgCkGe~Sg3oGvPKJ|yUJkOK61(MK@DFkb_yV|7{80`C z_sC)3i!#Rky?9B+f`5|3!Ixzm_=-%x)4NwDg0IRXa3A;tmOwJNU#5V6mTCBP56E=z zb(sOaAuaGtnQ8w{yd|^1x8)e{9q@7S7daL@D09GfWv=~Otd?=$domAvUycX=D)aI4 zAC?8+2eJ_S5d1YZNfCHNP69uc#Ws;YWC{3*ECr9rGVoJbVLvL4%L~EJg|XB2VU(0@Bjb+ literal 0 HcmV?d00001 diff --git a/Upload/inc/captcha_fonts/index.html b/Upload/inc/captcha_fonts/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/captcha_fonts/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/captcha_fonts/read_me.html b/Upload/inc/captcha_fonts/read_me.html new file mode 100644 index 0000000..25f2dae --- /dev/null +++ b/Upload/inc/captcha_fonts/read_me.html @@ -0,0 +1,253 @@ + + + + + + Larabie Fonts "read me" file, license and FAQ + + + + + +

    + LARABIE FONTS “README.TXT” +

    +

    + All Larabie Fonts in this file are free to use for personal and/or commercial purposes. No + payment is necessary to use these fonts for personal or commercial use. For Software Products + who want to include Larabie Fonts see the License Agreement below. You can add this font to a + website but do not combine fonts into a single archive or alter them in any way. +

    +
    +

    + Some Larabie Fonts have enhanced and expanded families available for sale at www.typodermic.com. +

    +

    + If you'd like to make a voluntary donation to Larabie Fonts for the use of the free fonts in + any amount please go to www.larabiefonts.com/donation.html +

    +

    + I accept CDs, magazines, t-shirts, a sample of your merchandise or anything featuring Larabie + Fonts. Please remember to list your item as a ‘gift’ on the customs form or I will have to + pay import duties and taxes on the item. Mailing information is provided at the link above. +

    +

    + Font installation help is available at www.larabiefonts.com/help.html +

    +

    + LARABIE FONTS FREQUENTLY ASKED QUESTIONS +

    +
      +
    • Q: How do use these fonts in my favourite software? +
    • +
    • A: In Windows, you take the fonts out of the ZIP archive and place them in your fonts + folder which can be found in your Control Panel. The next time you run your software, the + font will be available. For example: If you install a new font, the next time you run + Microsoft Word, that font will be available in the menu under Format / Font. For anything + more complicated, or Mac installation, visit + www.larabiefonts.com/help.html +
    • +
    +
      +
    • Q: How can I use this font in AOL Instant + Messenger, MSN Messenger, Outlook, Outlook Express, Euodora or any other email software? +
    • +
    • A: At the time of this writing (Feb 2004) you can’t. After installing one of my fonts, + you may be able to select it in the above applications but the person at the other end won’t + see that same thing unless they have the font installed. If you really want to use my fonts + in these applications, make sure the people at the other end have the same fonts installed. +
    • +
    +
      +
    • Q: How can I use these fonts on a web page? +
    • +
    • A: If you’re creating a web page using Flash, it’s easy. Consult your Flash manual. If + you’re using Acrobat, make sure the font + embedding settings are turned on. Consult your Acrobat manual. For anything else there are + limitations: If you want to use one of my fonts as your main, text font you’re pretty much + out of luck unless you explore a font embedding tool such as WEFT but I don’t recommend it. + To use my fonts as headings or titles, use image creation software such as The Gimp, Photoshop, Paint Shop Pro, Pixia etc. Save the images as GIF files and place + them on your web page. There’s a lot more to it than can be explained here but there are + countless books available on web page design. +
    • +
    +
      +
    • Q: How can I make these fonts bigger? +
    • +
    • A: All my fonts are infinitely scalable; the limitations are in your software. A common + problem is scaling fonts in Microsoft Word. If you choose Format / Font you can type in any + number you like under “size”. +
    • +
    +
      +
    • Q: Are these fonts really free? +
    • +
    • A: Yes they are. Some fonts such as Neuropol have expanded font families available + for sale at www.typodermic.com but the version you + downloaded at Larabie Fonts is free. +
    • +
    +
      +
    • Q: Your licence agreement states that the fonts can’t be altered. Does that mean I can’t + mess around with your fonts in Photoshop/Illustrator/Publisher etc? +
    • +
    • A: Those license restrictions refer to altering the actual fonts themselves, not what you + make with them. As long as you don’t alter the font files in font creation software such as + FontLab or Fontographer you’re free to create anything you like with them. +
    • +
    +
      +
    • Q: Can I use your fonts in a logo? +
    • +
    • A: Yes. But check with a lawyer if you’re not sure. It’s okay with me if you use it but + do so at your own risk. +
    • +
    +
      +
    • Q: Can I send you a sample of the nifty thing I created with your fonts? +
    • +
    • A: Of course. Check www.larabiefonts.com/donation.html for my + current email or mailing address. +
    • +
    +
      +
    • Q: Can you make a custom font for me? +
    • +
    • A: Possibly. Check typodermic.com/custom.html for details. Keep in mind + that making fonts is my full-time job so no freebies. +
    • +
    + +
      +
    • Q: I want to sell rubber stamp alphabets, alphabet punches or stencil alphabets using + your font designs. +
    • +
    • A: Contact me first at www.larabiefonts.com/email.html. +
    • +
    +
      +
    • Q: My software won’t let me embed one of your fonts. +
    • +
    • A: You may have an old version of one of my fonts. Uninstall it and install a current + version on Larabie Fonts. +
    • +
    +
      +
    • Q: Can you help me find a font? +
    • +
    • A: I really don’t have the time but if you send a donation, I can give it a try. If not. + post your question on my font forum: www.larabiefonts.com/info.html. +
    • +
    +

    + LARABIE FONTS END-USER LICENSE AGREEMENT FOR SOFTWARE PRODUCTS +

    +

    + SOFTWARE PRODUCT LICENSE +

    +

    + The SOFTWARE PRODUCT is protected by copyright laws and International copyright treaties, as + well as other intellectual property laws and treaties. The SOFTWARE PRODUCT is licensed, not + sold. +

    +
    + 1. GRANT OF LICENSE. This document grants you the following rights: +
    +

    + - Installation and Use. You may install and use an unlimited number of copies of the SOFTWARE + PRODUCT. You may copy and distribute unlimited copies of the SOFTWARE PRODUCT as you receive + them, in any medium, provided that you publish on each copy an appropriate copyright notice. + Keep intact all the notices that refer to this License and give any other recipients of the + fonts a copy of this License along with the fonts. +

    +
    + 2. DESCRIPTION OF OTHER RIGHTS AND LIMITATIONS. +
    +

    + - You may modify your copy or copies of the SOFTWARE PRODUCT or any portion of it, provided + that you also meet all of these rules: +

    +

    + a) Do not alter in any way alphanumeric characters (A-Z, a-z, 1-9) contained in the font. An + exception is converting between formats, here is allowed the nominal distortion that occurs + during conversion from second order to third order quadratic curves (TrueType to Postscript) + and vice versa. +

    +

    + b) Extra characters may be added; here it is allowed to use curves (shapes) from alphanumeric + characters in fonts under same license. +

    +

    + c) It is allowed to modify and remove analpahbetics (punctuation, special characters, + ligatures and symbols). +

    +

    + d) The original font name must be retained but can be augmented. (ie. a Font named Blue + Highway can be renamed Blue Highway Cyrillic or Blue Highway ANSI, etc.) +

    +

    + e) Character mapping may be altered. +

    +

    + f) If the kerning information is altered or discarded it must be stated in the user notes or + documentation. +

    +

    + g) All modifications must be released under this license. +

    +

    +   +

    LIMITED WARRANTY NO WARRANTIES. Larabie Fonts expressly disclaims any warranty for the + SOFTWARE PRODUCT. The SOFTWARE PRODUCT and any related documentation is provided "as is" + without warranty of any kind, either express or implied, including, without limitation, the + implied warranties or merchantability, fitness for a particular purpose, or non-infringement. + The entire risk arising out of use or performance of the SOFTWARE PRODUCT remains with you. +

    +   +

    +

    + NO LIABILITY FOR CONSEQUENTIAL DAMAGES. In no event shall Larabie Fonts be liable for any + damages whatsoever (including, without limitation, damages for loss of business profits, + business interruption, loss of business information, or any other pecuniary loss) arising out + of the use of or inability to use this product, even if Larabie Fonts has been advised of the + possibility of such damages. +

    +
    + 3. MISCELLANEOUS +
    +

    + Should you have any questions concerning this document, or if you desire to contact Larabie + Fonts for any reason, please email www.larabiefonts.com/email.html. +

    + + \ No newline at end of file diff --git a/Upload/inc/class_captcha.php b/Upload/inc/class_captcha.php new file mode 100644 index 0000000..0f7e632 --- /dev/null +++ b/Upload/inc/class_captcha.php @@ -0,0 +1,461 @@ +type = $mybb->settings['captchaimage']; + + // Prepare the build template + if($template) + { + $this->captcha_template = $template; + + if($this->type == 2) + { + $this->captcha_template .= "_recaptcha"; + } + else if($this->type == 3) + { + $this->captcha_template .= "_ayah"; + } + } + + // Work on which CAPTCHA we've got installed + if($this->type == 3 && $mybb->settings['ayahpublisherkey'] && $mybb->settings['ayahscoringkey']) + { + // We want to use Are You a Human, set configuration options + $this->ayah_web_service_host = "ws.areyouahuman.com"; + $this->ayah_publisher_key = $mybb->settings['ayahpublisherkey']; + $this->ayah_scoring_key = $mybb->settings['ayahscoringkey']; + $this->ayah_debug_mode = false; + $this->ayah_use_curl = true; + + if($build == true) + { + $this->build_ayah(); + } + } + else if($this->type == 2 && $mybb->settings['captchapublickey'] && $mybb->settings['captchaprivatekey']) + { + // We want to use reCAPTCHA, set the server options + $this->server = "http://www.google.com/recaptcha/api"; + $this->secure_server = "https://www.google.com/recaptcha/api"; + $this->verify_server = "www.google.com"; + + if($build == true) + { + $this->build_recaptcha(); + } + } + else if($this->type == 1) + { + if(!function_exists("imagecreatefrompng")) + { + // We want to use the default CAPTCHA, but it's not installed + return false; + } + else if($build == true) + { + $this->build_captcha(); + } + } + + // Plugin hook + } + + function build_captcha($return = false) + { + global $db, $lang, $templates, $theme, $mybb; + + // This will build a MyBB CAPTCHA + $randomstr = random_str(5); + $imagehash = md5(random_str(12)); + + $insert_array = array( + "imagehash" => $imagehash, + "imagestring" => $randomstr, + "dateline" => TIME_NOW + ); + + $db->insert_query("captcha", $insert_array); + eval("\$this->html = \"".$templates->get($this->captcha_template)."\";"); + //eval("\$this->html = \"".$templates->get("member_register_regimage")."\";"); + } + + function build_recaptcha() + { + global $lang, $mybb, $templates; + + // This will build a reCAPTCHA + $server = $this->server; + $public_key = $mybb->settings['captchapublickey']; + + if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') + { + // Use secure server if HTTPS + $server = $this->secure_server; + } + + eval("\$this->html = \"".$templates->get($this->captcha_template, 1, 0)."\";"); + //eval("\$this->html = \"".$templates->get("member_register_regimage_recaptcha")."\";"); + } + + function build_ayah() + { + global $lang, $mybb, $templates; + + define('AYAH_PUBLISHER_KEY', $this->ayah_publisher_key); + define('AYAH_SCORING_KEY', $this->ayah_scoring_key); + define('AYAH_USE_CURL', $this->ayah_use_curl); + define('AYAH_DEBUG_MODE', $this->ayah_debug_mode); + define('AYAH_WEB_SERVICE_HOST', $this->ayah_web_service_host); + + require_once MYBB_ROOT."inc/3rdparty/ayah/ayah.php"; + $ayah = new AYAH(); + $output = $ayah->getPublisherHTML(); + + if(!empty($output)) + { + eval("\$this->html = \"".$templates->get($this->captcha_template, 1, 0)."\";"); + //eval("\$this->html = \"".$templates->get("member_register_regimage_ayah")."\";"); + } + } + + function build_hidden_captcha() + { + global $db, $mybb, $templates; + + $field = array(); + + if($this->type == 1) + { + // Names + $hash = "imagehash"; + $string = "imagestring"; + + // Values + $field['hash'] = $db->escape_string($mybb->input['imagehash']); + $field['string'] = $db->escape_string($mybb->input['imagestring']); + } + else if($this->type == 2) + { + // Names + $hash = "recaptcha_challenge_field"; + $string = "recaptcha_response_field"; + + // Values + $field['hash'] = $mybb->input['recaptcha_challenge_field']; + $field['string'] = $mybb->input['recaptcha_response_field']; + } + else if($this->type == 3) + { + // Are You a Human can't be built as a hidden captcha + continue; + } + + eval("\$this->html = \"".$templates->get("post_captcha_hidden")."\";"); + return $this->html; + } + + function validate_captcha() + { + global $db, $lang, $mybb; + + // Plugin hook + + if($this->type == 1) + { + // We have a normal CAPTCHA to handle + $imagehash = $db->escape_string($mybb->input['imagehash']); + $imagestring = $db->escape_string(my_strtolower($mybb->input['imagestring'])); + + $query = $db->simple_select("captcha", "*", "imagehash = '{$imagehash}' AND LOWER(imagestring) = '{$imagestring}'"); + $imgcheck = $db->fetch_array($query); + + if(!$imgcheck) + { + $this->set_error($lang->invalid_captcha_verify); + $db->delete_query("captcha", "imagehash = '{$imagehash}'"); + } + } + elseif($this->type == 2) + { + $challenge = $mybb->input['recaptcha_challenge_field']; + $response = $mybb->input['recaptcha_response_field']; + + if(!$challenge || strlen($challenge) == 0 || !$response || strlen($response) == 0) + { + $this->set_error($lang->invalid_captcha); + } + else + { + // We have a reCAPTCHA to handle + $data = $this->_qsencode(array( + 'privatekey' => $mybb->settings['captchaprivatekey'], + 'remoteip' => $session->ipaddress, + 'challenge' => $challenge, + 'response' => $response + )); + + // Contact Google and see if our reCAPTCHA was successful + $http_request = "POST /recaptcha/api/verify HTTP/1.0\r\n"; + $http_request .= "Host: $this->verify_server\r\n"; + $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n"; + $http_request .= "Content-Length: ".strlen($data)."\r\n"; + $http_request .= "User-Agent: reCAPTCHA/PHP\r\n"; + $http_request .= "\r\n"; + $http_request .= $data; + + $fs = @fsockopen($this->verify_server, 80, $errno, $errstr, 10); + + if($fs == false) + { + $this->set_error($lang->invalid_captcha_transmit); + } + else + { + // We connected, but is it correct? + fwrite($fs, $http_request); + + while(!feof($fs)) + { + $response .= fgets($fs, 1160); + } + + fclose($fs); + + $response = explode("\r\n\r\n", $response, 2); + $answer = explode("\n", $response[1]); + + if(trim($answer[0]) != 'true') + { + // We got it wrong! Oh no... + $this->set_error($lang->invalid_captcha_verify); + } + } + } + } + elseif($this->type == 3) + { + define('AYAH_PUBLISHER_KEY', $this->ayah_publisher_key); + define('AYAH_SCORING_KEY', $this->ayah_scoring_key); + define('AYAH_USE_CURL', $this->ayah_use_curl); + define('AYAH_DEBUG_MODE', $this->ayah_debug_mode); + define('AYAH_WEB_SERVICE_HOST', $this->ayah_web_service_host); + + require_once MYBB_ROOT."inc/3rdparty/ayah/ayah.php"; + $ayah = new AYAH(); + + $result = $ayah->scoreResult(); + + if($result == false) + { + $this->set_error($lang->invalid_ayah_result); + } + } + + // Plugin hook + + if(count($this->errors) > 0) + { + return false; + } + else + { + return true; + } + } + + function invalidate_captcha() + { + global $db, $mybb; + + if($this->type == 1) + { + // We have a normal CAPTCHA to handle + $imagehash = $db->escape_string($mybb->input['imagehash']); + if($imagehash) + { + $db->delete_query("captcha", "imagehash = '{$imagehash}'"); + } + } + // Not necessary for reCAPTCHA or Are You a Human + + // Plugin hook + } + + /** + * Add an error to the error array. + */ + function set_error($error, $data='') + { + $this->errors[$error] = array( + "error_code" => $error, + "data" => $data + ); + } + + /** + * Returns the error(s) that occurred when handling data + * in a format that MyBB can handle. + * + * @return An array of errors in a MyBB format. + */ + function get_errors() + { + global $lang; + + foreach($this->errors as $error) + { + $lang_string = $error['error_code']; + + if(!$lang_string) + { + if($lang->invalid_captcha_verify) + { + $lang_string = 'invalid_captcha_verify'; + } + else + { + $lang_string = 'unknown_error'; + } + } + + if(!isset($lang->$lang_string)) + { + $errors[] = $error['error_code']; + continue; + } + + if(!empty($error['data']) && !is_array($error['data'])) + { + $error['data'] = array($error['data']); + } + + if(is_array($error['data'])) + { + array_unshift($error['data'], $lang->$lang_string); + $errors[] = call_user_func_array(array($lang, "sprintf"), $error['data']); + } + else + { + $errors[] = $lang->$lang_string; + } + } + + return $errors; + } + + private function _qsencode($data) + { + $req = ''; + foreach($data as $key => $value) + { + $req .= $key.'='.urlencode(stripslashes($value)).'&'; + } + + $req = substr($req, 0, (strlen($req) - 1)); + + return $req; + } +} diff --git a/Upload/inc/class_core.php b/Upload/inc/class_core.php new file mode 100644 index 0000000..5264d14 --- /dev/null +++ b/Upload/inc/class_core.php @@ -0,0 +1,622 @@ + array( + "tid", "pid", "uid", + "eid", "pmid", "fid", + "aid", "rid", "sid", + "vid", "cid", "bid", + "hid", "gid", "mid", + "wid", "lid", "iid", + "did", "qid", "id" + ), + "pos" => array( + "page", "perpage" + ), + "a-z" => array( + "sortby", "order" + ) + ); + + /** + * Variables that are to be ignored from cleansing process + * + * @var array + */ + public $ignore_clean_variables = array(); + + /** + * Using built in shutdown functionality provided by register_shutdown_function for < PHP 5? + */ + public $use_shutdown = true; + + /** + * Debug mode? + */ + public $debug_mode = false; + + /** + * Binary database fields need to be handled differently + */ + public $binary_fields = array( + 'adminlog' => array('ipaddress' => true), + 'adminsessions' => array('ip' => true), + 'maillogs' => array('ipaddress' => true), + 'moderatorlog' => array('ipaddress' => true), + 'posts' => array('ipaddress' => true), + 'privatemessages' => array('ipaddress' => true), + 'searchlog' => array('ipaddress' => true), + 'sessions' => array('ip' => true), + 'threadratings' => array('ipaddress' => true), + 'users' => array('regip' => true, 'lastip' => true), + 'spamlog' => array('ipaddress' => true), + ); + + /** + * The cache instance to use. + * + * @var datacache + */ + public $cache; + + /** + * The base URL to assets. + * + * @var string + */ + public $asset_url = null; + /** + * String input constant for use with get_input(). + * + * @see get_input + */ + const INPUT_STRING = 0; + /** + * Integer input constant for use with get_input(). + * + * @see get_input + */ + const INPUT_INT = 1; + /** + * Array input constant for use with get_input(). + * + * @see get_input + */ + const INPUT_ARRAY = 2; + /** + * Float input constant for use with get_input(). + * + * @see get_input + */ + const INPUT_FLOAT = 3; + /** + * Boolean input constant for use with get_input(). + * + * @see get_input + */ + const INPUT_BOOL = 4; + + /** + * Constructor of class. + * + * @return MyBB + */ + function __construct() + { + // Set up MyBB + $protected = array("_GET", "_POST", "_SERVER", "_COOKIE", "_FILES", "_ENV", "GLOBALS"); + foreach($protected as $var) + { + if(isset($_POST[$var]) || isset($_GET[$var]) || isset($_COOKIE[$var]) || isset($_FILES[$var])) + { + die("Hacking attempt"); + } + } + + if(defined("IGNORE_CLEAN_VARS")) + { + if(!is_array(IGNORE_CLEAN_VARS)) + { + $this->ignore_clean_variables = array(IGNORE_CLEAN_VARS); + } + else + { + $this->ignore_clean_variables = IGNORE_CLEAN_VARS; + } + } + + // Determine Magic Quotes Status (< PHP 6.0) + if(version_compare(PHP_VERSION, '6.0', '<')) + { + if(@get_magic_quotes_gpc()) + { + $this->magicquotes = 1; + $this->strip_slashes_array($_POST); + $this->strip_slashes_array($_GET); + $this->strip_slashes_array($_COOKIE); + } + @set_magic_quotes_runtime(0); + @ini_set("magic_quotes_gpc", 0); + @ini_set("magic_quotes_runtime", 0); + } + + // Determine input + $this->parse_incoming($_GET); + $this->parse_incoming($_POST); + + if($_SERVER['REQUEST_METHOD'] == "POST") + { + $this->request_method = "post"; + } + else if($_SERVER['REQUEST_METHOD'] == "GET") + { + $this->request_method = "get"; + } + + // If we've got register globals on, then kill them too + if(@ini_get("register_globals") == 1) + { + $this->unset_globals($_POST); + $this->unset_globals($_GET); + $this->unset_globals($_FILES); + $this->unset_globals($_COOKIE); + } + $this->clean_input(); + + $safe_mode_status = @ini_get("safe_mode"); + if($safe_mode_status == 1 || strtolower($safe_mode_status) == 'on') + { + $this->safemode = true; + } + + // Are we running on a development server? + if(isset($_SERVER['MYBB_DEV_MODE']) && $_SERVER['MYBB_DEV_MODE'] == 1) + { + $this->dev_mode = 1; + } + + // Are we running in debug mode? + if(isset($this->input['debug']) && $this->input['debug'] == 1) + { + $this->debug_mode = true; + } + + if(isset($this->input['action']) && $this->input['action'] == "mybb_logo") + { + require_once dirname(__FILE__)."/mybb_group.php"; + output_logo(); + } + + if(isset($this->input['intcheck']) && $this->input['intcheck'] == 1) + { + die("MYBB"); + } + } + + /** + * Parses the incoming variables. + * + * @param array The array of incoming variables. + */ + function parse_incoming($array) + { + if(!is_array($array)) + { + return; + } + + foreach($array as $key => $val) + { + $this->input[$key] = $val; + } + } + + /** + * Parses the incoming cookies + * + */ + function parse_cookies() + { + if(!is_array($_COOKIE)) + { + return; + } + + $prefix_length = strlen($this->settings['cookieprefix']); + + foreach($_COOKIE as $key => $val) + { + if($prefix_length && substr($key, 0, $prefix_length) == $this->settings['cookieprefix']) + { + $key = substr($key, $prefix_length); + + // Fixes conflicts with one board having a prefix and another that doesn't on the same domain + // Gives priority to our cookies over others (overwrites them) + if($this->cookies[$key]) + { + unset($this->cookies[$key]); + } + } + + if(empty($this->cookies[$key])) + { + $this->cookies[$key] = $val; + } + } + } + + /** + * Strips slashes out of a given array. + * + * @param array The array to strip. + */ + function strip_slashes_array(&$array) + { + foreach($array as $key => $val) + { + if(is_array($array[$key])) + { + $this->strip_slashes_array($array[$key]); + } + else + { + $array[$key] = stripslashes($array[$key]); + } + } + } + + /** + * Unsets globals from a specific array. + * + * @param array The array to unset from. + */ + function unset_globals($array) + { + if(!is_array($array)) + { + return; + } + + foreach(array_keys($array) as $key) + { + unset($GLOBALS[$key]); + unset($GLOBALS[$key]); // Double unset to circumvent the zend_hash_del_key_or_index hole in PHP <4.4.3 and <5.1.4 + } + } + + /** + * Cleans predefined input variables. + * + */ + function clean_input() + { + foreach($this->clean_variables as $type => $variables) + { + foreach($variables as $var) + { + // If this variable is in the ignored array, skip and move to next. + if(in_array($var, $this->ignore_clean_variables)) + { + continue; + } + + if(isset($this->input[$var])) + { + switch($type) + { + case "int": + $this->input[$var] = $this->get_input($var, 1); + break; + case "a-z": + $this->input[$var] = preg_replace("#[^a-z\.\-_]#i", "", $this->get_input($var)); + break; + case "pos": + if(($this->input[$var] < 0 && $var != "page") || ($var == "page" && $this->input[$var] != "last" && $this->input[$var] < 0)) + $this->input[$var] = 0; + break; + } + } + } + } + } + + /** + * Checks the input data type before usage. + * + * @param string $name Variable name ($mybb->input) + * @param int $type The type of the variable to get. Should be one of MyBB::INPUT_INT, MyBB::INPUT_ARRAY or MyBB::INPUT_STRING. + * + * @return mixed Checked data + */ + function get_input($name, $type = MyBB::INPUT_STRING) + { + switch($type) + { + case MyBB::INPUT_ARRAY: + if(!isset($this->input[$name]) || !is_array($this->input[$name])) + { + return array(); + } + return $this->input[$name]; + case MyBB::INPUT_INT: + if(!isset($this->input[$name]) || !is_numeric($this->input[$name])) + { + return 0; + } + return (int)$this->input[$name]; + case MyBB::INPUT_FLOAT: + if(!isset($this->input[$name]) || !is_numeric($this->input[$name])) + { + return 0.0; + } + return (float)$this->input[$name]; + case MyBB::INPUT_BOOL: + if(!isset($this->input[$name]) || !is_scalar($this->input[$name])) + { + return false; + } + return (bool)$this->input[$name]; + default: + if(!isset($this->input[$name]) || !is_scalar($this->input[$name])) + { + return ''; + } + return $this->input[$name]; + } + } + + /** + * Get the path to an asset using the CDN URL if configured. + * + * @param string $path The path to the file. + * @param bool $use_cdn Whether to use the configured CDN options. + * + * @return string The complete URL to the asset. + */ + public function get_asset_url($path = '', $use_cdn = true) + { + $path = (string) $path; + $path = ltrim($path, '/'); + + if(substr($path, 0, 4) != 'http') + { + if(substr($path, 0, 2) == './') + { + $path = substr($path, 2); + } + + $base_path = ''; + if($use_cdn && $this->settings['usecdn'] && !empty($this->settings['cdnurl'])) + { + $base_path = rtrim($this->settings['cdnurl'], '/'); + } + else + { + $base_path = rtrim($this->settings['bburl'], '/'); + } + + $url = $base_path; + + if(!empty($path)) + { + $url = $base_path . '/' . $path; + } + } + else + { + $url = $path; + } + + return $url; + } + + /** + * Triggers a generic error. + * + * @param string The error code. + */ + function trigger_generic_error($code) + { + global $error_handler; + + switch($code) + { + case "cache_no_write": + $message = "Katalog z pamięcią podręczną (cache/) musi istnieć na serwerze i posiadać prawa do zapisu. Zmień jego uprawnienia CHMOD na 777, aby MyBB mogło zapisywać w nim pliki (tylko serwery Unix/Linux)."; + $error_code = MYBB_CACHE_NO_WRITE; + break; + case "install_directory": + $message = "Katalog instalacyjny (install/) wciąż znajduje się na serwerze i nie został zablokowany. Aby przejść do swojego forum usuń ten katalog lub zablokuj go za pomocą pustego pliku o nazwie 'lock'."; + $error_code = MYBB_INSTALL_DIR_EXISTS; + break; + case "board_not_installed": + $message = "MyBB nie zostało jeszcze zainstalowane i skonfigurowane. Zrób to, zanim przystąpisz do przeglądania forum."; + $error_code = MYBB_NOT_INSTALLED; + break; + case "board_not_upgraded": + $message = "MyBB nie zostało jeszcze zaktualizowane. Zrób to, zanim przystąpisz do przeglądania forum."; + $error_code = MYBB_NOT_UPGRADED; + break; + case "sql_load_error": + $message = "MyBB nie może załadować obsługi serwera SQL. Odwiedź Polski Support MyBB aby uzyskać pomoc."; + $error_code = MYBB_SQL_LOAD_ERROR; + break; + case "apc_load_error": + $message = "Aby korzystać z systemu APC, należy go skonfigurować do pracy z PHP."; + $error_code = MYBB_CACHEHANDLER_LOAD_ERROR; + break; + case "eaccelerator_load_error": + $message = "Aby korzystać z systemu eAccelerator, należy go skonfigurować do pracy z PHP."; + $error_code = MYBB_CACHEHANDLER_LOAD_ERROR; + break; + case "memcache_load_error": + $message = "Twój serwer nie posiada wsparcia dla memcache."; + $error_code = MYBB_CACHEHANDLER_LOAD_ERROR; + break; + case "memcached_load_error": + $message = "Twój serwer nie posiada wsparcia dla memcached."; + $error_code = MYBB_CACHEHANDLER_LOAD_ERROR; + break; + case "xcache_load_error": + $message = "Aby korzystać z systemu Xcache, należy go skonfigurować do pracy z PHP."; + $error_code = MYBB_CACHEHANDLER_LOAD_ERROR; + break; + default: + $message = "MyBB napotkało błąd wewnętrzny. Odwiedź Polski Support MyBB aby uzyskać pomoc."; + $error_code = MYBB_GENERAL; + } + $error_handler->trigger($message, $error_code); + } + + function __destruct() + { + // Run shutdown function + if(function_exists("run_shutdown")) + { + run_shutdown(); + } + } +} + +/** + * Do this here because the core is used on every MyBB page + */ + +$grouppermignore = array("gid", "type", "title", "description", "namestyle", "usertitle", "stars", "starimage", "image"); +$groupzerogreater = array("pmquota", "maxpmrecipients", "maxreputationsday", "attachquota", "maxemails", "maxwarningsday", "maxposts", "edittimelimit", "canusesigxposts", "maxreputationsperthread", "emailfloodtime"); +$displaygroupfields = array("title", "description", "namestyle", "usertitle", "stars", "starimage", "image"); + +// These are fields in the usergroups table that are also forum permission specific. +$fpermfields = array( + 'canview', + 'canviewthreads', + 'candlattachments', + 'canpostthreads', + 'canpostreplys', + 'canpostattachments', + 'canratethreads', + 'caneditposts', + 'candeleteposts', + 'candeletethreads', + 'caneditattachments', + 'modposts', + 'modthreads', + 'modattachments', + 'mod_edit_posts', + 'canpostpolls', + 'canvotepolls', + 'cansearch' +); + diff --git a/Upload/inc/class_custommoderation.php b/Upload/inc/class_custommoderation.php new file mode 100644 index 0000000..6e20690 --- /dev/null +++ b/Upload/inc/class_custommoderation.php @@ -0,0 +1,498 @@ +
    Please make sure IN_MYBB is defined."); +} + +/** + * Used to execute a custom moderation tool + * + */ + +class CustomModeration extends Moderation +{ + /** + * Get info on a tool + * + * @param int Tool ID + * @param mixed Thread IDs + * @param mixed Post IDs + * @return mixed Returns tool data (tid, type, name, description) in an array, otherwise boolean false. + */ + function tool_info($tool_id) + { + global $db; + + // Get tool info + $query = $db->simple_select("modtools", "*", 'tid="'.(int)$tool_id.'"'); + $tool = $db->fetch_array($query); + if(!$tool['tid']) + { + return false; + } + else + { + return $tool; + } + } + + /** + * Execute Custom Moderation Tool + * + * @param int Tool ID + * @param mixed Thread ID(s) + * @param mixed Post IDs + * @return string 'forum' or 'default' indicating where to redirect + */ + function execute($tool_id, $tids=0, $pids=0) + { + global $db; + + // Get tool info + $query = $db->simple_select("modtools", '*', 'tid="'.(int)$tool_id.'"'); + $tool = $db->fetch_array($query); + if(!$tool['tid']) + { + return false; + } + + // Format single tid and pid + if(!is_array($tids)) + { + $tids = array($tids); + } + if(!is_array($pids)) + { + $pids = array($pids); + } + + // Unserialize custom moderation + $post_options = my_unserialize($tool['postoptions']); + $thread_options = my_unserialize($tool['threadoptions']); + + // If the tool type is a post tool, then execute the post moderation + if($tool['type'] == 'p') + { + $deleted_thread = $this->execute_post_moderation($post_options, $pids, $tids); + } + // Always execute thead moderation + $this->execute_thread_moderation($thread_options, $tids); + + // If the thread is deleted, indicate to the calling script to redirect to the forum, and not the nonexistant thread + if($thread_options['deletethread'] == 1 || $deleted_thread === 1) + { + return 'forum'; + } + return 'default'; + } + + /** + * Execute Inline Post Moderation + * + * @param array Moderation information + * @param mixed Post IDs + * @param array Thread IDs (in order of dateline ascending) + * @return boolean true + */ + function execute_post_moderation($post_options, $pids, $tid) + { + global $db, $mybb, $lang; + + if(is_array($tid)) + { + $tid = (int)$tid[0]; // There's only 1 thread when doing inline post moderation + // The thread chosen is the first thread in the array of tids. + // It is recommended that this be the tid of the oldest post + } + + // Get the information about thread + $thread = get_thread($tid); + + // If deleting posts, only do that + if($post_options['deleteposts'] == 1) + { + foreach($pids as $pid) + { + $this->delete_post($pid); + } + + $delete_tids = array(); + $imploded_pids = implode(",", array_map("intval", $pids)); + $query = $db->simple_select("threads", "tid", "firstpost IN ({$imploded_pids})"); + while($threadid = $db->fetch_field($query, "tid")) + { + $delete_tids[] = $threadid; + } + if(!empty($delete_tids)) + { + foreach($delete_tids as $delete_tid) + { + $this->delete_thread($delete_tid); + mark_reports($delete_tid, "thread"); + } + // return 1 here so the code in execute() above knows to redirect to the forum + return 1; + } + } + else + { + if($post_options['mergeposts'] == 1) // Merge posts + { + $this->merge_posts($pids); + } + + if($post_options['approveposts'] == 'approve') // Approve posts + { + $this->approve_posts($pids); + } + elseif($post_options['approveposts'] == 'unapprove') // Unapprove posts + { + $this->unapprove_posts($pids); + } + elseif($post_options['approveposts'] == 'toggle') // Toggle post visibility + { + $this->toggle_post_visibility($pids); + } + + if($post_options['softdelete'] == 'softdelete') // Soft delete posts + { + $this->soft_delete_posts($pids); + } + elseif($post_options['softdelete'] == 'restore') // Restore posts + { + $this->restore_posts($pids); + } + elseif($post_options['softdelete'] == 'toggle') // Toggle post visibility + { + $this->toggle_post_softdelete($pids); + } + + if($post_options['splitposts'] > 0 || $post_options['splitposts'] == -2) // Split posts + { + $query = $db->simple_select("posts", "COUNT(*) AS totalposts", "tid='{$tid}'"); + $count = $db->fetch_array($query); + + if($count['totalposts'] == 1) + { + error($lang->error_cantsplitonepost); + } + + if($count['totalposts'] == count($pids)) + { + error($lang->error_cantsplitall); + } + + if($post_options['splitposts'] == -2) + { + $post_options['splitposts'] = $thread['fid']; + } + if(empty($post_options['splitpostsnewsubject'])) + { + // Enter in a subject if a predefined one does not exist. + $post_options['splitpostsnewsubject'] = "{$lang->split_thread_subject} {$thread['subject']}"; + } + $new_subject = str_ireplace('{subject}', $thread['subject'], $post_options['splitpostsnewsubject']); + $new_tid = $this->split_posts($pids, $tid, $post_options['splitposts'], $new_subject); + if($post_options['splitpostsclose'] == 'close') // Close new thread + { + $this->close_threads($new_tid); + } + if($post_options['splitpostsstick'] == 'stick') // Stick new thread + { + $this->stick_threads($new_tid); + } + if($post_options['splitpostsunapprove'] == 'unapprove') // Unapprove new thread + { + $this->unapprove_threads($new_tid, $thread['fid']); + } + if($post_options['splitthreadprefix'] != '0') + { + $this->apply_thread_prefix($new_tid, $post_options['splitthreadprefix']); // Add thread prefix to new thread + } + if(!empty($post_options['splitpostsaddreply'])) // Add reply to new thread + { + require_once MYBB_ROOT."inc/datahandlers/post.php"; + $posthandler = new PostDataHandler("insert"); + + if(empty($post_options['splitpostsreplysubject'])) + { + $post_options['splitpostsreplysubject'] = 'RE: '.$new_subject; + } + else + { + $post_options['splitpostsreplysubject'] = str_ireplace('{username}', $mybb->user['username'], $post_options['splitpostsreplysubject']); + $post_options['splitpostsreplysubject'] = str_ireplace('{subject}', $new_subject, $post_options['splitpostsreplysubject']); + } + + // Set the post data that came from the input to the $post array. + $post = array( + "tid" => $new_tid, + "fid" => $post_options['splitposts'], + "subject" => $post_options['splitpostsreplysubject'], + "uid" => $mybb->user['uid'], + "username" => $mybb->user['username'], + "message" => $post_options['splitpostsaddreply'], + "ipaddress" => $db->escape_binary(my_inet_pton(get_ip())), + ); + // Set up the post options from the input. + $post['options'] = array( + "signature" => 1, + "emailnotify" => 0, + "disablesmilies" => 0 + ); + + $posthandler->set_data($post); + + if($posthandler->validate_post($post)) + { + $posthandler->insert_post($post); + } + } + } + } + return true; + } + + /** + * Execute Normal and Inline Thread Moderation + * + * @param array Moderation information + * @param mixed Thread IDs + * @return boolean true + */ + function execute_thread_moderation($thread_options, $tids) + { + global $db, $mybb; + + $tid = (int)$tids[0]; // Take the first thread to get thread data from + $query = $db->simple_select("threads", 'fid', "tid='$tid'"); + $thread = $db->fetch_array($query); + + // If deleting threads, only do that + if($thread_options['deletethread'] == 1) + { + foreach($tids as $tid) + { + $this->delete_thread($tid); + } + } + else + { + if($thread_options['mergethreads'] == 1 && count($tids) > 1) // Merge Threads (ugly temp code until find better fix) + { + $tid_list = implode(',', $tids); + $options = array('order_by' => 'dateline', 'order_dir' => 'DESC'); + $query = $db->simple_select("threads", 'tid, subject', "tid IN ($tid_list)", $options); // Select threads from newest to oldest + $last_tid = 0; + while($tid = $db->fetch_array($query)) + { + if($last_tid != 0) + { + $this->merge_threads($last_tid, $tid['tid'], $tid['subject']); // And keep merging them until we get down to one thread. + } + $last_tid = $tid['tid']; + } + } + if($thread_options['deletepoll'] == 1) // Delete poll + { + foreach($tids as $tid) + { + $this->delete_poll($tid); + } + } + if($thread_options['removeredirects'] == 1) // Remove redirects + { + foreach($tids as $tid) + { + $this->remove_redirects($tid); + } + } + + if($thread_options['removesubscriptions'] == 1) // Remove thread subscriptions + { + $this->remove_thread_subscriptions($tids, true); + } + + if($thread_options['approvethread'] == 'approve') // Approve thread + { + $this->approve_threads($tids, $thread['fid']); + } + elseif($thread_options['approvethread'] == 'unapprove') // Unapprove thread + { + $this->unapprove_threads($tids, $thread['fid']); + } + elseif($thread_options['approvethread'] == 'toggle') // Toggle thread visibility + { + $this->toggle_thread_visibility($tids, $thread['fid']); + } + + if($thread_options['softdelete'] == 'softdelete') // Soft delete thread + { + $this->soft_delete_threads($tids, $thread['fid']); + } + elseif($thread_options['softdelete'] == 'restore') // Restore thread + { + $this->restore_threads($tids, $thread['fid']); + } + elseif($thread_options['softdelete'] == 'toggle') // Toggle thread visibility + { + $this->toggle_thread_softdelete($tids, $thread['fid']); + } + + if($thread_options['openthread'] == 'open') // Open thread + { + $this->open_threads($tids); + } + elseif($thread_options['openthread'] == 'close') // Close thread + { + $this->close_threads($tids); + } + elseif($thread_options['openthread'] == 'toggle') // Toggle thread visibility + { + $this->toggle_thread_status($tids); + } + + if($thread_options['stickthread'] == 'stick') // Stick thread + { + $this->stick_threads($tids); + } + elseif($thread_options['stickthread'] == 'unstick') // Unstick thread + { + $this->unstick_threads($tids); + } + elseif($thread_options['stickthread'] == 'toggle') // Toggle thread importance + { + $this->toggle_thread_importance($tids); + } + + if($thread_options['threadprefix'] != '-1') + { + $this->apply_thread_prefix($tids, $thread_options['threadprefix']); // Update thread prefix + } + + if(my_strtolower(trim($thread_options['newsubject'])) != '{subject}') // Update thread subjects + { + $this->change_thread_subject($tids, $thread_options['newsubject']); + } + if(!empty($thread_options['addreply'])) // Add reply to thread + { + $tid_list = implode(',', $tids); + $query = $db->simple_select("threads", 'uid, fid, subject, tid, firstpost, closed', "tid IN ($tid_list) AND closed NOT LIKE 'moved|%'"); + require_once MYBB_ROOT."inc/datahandlers/post.php"; + + // Loop threads adding a reply to each one + while($thread = $db->fetch_array($query)) + { + $posthandler = new PostDataHandler("insert"); + + if(empty($thread_options['replysubject'])) + { + $new_subject = 'RE: '.$thread['subject']; + } + else + { + $new_subject = str_ireplace('{username}', $mybb->user['username'], $thread_options['replysubject']); + $new_subject = str_ireplace('{subject}', $thread['subject'], $new_subject); + } + + // Set the post data that came from the input to the $post array. + $post = array( + "tid" => $thread['tid'], + "replyto" => $thread['firstpost'], + "fid" => $thread['fid'], + "subject" => $new_subject, + "uid" => $mybb->user['uid'], + "username" => $mybb->user['username'], + "message" => $thread_options['addreply'], + "ipaddress" => $db->escape_binary(my_inet_pton(get_ip())), + ); + + // Set up the post options from the input. + $post['options'] = array( + "signature" => 1, + "emailnotify" => 0, + "disablesmilies" => 0 + ); + + if($thread['closed'] == 1) + { + // Keep this thread closed + $post['modoptions']['closethread'] = 1; + } + + $posthandler->set_data($post); + if($posthandler->validate_post($post)) + { + $posthandler->insert_post($post); + } + } + } + if($thread_options['movethread'] > 0 && $thread_options['movethread'] != $thread['fid']) // Move thread + { + if($thread_options['movethreadredirect'] == 1) // Move Thread with redirect + { + $time = TIME_NOW + ($thread_options['movethreadredirectexpire'] * 86400); + foreach($tids as $tid) + { + $this->move_thread($tid, $thread_options['movethread'], 'redirect', $time); + } + } + else // Normal move + { + $this->move_threads($tids, $thread_options['movethread']); + } + } + if($thread_options['copythread'] > 0 || $thread_options['copythread'] == -2) // Copy thread + { + if($thread_options['copythread'] == -2) + { + $thread_options['copythread'] = $thread['fid']; + } + foreach($tids as $tid) + { + $new_tid = $this->move_thread($tid, $thread_options['copythread'], 'copy'); + } + } + if(!empty($thread_options['recountrebuild'])) + { + require_once MYBB_ROOT.'/inc/functions_rebuild.php'; + + foreach($tids as $tid) + { + rebuild_thread_counters($tid); + } + } + } + + // Do we have a PM subject and PM message? + if(isset($thread_options['pm_subject']) && $thread_options['pm_subject'] != '' && isset($thread_options['pm_message']) && $thread_options['pm_message'] != '') + { + $tid_list = implode(',', $tids); + + // For each thread, we send a PM to the author + $query = $db->simple_select("threads", 'uid', "tid IN ($tid_list)"); + while($uid = $db->fetch_field($query, 'uid')) + { + // Let's send our PM + $pm = array( + 'subject' => $thread_options['pm_subject'], + 'message' => $thread_options['pm_message'], + 'touid' => $uid + ); + send_pm($pm, $mybb->user['uid'], 1); + } + } + + return true; + } +} diff --git a/Upload/inc/class_datacache.php b/Upload/inc/class_datacache.php new file mode 100644 index 0000000..6d439d7 --- /dev/null +++ b/Upload/inc/class_datacache.php @@ -0,0 +1,1308 @@ +config['cache_store']) + { + // Disk cache + case "files": + require_once MYBB_ROOT."/inc/cachehandlers/disk.php"; + $this->handler = new diskCacheHandler($this->silent); + break; + // Memcache cache + case "memcache": + require_once MYBB_ROOT."/inc/cachehandlers/memcache.php"; + $this->handler = new memcacheCacheHandler($this->silent); + break; + // Memcached cache + case "memcached": + require_once MYBB_ROOT."/inc/cachehandlers/memcached.php"; + $this->handler = new memcachedCacheHandler($this->silent); + break; + // eAccelerator cache + case "eaccelerator": + require_once MYBB_ROOT."/inc/cachehandlers/eaccelerator.php"; + $this->handler = new eacceleratorCacheHandler($this->silent); + break; + // Xcache cache + case "xcache": + require_once MYBB_ROOT."/inc/cachehandlers/xcache.php"; + $this->handler = new xcacheCacheHandler($this->silent); + break; + // APC cache + case "apc": + require_once MYBB_ROOT."/inc/cachehandlers/apc.php"; + $this->handler = new apcCacheHandler($this->silent); + break; + } + + if(is_object($this->handler)) + { + if(method_exists($this->handler, "connect")) + { + if(!$this->handler->connect()) + { + $this->handler = null; + } + } + } + else + { + // Database cache + $query = $db->simple_select("datacache", "title,cache"); + while($data = $db->fetch_array($query)) + { + $this->cache[$data['title']] = my_unserialize($data['cache']); + } + } + } + + /** + * Read cache from files or db. + * + * @param string The cache component to read. + * @param boolean If true, cannot be overwritten during script execution. + * @return unknown + */ + function read($name, $hard=false) + { + global $db, $mybb; + + // Already have this cache and we're not doing a hard refresh? Return cached copy + if(isset($this->cache[$name]) && $hard == false) + { + return $this->cache[$name]; + } + // If we're not hard refreshing, and this cache doesn't exist, return false + // It would have been loaded pre-global if it did exist anyway... + else if($hard == false && !is_object($this->handler)) + { + return false; + } + + if(is_object($this->handler)) + { + get_execution_time(); + + $data = $this->handler->fetch($name); + + $call_time = get_execution_time(); + $this->call_time += $call_time; + $this->call_count++; + + if($mybb->debug_mode) + { + $hit = true; + if($data === false) + { + $hit = false; + } + $this->debug_call('read:'.$name, $call_time, $hit); + } + + // No data returned - cache gone bad? + if($data === false) + { + // Fetch from database + $query = $db->simple_select("datacache", "title,cache", "title='".$db->escape_string($name)."'"); + $cache_data = $db->fetch_array($query); + $data = my_unserialize($cache_data['cache']); + + // Update cache for handler + get_execution_time(); + + $hit = $this->handler->put($name, $data); + + $call_time = get_execution_time(); + $this->call_time += $call_time; + $this->call_count++; + + if($mybb->debug_mode) + { + $this->debug_call('set:'.$name, $call_time, $hit); + } + } + } + // Else, using internal database cache + else + { + $query = $db->simple_select("datacache", "title,cache", "title='$name'"); + $cache_data = $db->fetch_array($query); + + if(!$cache_data['title']) + { + $data = false; + } + else + { + $data = my_unserialize($cache_data['cache']); + } + } + + // Cache locally + $this->cache[$name] = $data; + + if($data !== false) + { + return $data; + } + else + { + return false; + } + } + + /** + * Update cache contents. + * + * @param string The cache content identifier. + * @param string The cache content. + */ + function update($name, $contents) + { + global $db, $mybb; + + $this->cache[$name] = $contents; + + // We ALWAYS keep a running copy in the db just incase we need it + $dbcontents = $db->escape_string(serialize($contents)); + + $replace_array = array( + "title" => $db->escape_string($name), + "cache" => $dbcontents + ); + $db->replace_query("datacache", $replace_array, "", false); + + // Do we have a cache handler we're using? + if(is_object($this->handler)) + { + get_execution_time(); + + $hit = $this->handler->put($name, $contents); + + $call_time = get_execution_time(); + $this->call_time += $call_time; + $this->call_count++; + + if($mybb->debug_mode) + { + $this->debug_call('update:'.$name, $call_time, $hit); + } + } + } + + /** + * Delete cache contents. + * Originally from frostschutz's PluginLibrary + * github.com/frostschutz + * + * @param string Cache name or title + * @param boolean To delete a cache starting with name_ + */ + function delete($name, $greedy = false) + { + global $db, $mybb, $cache; + + // Prepare for database query. + $dbname = $db->escape_string($name); + $where = "title = '{$dbname}'"; + + // Delete on-demand or handler cache + if($this->handler) + { + get_execution_time(); + + $hit = $this->handler->delete($name); + + $call_time = get_execution_time(); + $this->call_time += $call_time; + $this->call_count++; + + if($mybb->debug_mode) + { + $this->debug_call('delete:'.$name, $call_time, $hit); + } + } + + // Greedy? + if($greedy) + { + $name .= '_'; + $names = array(); + $keys = array_keys($cache->cache); + + foreach($keys as $key) + { + if(strpos($key, $name) === 0) + { + $names[$key] = 0; + } + } + + $ldbname = strtr($dbname, + array( + '%' => '=%', + '=' => '==', + '_' => '=_' + ) + ); + + $where .= " OR title LIKE '{$ldbname}=_%' ESCAPE '='"; + + if($this->handler) + { + $query = $db->simple_select("datacache", "title", $where); + + while($row = $db->fetch_array($query)) + { + $names[$row['title']] = 0; + } + + // ...from the filesystem... + $start = strlen(MYBB_ROOT."cache/"); + foreach((array)@glob(MYBB_ROOT."cache/{$name}*.php") as $filename) + { + if($filename) + { + $filename = substr($filename, $start, strlen($filename)-4-$start); + $names[$filename] = 0; + } + } + + foreach($names as $key => $val) + { + get_execution_time(); + + $hit = $this->handler->delete($key); + + $call_time = get_execution_time(); + $this->call_time += $call_time; + $this->call_count++; + + if($mybb->debug_mode) + { + $this->debug_call('delete:'.$name, $call_time, $hit); + } + } + } + } + + // Delete database cache + $db->delete_query("datacache", $where); + } + + /** + * Debug a cache call to a non-database cache handler + * + * @param string The cache key + * @param string The time it took to perform the call. + * @param boolean Hit or miss status + */ + function debug_call($string, $qtime, $hit) + { + global $mybb, $plugins; + + $debug_extra = ''; + if($plugins->current_hook) + { + $debug_extra = "
    (Plugin Hook: {$plugins->current_hook})
    "; + } + + if($hit) + { + $hit_status = 'HIT'; + } + else + { + $hit_status = 'MISS'; + } + + $cache_data = explode(':', $string); + $cache_method = $cache_data[0]; + $cache_key = $cache_data[1]; + + $this->cache_debug .= "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "
    {$debug_extra}
    #".$this->call_count." - ".ucfirst($cache_method)." Call
    (".$mybb->config['cache_store'].") [".$hit_status."] ".htmlspecialchars_uni($cache_key)."
    Call Time: ".format_time_duration($qtime)."
    \n". + "
    \n"; + + $this->calllist[$this->call_count]['key'] = $string; + $this->calllist[$this->call_count]['time'] = $qtime; + } + + /** + * Select the size of the cache + * + * @param string The name of the cache + * @return integer the size of the cache + */ + function size_of($name='') + { + global $db; + + if(is_object($this->handler)) + { + $size = $this->handler->size_of($name); + if(!$size) + { + if($name) + { + $query = $db->simple_select("datacache", "cache", "title='{$name}'"); + return strlen($db->fetch_field($query, "cache")); + } + else + { + return $db->fetch_size("datacache"); + } + } + else + { + return $size; + } + } + // Using MySQL as cache + else + { + if($name) + { + $query = $db->simple_select("datacache", "cache", "title='{$name}'"); + return strlen($db->fetch_field($query, "cache")); + } + else + { + return $db->fetch_size("datacache"); + } + } + } + + /** + * Update the MyBB version in the cache. + * + */ + function update_version() + { + global $mybb; + + $version = array( + "version" => $mybb->version, + "version_code" => $mybb->version_code + ); + + $this->update("version", $version); + } + + /** + * Update the attachment type cache. + * + */ + function update_attachtypes() + { + global $db; + + $types = array(); + + $query = $db->simple_select("attachtypes", "*"); + while($type = $db->fetch_array($query)) + { + $type['extension'] = my_strtolower($type['extension']); + $types[$type['extension']] = $type; + } + + $this->update("attachtypes", $types); + } + + /** + * Update the smilies cache. + * + */ + function update_smilies() + { + global $db; + + $smilies = array(); + + $query = $db->simple_select("smilies", "*", "", array('order_by' => 'disporder', 'order_dir' => 'ASC')); + while($smilie = $db->fetch_array($query)) + { + $smilies[$smilie['sid']] = $smilie; + } + + $this->update("smilies", $smilies); + } + + /** + * Update the posticon cache. + * + */ + function update_posticons() + { + global $db; + + $icons = array(); + + $query = $db->simple_select("icons", "iid, name, path"); + while($icon = $db->fetch_array($query)) + { + $icons[$icon['iid']] = $icon; + } + + $this->update("posticons", $icons); + } + + /** + * Update the badwords cache. + * + */ + function update_badwords() + { + global $db; + + $badwords = array(); + + $query = $db->simple_select("badwords", "*"); + while($badword = $db->fetch_array($query)) + { + $badwords[$badword['bid']] = $badword; + } + + $this->update("badwords", $badwords); + } + + /** + * Update the usergroups cache. + * + */ + function update_usergroups() + { + global $db; + + $query = $db->simple_select("usergroups"); + + $gs = array(); + while($g = $db->fetch_array($query)) + { + $gs[$g['gid']] = $g; + } + + $this->update("usergroups", $gs); + } + + /** + * Update the forum permissions cache. + * + * @return false When failed, returns false. + */ + function update_forumpermissions() + { + global $forum_cache, $db; + + $this->built_forum_permissions = array(0); + + // Get our forum list + cache_forums(true); + if(!is_array($forum_cache)) + { + return false; + } + + reset($forum_cache); + $fcache = array(); + + // Resort in to the structure we require + foreach($forum_cache as $fid => $forum) + { + $this->forum_permissions_forum_cache[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum; + } + + // Sort children + foreach($fcache as $pid => $value) + { + ksort($fcache[$pid]); + } + ksort($fcache); + + // Fetch forum permissions from the database + $query = $db->simple_select("forumpermissions"); + while($forum_permission = $db->fetch_array($query)) + { + $this->forum_permissions[$forum_permission['fid']][$forum_permission['gid']] = $forum_permission; + } + + $this->build_forum_permissions(); + $this->update("forumpermissions", $this->built_forum_permissions); + } + + /** + * Build the forum permissions array + * + * @access private + * @param array An optional permissions array. + * @param int An optional permission id. + */ + private function build_forum_permissions($permissions=array(), $pid=0) + { + $usergroups = array_keys($this->read("usergroups", true)); + if($this->forum_permissions_forum_cache[$pid]) + { + foreach($this->forum_permissions_forum_cache[$pid] as $main) + { + foreach($main as $forum) + { + $perms = $permissions; + foreach($usergroups as $gid) + { + if($this->forum_permissions[$forum['fid']][$gid]) + { + $perms[$gid] = $this->forum_permissions[$forum['fid']][$gid]; + } + if($perms[$gid]) + { + $perms[$gid]['fid'] = $forum['fid']; + $this->built_forum_permissions[$forum['fid']][$gid] = $perms[$gid]; + } + } + $this->build_forum_permissions($perms, $forum['fid']); + } + } + } + } + + /** + * Update the stats cache (kept for the sake of being able to rebuild this cache via the cache interface) + * + */ + function update_stats() + { + global $db; + + require_once MYBB_ROOT."inc/functions_rebuild.php"; + rebuild_stats(); + } + + /** + * Update the statistics cache + * + */ + function update_statistics() + { + global $db; + + $query = $db->simple_select('forums', 'fid, threads, posts', $fidnot.'type=\'f\'', array('order_by' => 'posts', 'order_dir' => 'DESC', 'limit' => 1)); + $forum = $db->fetch_array($query); + + $query = $db->simple_select('users', 'uid, username, referrals', 'referrals>0', array('order_by' => 'referrals', 'order_dir' => 'DESC', 'limit' => 1)); + $topreferrer = $db->fetch_array($query); + + $timesearch = TIME_NOW - 86400; + switch($db->type) + { + case 'pgsql': + $group_by = $db->build_fields_string('users', 'u.'); + break; + default: + $group_by = 'p.uid'; + break; + } + + $query = $db->query(' + SELECT u.uid, u.username, COUNT(*) AS poststoday + FROM '.TABLE_PREFIX.'posts p + LEFT JOIN '.TABLE_PREFIX.'users u ON (p.uid=u.uid) + WHERE p.dateline>'.$timesearch.' + GROUP BY '.$group_by.' ORDER BY poststoday DESC + LIMIT 1 + '); + $topposter = $db->fetch_array($query); + + $query = $db->simple_select('users', 'COUNT(*) AS posters', 'postnum>0'); + $posters = $db->fetch_field($query, 'posters'); + + $statistics = array( + 'time' => TIME_NOW, + 'top_forum' => (array)$forum, + 'top_referrer' => (array)$topreferrer, + 'top_poster' => (array)$topposter, + 'posters' => (int)$posters, + ); + + $this->update('statistics', $statistics); + } + + /** + * Update the moderators cache. + * + */ + function update_moderators() + { + global $forum_cache, $db; + + $this->built_moderators = array(0); + + // Get our forum list + cache_forums(true); + if(!is_array($forum_cache)) + { + return false; + } + + reset($forum_cache); + $fcache = array(); + + // Resort in to the structure we require + foreach($forum_cache as $fid => $forum) + { + $this->moderators_forum_cache[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum; + } + + // Sort children + foreach($fcache as $pid => $value) + { + ksort($fcache[$pid]); + } + ksort($fcache); + + $this->moderators = array(); + + // Fetch moderators from the database + $query = $db->query(" + SELECT m.*, u.username, u.usergroup, u.displaygroup + FROM ".TABLE_PREFIX."moderators m + LEFT JOIN ".TABLE_PREFIX."users u ON (m.id=u.uid) + WHERE m.isgroup = '0' + ORDER BY u.username + "); + while($moderator = $db->fetch_array($query)) + { + $this->moderators[$moderator['fid']]['users'][$moderator['id']] = $moderator; + } + + if(!function_exists("sort_moderators_by_usernames")) + { + function sort_moderators_by_usernames($a, $b) + { + return strcasecmp($a['username'], $b['username']); + } + } + + //Fetch moderating usergroups from the database + $query = $db->query(" + SELECT m.*, u.title + FROM ".TABLE_PREFIX."moderators m + LEFT JOIN ".TABLE_PREFIX."usergroups u ON (m.id=u.gid) + WHERE m.isgroup = '1' + ORDER BY u.title + "); + while($moderator = $db->fetch_array($query)) + { + $this->moderators[$moderator['fid']]['usergroups'][$moderator['id']] = $moderator; + } + + if(is_array($this->moderators)) + { + foreach(array_keys($this->moderators) as $fid) + { + uasort($this->moderators[$fid], 'sort_moderators_by_usernames'); + } + } + + $this->build_moderators(); + + $this->update("moderators", $this->built_moderators); + } + + /** + * Update the users awaiting activation cache. + * + */ + function update_awaitingactivation() + { + global $db; + + $query = $db->simple_select('users', 'COUNT(uid) AS awaitingusers', 'usergroup=\'5\''); + $awaitingusers = (int)$db->fetch_field($query, 'awaitingusers'); + + $this->update('awaitingactivation', array('users' => $awaitingusers)); + } + + /** + * Build the moderators array + * + * @access private + * @param array An optional moderators array (moderators of the parent forum for example). + * @param int An optional parent ID. + */ + private function build_moderators($moderators=array(), $pid=0) + { + if(isset($this->moderators_forum_cache[$pid])) + { + foreach($this->moderators_forum_cache[$pid] as $main) + { + foreach($main as $forum) + { + $forum_mods = ''; + if(count($moderators)) + { + $forum_mods = $moderators; + } + // Append - local settings override that of a parent - array_merge works here + if(isset($this->moderators[$forum['fid']])) + { + if(is_array($forum_mods) && count($forum_mods)) + { + $forum_mods = array_merge($forum_mods, $this->moderators[$forum['fid']]); + } + else + { + $forum_mods = $this->moderators[$forum['fid']]; + } + } + $this->built_moderators[$forum['fid']] = $forum_mods; + $this->build_moderators($forum_mods, $forum['fid']); + } + } + } + } + + /** + * Update the forums cache. + * + */ + function update_forums() + { + global $db; + + $forums = array(); + + // Things we don't want to cache + $exclude = array("unapprovedthreads", "unapprovedposts", "threads", "posts", "lastpost", "lastposter", "lastposttid", "deletedthreads", "deletedposts"); + + $query = $db->simple_select("forums", "*", "", array('order_by' => 'pid,disporder')); + while($forum = $db->fetch_array($query)) + { + foreach($forum as $key => $val) + { + if(in_array($key, $exclude)) + { + unset($forum[$key]); + } + } + $forums[$forum['fid']] = $forum; + } + + $this->update("forums", $forums); + } + + /** + * Update usertitles cache. + * + */ + function update_usertitles() + { + global $db; + + $usertitles = array(); + $query = $db->simple_select("usertitles", "utid, posts, title, stars, starimage", "", array('order_by' => 'posts', 'order_dir' => 'DESC')); + while($usertitle = $db->fetch_array($query)) + { + $usertitles[] = $usertitle; + } + + $this->update("usertitles", $usertitles); + } + + /** + * Update reported content cache. + * + */ + function update_reportedcontent() + { + global $db, $mybb; + + $reports = array(); + $query = $db->simple_select("reportedcontent", "COUNT(rid) AS unreadcount", "reportstatus='0'"); + $num = $db->fetch_array($query); + + $query = $db->simple_select("reportedcontent", "COUNT(rid) AS reportcount"); + $total = $db->fetch_array($query); + + $query = $db->simple_select("reportedcontent", "dateline", "reportstatus='0'", array('order_by' => 'dateline', 'order_dir' => 'DESC')); + $latest = $db->fetch_array($query); + + $reasons = array(); + + if(!empty($mybb->settings['reportreasons'])) + { + $options = $mybb->settings['reportreasons']; + $options = explode("\n", $options); + + foreach($options as $option) + { + $option = explode("=", $option); + $reasons[$option[0]] = $option[1]; + } + } + + $reports = array( + "unread" => $num['unreadcount'], + "total" => $total['reportcount'], + "lastdateline" => $latest['dateline'], + "reasons" => $reasons + ); + + $this->update("reportedcontent", $reports); + } + + /** + * Update mycode cache. + * + */ + function update_mycode() + { + global $db; + + $mycodes = array(); + $query = $db->simple_select("mycode", "regex, replacement", "active=1", array('order_by' => 'parseorder')); + while($mycode = $db->fetch_array($query)) + { + $mycodes[] = $mycode; + } + + $this->update("mycode", $mycodes); + } + + /** + * Update the mailqueue cache + * + */ + function update_mailqueue($last_run=0, $lock_time=0) + { + global $db; + + $query = $db->simple_select("mailqueue", "COUNT(*) AS queue_size"); + $queue_size = $db->fetch_field($query, "queue_size"); + + $mailqueue = $this->read("mailqueue"); + if(!is_array($mailqueue)) + { + $mailqueue = array(); + } + $mailqueue['queue_size'] = $queue_size; + if($last_run > 0) + { + $mailqueue['last_run'] = $last_run; + } + $mailqueue['locked'] = $lock_time; + + $this->update("mailqueue", $mailqueue); + } + + /** + * Update update_check cache (dummy function used by upgrade/install scripts) + */ + function update_update_check() + { + $update_cache = array( + "dateline" => TIME_NOW + ); + + $this->update("update_check", $update_cache); + } + + /** + * Update default_theme cache + */ + function update_default_theme() + { + global $db; + + $query = $db->simple_select("themes", "name, tid, properties, stylesheets", "def='1'", array('limit' => 1)); + $theme = $db->fetch_array($query); + $this->update("default_theme", $theme); + } + + /** + * Updates the tasks cache saving the next run time + */ + function update_tasks() + { + global $db; + + $query = $db->simple_select("tasks", "nextrun", "enabled=1", array("order_by" => "nextrun", "order_dir" => "asc", "limit" => 1)); + $next_task = $db->fetch_array($query); + + $task_cache = $this->read("tasks"); + if(!is_array($task_cache)) + { + $task_cache = array(); + } + $task_cache['nextrun'] = $next_task['nextrun']; + + if(!$task_cache['nextrun']) + { + $task_cache['nextrun'] = TIME_NOW+3600; + } + + $this->update("tasks", $task_cache); + } + + /** + * Updates the banned IPs cache + */ + function update_bannedips() + { + global $db; + + $banned_ips = array(); + $query = $db->simple_select("banfilters", "fid,filter", "type=1"); + while($banned_ip = $db->fetch_array($query)) + { + $banned_ips[$banned_ip['fid']] = $banned_ip; + } + $this->update("bannedips", $banned_ips); + } + + /** + * Updates the banned emails cache + */ + function update_bannedemails() + { + global $db; + + $banned_emails = array(); + $query = $db->simple_select("banfilters", "fid, filter", "type = '3'"); + + while($banned_email = $db->fetch_array($query)) + { + $banned_emails[$banned_email['fid']] = $banned_email; + } + + $this->update("bannedemails", $banned_emails); + } + + /** + * Updates the search engine spiders cache + */ + function update_spiders() + { + global $db; + + $spiders = array(); + $query = $db->simple_select("spiders", "sid, name, useragent, usergroup", "", array("order_by" => "LENGTH(useragent)", "order_dir" => "DESC")); + while($spider = $db->fetch_array($query)) + { + $spiders[$spider['sid']] = $spider; + } + $this->update("spiders", $spiders); + } + + function update_most_replied_threads() + { + global $db, $mybb; + + $threads = array(); + + $query = $db->simple_select("threads", "tid, subject, replies, fid", "visible='1'", array('order_by' => 'replies', 'order_dir' => 'DESC', 'limit_start' => 0, 'limit' => $mybb->settings['statslimit'])); + while($thread = $db->fetch_array($query)) + { + $threads[] = $thread; + } + + $this->update("most_replied_threads", $threads); + } + + function update_most_viewed_threads() + { + global $db, $mybb; + + $threads = array(); + + $query = $db->simple_select("threads", "tid, subject, views, fid", "visible='1'", array('order_by' => 'views', 'order_dir' => 'DESC', 'limit_start' => 0, 'limit' => $mybb->settings['statslimit'])); + while($thread = $db->fetch_array($query)) + { + $threads[] = $thread; + } + + $this->update("most_viewed_threads", $threads); + } + + function update_banned() + { + global $db; + + $bans = array(); + + $query = $db->simple_select("banned"); + while($ban = $db->fetch_array($query)) + { + $bans[$ban['uid']] = $ban; + } + + $this->update("banned", $bans); + } + + function update_birthdays() + { + global $db; + + $birthdays = array(); + + // Get today, yesturday, and tomorrow's time (for different timezones) + $bdaytime = TIME_NOW; + $bdaydate = my_date("j-n", $bdaytime, '', 0); + $bdaydatetomorrow = my_date("j-n", ($bdaytime+86400), '', 0); + $bdaydateyesterday = my_date("j-n", ($bdaytime-86400), '', 0); + + $query = $db->simple_select("users", "uid, username, usergroup, displaygroup, birthday, birthdayprivacy", "birthday LIKE '$bdaydate-%' OR birthday LIKE '$bdaydateyesterday-%' OR birthday LIKE '$bdaydatetomorrow-%'"); + while($bday = $db->fetch_array($query)) + { + // Pop off the year from the birthday because we don't need it. + $bday['bday'] = explode('-', $bday['birthday']); + array_pop($bday['bday']); + $bday['bday'] = implode('-', $bday['bday']); + + if($bday['birthdayprivacy'] != 'all') + { + ++$birthdays[$bday['bday']]['hiddencount']; + continue; + } + + // We don't need any excess caleries in the cache + unset($bday['birthdayprivacy']); + + $birthdays[$bday['bday']]['users'][] = $bday; + } + + $this->update("birthdays", $birthdays); + } + + function update_groupleaders() + { + global $db; + + $groupleaders = array(); + + $query = $db->simple_select("groupleaders"); + while($groupleader = $db->fetch_array($query)) + { + $groupleaders[$groupleader['uid']][] = $groupleader; + } + + $this->update("groupleaders", $groupleaders); + } + + function update_threadprefixes() + { + global $db; + + $prefixes = array(); + $query = $db->simple_select("threadprefixes", "*", "", array('order_by' => 'prefix', 'order_dir' => 'ASC')); + + while($prefix = $db->fetch_array($query)) + { + $prefixes[$prefix['pid']] = $prefix; + } + + $this->update("threadprefixes", $prefixes); + } + + function update_forumsdisplay() + { + global $db; + + $fd_statistics = array(); + + $time = TIME_NOW; // Look for announcements that don't end, or that are ending some time in the future + $query = $db->simple_select("announcements", "fid", "enddate = '0' OR enddate > '{$time}'", array("order_by" => "aid")); + + if($db->num_rows($query)) + { + while($forum = $db->fetch_array($query)) + { + if(!isset($fd_statistics[$forum['fid']]['announcements'])) + { + $fd_statistics[$forum['fid']]['announcements'] = 1; + } + } + } + + // Do we have any mod tools to use in our forums? + $query = $db->simple_select("modtools", "forums, tid", '', array("order_by" => "tid")); + + if($db->num_rows($query)) + { + unset($forum); + while($tool = $db->fetch_array($query)) + { + $forums = explode(",", $tool['forums']); + + foreach($forums as $forum) + { + if(!$forum) + { + $forum = -1; + } + + if(!isset($fd_statistics[$forum]['modtools'])) + { + $fd_statistics[$forum]['modtools'] = 1; + } + } + } + } + + $this->update("forumsdisplay", $fd_statistics); + } + + /** + * Update profile fields cache. + * + */ + function update_profilefields() + { + global $db; + + $fields = array(); + $query = $db->simple_select("profilefields", "*", "", array('order_by' => 'disporder')); + while($field = $db->fetch_array($query)) + { + $fields[] = $field; + } + + $this->update("profilefields", $fields); + } + + /* Other, extra functions for reloading caches if we just changed to another cache extension (i.e. from db -> xcache) */ + function reload_mostonline() + { + global $db; + + $query = $db->simple_select("datacache", "title,cache", "title='mostonline'"); + $this->update("mostonline", my_unserialize($db->fetch_field($query, "cache"))); + } + + function reload_plugins() + { + global $db; + + $query = $db->simple_select("datacache", "title,cache", "title='plugins'"); + $this->update("plugins", my_unserialize($db->fetch_field($query, "cache"))); + } + + function reload_last_backup() + { + global $db; + + $query = $db->simple_select("datacache", "title,cache", "title='last_backup'"); + $this->update("last_backup", my_unserialize($db->fetch_field($query, "cache"))); + } + + function reload_internal_settings() + { + global $db; + + $query = $db->simple_select("datacache", "title,cache", "title='internal_settings'"); + $this->update("internal_settings", my_unserialize($db->fetch_field($query, "cache"))); + } + + function reload_version_history() + { + global $db; + + $query = $db->simple_select("datacache", "title,cache", "title='version_history'"); + $this->update("version_history", my_unserialize($db->fetch_field($query, "cache"))); + } + + function reload_modnotes() + { + global $db; + + $query = $db->simple_select("datacache", "title,cache", "title='modnotes'"); + $this->update("modnotes", my_unserialize($db->fetch_field($query, "cache"))); + } + + function reload_adminnotes() + { + global $db; + + $query = $db->simple_select("datacache", "title,cache", "title='adminnotes'"); + $this->update("adminnotes", my_unserialize($db->fetch_field($query, "cache"))); + } + + function reload_mybb_credits() + { + admin_redirect('index.php?module=home-credits&fetch_new=-2'); + } +} diff --git a/Upload/inc/class_error.php b/Upload/inc/class_error.php new file mode 100644 index 0000000..9d77b89 --- /dev/null +++ b/Upload/inc/class_error.php @@ -0,0 +1,607 @@ + 'Błąd', + E_WARNING => 'Ostrzeżenie', + E_PARSE => 'Błąd parsowania', + E_NOTICE => 'Powiadomienie', + E_CORE_ERROR => 'Błąd silnika', + E_CORE_WARNING => 'Ostrzeżenie silnika', + E_COMPILE_ERROR => 'Błąd kompilacji', + E_COMPILE_WARNING => 'Ostrzeżenie kompilacji', + E_DEPRECATED => 'Ostrzeżenie o przestarzałej funkcji', + E_USER_ERROR => 'Błąd użytkownika', + E_USER_WARNING => 'Ostrzeżenie użytkownika', + E_USER_NOTICE => 'Informacja użytkownika', + E_USER_DEPRECATED => 'Nieobsługiwana wersja', + E_STRICT => 'Błąd wykonywania', + E_RECOVERABLE_ERROR => 'Wychwytywalny błąd krytyczny', + MYBB_SQL => 'Błąd SQL MyBB', + MYBB_TEMPLATE => 'Błąd szablonu MyBB', + MYBB_GENERAL => 'Błąd MyBB', + MYBB_NOT_INSTALLED => 'Błąd MyBB', + MYBB_NOT_UPGRADED => 'Błąd MyBB', + MYBB_INSTALL_DIR_EXISTS => 'Błąd MyBB', + MYBB_SQL_LOAD_ERROR => 'Błąd MyBB', + MYBB_CACHE_NO_WRITE => 'Błąd MyBB', + MYBB_CACHEHANDLER_LOAD_ERROR => 'Błąd MyBB', + ); + + /** + * Array of MyBB error types + * + * @var array + */ + public $mybb_error_types = array( + MYBB_SQL, + MYBB_TEMPLATE, + MYBB_GENERAL, + MYBB_NOT_INSTALLED, + MYBB_NOT_UPGRADED, + MYBB_INSTALL_DIR_EXISTS, + MYBB_SQL_LOAD_ERROR, + MYBB_CACHE_NO_WRITE, + MYBB_CACHEHANDLER_LOAD_ERROR, + ); + + /** + * Array of all of the error types to ignore + * + * @var array + */ + public $ignore_types = array( + E_DEPRECATED, + E_NOTICE, + E_USER_NOTICE, + E_STRICT + ); + + /** + * String of all the warnings collected + * + * @var string + */ + public $warnings = ""; + + /** + * Is MyBB in an errornous state? (Have we received an error?) + * + * @var boolean + */ + public $has_errors = false; + + /** + * Initializes the error handler + * + */ + function __construct() + { + // Lets set the error handler in here so we can just do $handler = new errorHandler() and be all set up. + $error_types = E_ALL; + foreach($this->ignore_types as $bit) + { + $error_types = $error_types & ~$bit; + } + error_reporting($error_types); + set_error_handler(array(&$this, "error"), $error_types); + } + + /** + * Parses a error for processing. + * + * @param string The error type (i.e. E_ERROR, E_FATAL) + * @param string The error message + * @param string The error file + * @param integer The error line + * @return boolean True if parsing was a success, otherwise assume a error + */ + function error($type, $message, $file=null, $line=0) + { + global $mybb; + + // Error reporting turned off (either globally or by @ before erroring statement) + if(error_reporting() == 0) + { + return true; + } + + if(in_array($type, $this->ignore_types)) + { + return true; + } + + $file = str_replace(MYBB_ROOT, "", $file); + + $this->has_errors = true; + + // For some reason in the installer this setting is set to "<" + $accepted_error_types = array('both', 'error', 'warning', 'none'); + if(!in_array($mybb->settings['errortypemedium'], $accepted_error_types)) + { + $mybb->settings['errortypemedium'] = "both"; + } + + if(defined("IN_TASK")) + { + global $task; + + require_once MYBB_ROOT."inc/functions_task.php"; + + if($file) + { + $filestr = " - Linia: $line - Plik: $file"; + } + + add_task_log($task, "{$this->error_types[$type]} - [$type] ".var_export($message, true)."{$filestr}"); + } + + // Saving error to log file. + if($mybb->settings['errorlogmedium'] == "log" || $mybb->settings['errorlogmedium'] == "both") + { + $this->log_error($type, $message, $file, $line); + } + + // Are we emailing the Admin a copy? + if($mybb->settings['errorlogmedium'] == "mail" || $mybb->settings['errorlogmedium'] == "both") + { + $this->email_error($type, $message, $file, $line); + } + + // SQL Error + if($type == MYBB_SQL) + { + $this->output_error($type, $message, $file, $line); + } + else + { + // Do we have a PHP error? + if(my_strpos(my_strtolower($this->error_types[$type]), 'warning') === false) + { + $this->output_error($type, $message, $file, $line); + } + // PHP Error + else + { + if($mybb->settings['errortypemedium'] == "none" || $mybb->settings['errortypemedium'] == "error") + { + echo "
    Wewnętrzny błąd MyBB: Wystąpiło jedno lub więcej ostrzeżeń. Skontaktuj się z administratorem, aby uzyskać pomoc.
    "; + } + else + { + global $templates; + + $warning = "{$this->error_types[$type]} [$type] $message - Linia: $line - Plik: $file PHP ".PHP_VERSION." (".PHP_OS.")
    \n"; + if(is_object($templates) && method_exists($templates, "get") && !defined("IN_ADMINCP")) + { + $this->warnings .= $warning; + $this->warnings .= $this->generate_backtrace(); + } + else + { + echo "
    {$warning}".$this->generate_backtrace()."
    "; + } + } + } + } + + return true; + } + + /** + * Returns all the warnings + * + * @return string The warnings + */ + function show_warnings() + { + global $lang, $templates; + + if(empty($this->warnings)) + { + return false; + } + + // Incase a template fails and we're receiving a blank page. + if(MANUAL_WARNINGS) + { + echo $this->warnings."
    "; + } + + if(!$lang->warnings) + { + $lang->warnings = "Wystąpiły poniższe ostrzeżenia:"; + } + + $template_exists = false; + + if(!is_object($templates) || !method_exists($templates, 'get')) + { + if(@file_exists(MYBB_ROOT."inc/class_templates.php")) + { + @require_once MYBB_ROOT."inc/class_templates.php"; + $templates = new templates; + $template_exists = true; + } + } + else + { + $template_exists = true; + } + + if($template_exists == true) + { + eval("\$warning = \"".$templates->get("php_warnings")."\";"); + } + + return $warning; + } + + /** + * Triggers a user created error + * Example: $error_handler->trigger("Some Warning", E_USER_ERROR); + * + * @param string Message + * @param string Type + */ + function trigger($message="", $type=E_USER_ERROR) + { + global $lang; + + if(!$message) + { + $message = $lang->unknown_user_trigger; + } + + if(in_array($type, $this->mybb_error_types)) + { + $this->error($type, $message); + } + else + { + trigger_error($message, $type); + } + } + + /** + * Logs the error in the specified error log file. + * + * @param string Warning type + * @param string Warning message + * @param string Warning file + * @param integer Warning line + */ + function log_error($type, $message, $file, $line) + { + global $mybb; + + if($type == MYBB_SQL) + { + $message = "Błąd SQL: {$message['error_no']} - {$message['error']}\nQuery: {$message['query']}"; + } + $error_data = "\n"; + $error_data .= "\t".TIME_NOW."\n"; + $error_data .= "\t\n"; + $error_data .= "\t".$line."\n"; + $error_data .= "\t".$type."\n"; + $error_data .= "\t".$this->error_types[$type]."\n"; + $error_data .= "\t".$message."\n"; + $error_data .= "\n\n"; + + if(trim($mybb->settings['errorloglocation']) != "") + { + @error_log($error_data, 3, $mybb->settings['errorloglocation']); + } + else + { + @error_log($error_data, 0); + } + } + + /** + * Emails the error in the specified error log file. + * + * @param string Warning type + * @param string Warning message + * @param string Warning file + * @param integer Warning line + */ + function email_error($type, $message, $file, $line) + { + global $mybb; + + if(!$mybb->settings['adminemail']) + { + return false; + } + + if($type == MYBB_SQL) + { + $message = "Błąd SQL: {$message['error_no']} - {$message['error']}\nQuery: {$message['query']}"; + } + + $message = "W MyBB uruchomionym na forum {$mybb->settings['bbname']} ({$mybb->settings['bburl']}) wystąpił błąd. Szczegóły problemu:\n---\nTyp: $type\nPlik: $file (linia $line)\nTreść komunikatu\n$message"; + + @my_mail($mybb->settings['adminemail'], "Błąd MyBB na forum {$mybb->settings['bbname']}", $message, $mybb->settings['adminemail']); + } + + function output_error($type, $message, $file, $line) + { + global $mybb, $parser; + + if(!$mybb->settings['bbname']) + { + $mybb->settings['bbname'] = "MyBB"; + } + + if($type == MYBB_SQL) + { + $title = "Błąd SQL"; + $error_message = "

    MyBB napotkało wewnętrzny błąd w zapytaniu SQL i nie może kontynuować.

    "; + if($mybb->settings['errortypemedium'] == "both" || $mybb->settings['errortypemedium'] == "error" || defined("IN_INSTALL") || defined("IN_UPGRADE")) + { + $message['query'] = htmlspecialchars_uni($message['query']); + $message['error'] = htmlspecialchars_uni($message['error']); + $error_message .= "
    \n"; + $error_message .= "
    BÅ‚Ä…d SQL:
    \n
    {$message['error_no']} - {$message['error']}
    \n"; + if($message['query'] != "") + { + $error_message .= "
    Zapytanie:
    \n
    {$message['query']}
    \n"; + } + $error_message .= "
    \n"; + } + } + else + { + $title = "Wewnętrzny błąd MyBB"; + $error_message = "

    MyBB napotkało błąd wewnętrzny i nie może kontynuować.

    "; + if($mybb->settings['errortypemedium'] == "both" || $mybb->settings['errortypemedium'] == "error" || defined("IN_INSTALL") || defined("IN_UPGRADE")) + { + $error_message .= "
    \n"; + $error_message .= "
    Typ błędu:
    \n
    {$this->error_types[$type]} ($type)
    \n"; + $error_message .= "
    Treść błędu:
    \n
    {$message}
    \n"; + if(!empty($file)) + { + $error_message .= "
    Lokalizacja:
    File: {$file}
    Line: {$line}
    \n"; + if(!@preg_match('#config\.php|settings\.php#', $file) && @file_exists($file)) + { + $code_pre = @file($file); + + $code = ""; + + if(isset($code_pre[$line-4])) + { + $code .= $line-3 . ". ".$code_pre[$line-4]; + } + + if(isset($code_pre[$line-3])) + { + $code .= $line-2 . ". ".$code_pre[$line-3]; + } + + if(isset($code_pre[$line-2])) + { + $code .= $line-1 . ". ".$code_pre[$line-2]; + } + + $code .= $line . ". ".$code_pre[$line-1]; // The actual line. + + if(isset($code_pre[$line])) + { + $code .= $line+1 . ". ".$code_pre[$line]; + } + + if(isset($code_pre[$line+1])) + { + $code .= $line+2 . ". ".$code_pre[$line+1]; + } + + if(isset($code_pre[$line+2])) + { + $code .= $line+3 . ". ".$code_pre[$line+2]; + } + + unset($code_pre); + + $parser_exists = false; + + if(!is_object($parser) || !method_exists($parser, 'mycode_parse_php')) + { + if(@file_exists(MYBB_ROOT."inc/class_parser.php")) + { + @require_once MYBB_ROOT."inc/class_parser.php"; + $parser = new postParser; + $parser_exists = true; + } + } + else + { + $parser_exists = true; + } + + if($parser_exists) + { + $code = $parser->mycode_parse_php($code, true); + } + else + { + $code = @nl2br($code); + } + + $error_message .= "
    Kod:
    {$code}
    \n"; + } + } + $backtrace = $this->generate_backtrace(); + if($backtrace && !in_array($type, $this->mybb_error_types)) + { + $error_message .= "
    Fragment kodu:
    {$backtrace}
    \n"; + } + $error_message .= "
    \n"; + } + } + + if(isset($lang->settings['charset'])) + { + $charset = $lang->settings['charset']; + } + else + { + $charset = 'UTF-8'; + } + + if(!headers_sent() && !defined("IN_INSTALL") && !defined("IN_UPGRADE")) + { + @header('HTTP/1.1 503 Service Temporarily Unavailable'); + @header('Status: 503 Service Temporarily Unavailable'); + @header('Retry-After: 1800'); + @header("Content-type: text/html; charset={$charset}"); + $_SERVER['PHP_SELF'] = htmlspecialchars_uni($_SERVER['PHP_SELF']); + + echo << + + + + {$mybb->settings['bbname']} - błąd wewnętrzny + + + +
    + + +
    +

    {$title}

    + +
    + {$error_message} + +
    +
    +
    + + +EOF; + } + else + { + echo << + #mybb_error_content { border: 1px solid #026CB1; background: #fff; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; } + #mybb_error_content a:link { color: #026CB1; text-decoration: none; } + #mybb_error_content a:visited { color: #026CB1; text-decoration: none; } + #mybb_error_content a:hover, a:active { color: #000; text-decoration: underline; } + #mybb_error_content h2 { font-size: 12px; padding: 4px; background: #026CB1; color: #fff; margin: 0; border-bottom: none; } + #mybb_error_error { padding: 6px; } + #mybb_error_footer { font-size: 12px; border-top: 1px dotted #DDDDDD; padding-top: 10px; } + #mybb_error_content dt { font-weight: bold; } + +
    +

    {$title}

    +
    + {$error_message} + +
    +
    +EOF; + } + exit(1); + } + + /** + * Generates a backtrace if the server supports it. + * + * @return string The generated backtrace + */ + function generate_backtrace() + { + if(function_exists("debug_backtrace")) + { + $trace = debug_backtrace(); + $backtrace = "\n"; + $backtrace .= "\n"; + $backtrace .= "\n"; + $backtrace .= "\n"; + $backtrace .= "\n"; + $backtrace .= "\n\n"; + + // Strip off this function from trace + array_shift($trace); + + foreach($trace as $call) + { + if(empty($call['file'])) $call['file'] = "[PHP]"; + if(empty($call['line'])) $call['line'] = " "; + if(!empty($call['class'])) $call['function'] = $call['class'].$call['type'].$call['function']; + $call['file'] = str_replace(MYBB_ROOT, "/", $call['file']); + $backtrace .= "\n"; + $backtrace .= "\n"; + $backtrace .= "\n"; + $backtrace .= "\n"; + $backtrace .= "\n"; + } + $backtrace .= "
    PlikLiniaFunkcja
    {$call['file']}{$call['line']}{$call['function']}
    \n"; + } + return $backtrace; + } +} diff --git a/Upload/inc/class_feedgeneration.php b/Upload/inc/class_feedgeneration.php new file mode 100644 index 0000000..08d6f77 --- /dev/null +++ b/Upload/inc/class_feedgeneration.php @@ -0,0 +1,224 @@ +feed_format = 'atom1.0'; + } + else + { + $this->feed_format = 'rss2.0'; + } + } + + /** + * Sets the channel information for the RSS feed. + * + * @param array The channel information + */ + function set_channel($channel) + { + $this->channel = $channel; + } + + /** + * Adds an item to the RSS feed. + * + * @param array The item. + */ + function add_item($item) + { + $this->items[] = $item; + } + + /** + * Generate and echo XML for the feed. + * + */ + function generate_feed() + { + global $lang; + + // First, add the feed metadata. + switch($this->feed_format) + { + // Ouput an Atom 1.0 formatted feed. + case "atom1.0": + $this->channel['date'] = gmdate("Y-m-d\TH:i:s\Z", $this->channel['date']); + $this->xml .= "settings['charset']}\"?>\n"; + $this->xml .= "\n"; + $this->xml .= "\t<![CDATA[".$this->sanitize_content($this->channel['title'])."]]>\n"; + $this->xml .= "\tsanitize_content($this->channel['description'])."]]>\n"; + $this->xml .= "\tchannel['link']}syndication.php\"/>\n"; + $this->xml .= "\t{$this->channel['link']}\n"; + $this->xml .= "\tchannel['link']}\"/>\n"; + $this->xml .= "\t{$this->channel['date']}\n"; + $this->xml .= "\tMyBB\n"; + break; + // The default is the RSS 2.0 format. + default: + $this->channel['date'] = gmdate("D, d M Y H:i:s O", $this->channel['date']); + $this->xml .= "settings['charset']}\"?>\n"; + $this->xml .= "\n"; + $this->xml .= "\t\n"; + $this->xml .= "\t\t<![CDATA[".$this->sanitize_content($this->channel['title'])."]]>\n"; + $this->xml .= "\t\t".$this->channel['link']."\n"; + $this->xml .= "\t\tsanitize_content($this->channel['description'])."]]>\n"; + $this->xml .= "\t\t".$this->channel['date']."\n"; + $this->xml .= "\t\tMyBB\n"; + } + + // Now loop through all of the items and add them to the feed XML. + foreach($this->items as $item) + { + if(!$item['date']) + { + $item['date'] = TIME_NOW; + } + switch($this->feed_format) + { + // Output Atom 1.0 format feed. + case "atom1.0": + $item['date'] = date("Y-m-d\TH:i:s\Z", $item['date']); + $this->xml .= "\t\n"; + if(!empty($item['author'])) + { + $this->xml .= "\t\t\n"; + $this->xml .= "\t\t\tsanitize_content($item['author'])."]]>\n"; + $this->xml .= "\t\t\n"; + } + $this->xml .= "\t\t{$item['date']}\n"; + if(empty($item['updated'])) + { + $item['updated'] = $item['date']; + } + else + { + $item['updated'] = date("Y-m-d\TH:i:s\Z", $item['updated']); + } + $this->xml .= "\t\t{$item['updated']}\n"; + $this->xml .= "\t\t\n"; + $this->xml .= "\t\t{$item['link']}\n"; + $this->xml .= "\t\t<![CDATA[".$this->sanitize_content($item['title'])."]]>\n"; + $this->xml .= "\t\tsanitize_content($item['description'])."]]>\n"; + $this->xml .= "\t\tfalse\n"; + $this->xml .= "\t\n"; + break; + + // The default is the RSS 2.0 format. + default: + $item['date'] = date("D, d M Y H:i:s O", $item['date']); + $this->xml .= "\t\t\n"; + $this->xml .= "\t\t\t<![CDATA[".$this->sanitize_content($item['title'])."]]>\n"; + $this->xml .= "\t\t\t".$item['link']."\n"; + $this->xml .= "\t\t\t".$item['date']."\n"; + if(!empty($item['author'])) + { + $this->xml .= "\t\t\tsanitize_content($item['author'])."]]>\n"; + } + $this->xml .= "\t\t\t".$item['link']."\n"; + $this->xml .= "\t\t\t\n"; + $this->xml .= "\t\t\t\n"; + $this->xml .= "\t\t\n"; + break; + } + } + + // Now, neatly end the feed XML. + switch($this->feed_format) + { + case "atom1.0": + $this->xml .= ""; + break; + default: + $this->xml .= "\t\n"; + $this->xml .= ""; + } + } + + /** + * Sanitize content suitable for RSS feeds. + * + * @param string The string we wish to sanitize. + * @return string The cleaned string. + */ + function sanitize_content($content) + { + $content = preg_replace("#&[^\s]([^\#])(?![a-z1-4]{1,10});#i", "&$1", $content); + $content = str_replace("]]>", "]]]]>", $content); + + return $content; + } + + /** + * Output the feed XML. + */ + function output_feed() + { + global $lang; + // Send an appropriate header to the browser. + switch($this->feed_format) + { + case "atom1.0": + header("Content-Type: application/atom+xml; charset=\"{$lang->settings['charset']}\""); + break; + default: + header("Content-Type: text/xml; charset=\"{$lang->settings['charset']}\""); + } + + // Output the feed XML. If the feed hasn't been generated, do so. + if($this->xml) + { + echo $this->xml; + } + else + { + $this->generate_feed(); + echo $this->xml; + } + } +} diff --git a/Upload/inc/class_feedparser.php b/Upload/inc/class_feedparser.php new file mode 100644 index 0000000..f738911 --- /dev/null +++ b/Upload/inc/class_feedparser.php @@ -0,0 +1,240 @@ +")+1 !== strlen($contents)) + { + $contents = substr($contents, 0, strrpos($contents, ">")+1); + } + + // Could not load the feed, return an error + if(!$contents) + { + $this->error = "invalid_file"; + return false; + } + + // Parse the feed and get the tree + $parser = new XMLParser($contents); + $tree = $parser->get_tree(); + + // If the feed is invalid, throw back an error + if($tree == false) + { + $this->error = "invalid_feed_xml"; + return false; + } + + // Change array key names to lower case + $tree = $this->keys_to_lowercase($tree); + + // This is an RSS feed, parse it + if(array_key_exists("rss", $tree)) + { + $this->parse_rss($tree['rss']); + } + + // We don't know how to parse this feed + else + { + $this->error = "unknown_feed_type"; + return false; + } + } + + /** + * Parses an XML structure in the format of an RSS feed + * + * @param array PHP XML parser structure + * @return boolean true + */ + function parse_rss($feed_contents) + { + foreach(array('title', 'link', 'description', 'pubdate') as $value) + { + if(!isset($feed_contents['channel'][$value]['value'])) + { + $feed_contents['channel'][$value]['value'] = ''; + } + } + + // Fetch channel information from the parsed feed + $this->channel = array( + "title" => $feed_contents['channel']['title']['value'], + "link" => $feed_contents['channel']['link']['value'], + "description" => $feed_contents['channel']['description']['value'], + "date" => $feed_contents['channel']['pubdate']['value'], + "date_timestamp" => $this->get_rss_timestamp($feed_contents['channel']['pubdate']['value']) + ); + + // The XML parser does not create a multidimensional array of items if there is one item, so fake it + if(!array_key_exists("0", $feed_contents['channel']['item'])) + { + $feed_contents['channel']['item'] = array($feed_contents['channel']['item']); + } + + // Loop through each of the items in the feed + foreach($feed_contents['channel']['item'] as $feed_item) + { + // Here is a nice long stretch of code for parsing items, we do it this way because most elements are optional in an + // item and we only want to assign what we have. + + $item = array(); + + + // Set the item title if we have it + if(array_key_exists("title", $feed_item)) + { + $item['title'] = $feed_item['title']['value']; + } + + if(array_key_exists("description", $feed_item)) + { + $item['description'] = $feed_item['description']['value']; + } + + if(array_key_exists("link", $feed_item)) + { + $item['link'] = $feed_item['link']['value']; + } + + // If we have a pub date, store it and attempt to generate a unix timestamp from it + if(array_key_exists("pubdate", $feed_item)) + { + $item['date'] = $feed_item['pubdate']['value']; + $item['date_timestamp'] = $this->get_rss_timestamp($item['date']); + } + + // If we have a GUID + if(array_key_exists("guid", $feed_item)) + { + $item['guid'] = $feed_item['guid']['value']; + } + // Otherwise, attempt to generate one from the link and item title + else + { + $item['guid'] = md5($item['link'].$item['title']); + } + + // If we have some content, set it + if(array_key_exists("content:encoded", $feed_item)) + { + $item['content'] = $feed_item['content:encoded']['value']; + } + else if(array_key_exists("content", $feed_item)) + { + $item['content'] = $feed_item['content']['value']; + } + + // We have a DC based creator, set it + if(array_key_exists("dc:creator", $feed_item)) + { + $item['author'] = $feed_item['dc:creator']['value']; + } + // Otherwise, attempt to use the author if we have it + else if(array_key_exists("author", $feed_item)) + { + $item['author'] = $feed_item['author']['value']; + } + + // Assign the item to our list of items + $this->items[] = $item; + } + return true; + } + + /** + * Convert all array keys within an array to lowercase + * + * @param array The array to be converted + * @return array The converted array + */ + function keys_to_lowercase($array) + { + $new_array = array(); + foreach($array as $key => $value) + { + $new_key = strtolower($key); + if(is_array($value)) + { + $new_array[$new_key] = $this->keys_to_lowercase($value); + } + else + { + $new_array[$new_key] = $value; + } + } + return $new_array; + } + + /** + * Converts an RSS date stamp in to a unix timestamp + * + * @param string The RSS date + * @return integer The unix timestamp (if successful), 0 if unsuccessful + */ + function get_rss_timestamp($date) + { + $stamp = strtotime($date); + if($stamp <= 0) + { + if(preg_match("#\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2}#", $date, $result)) + { + $date = str_replace(array("T", "+"), array(" ", " +"), $date); + $date[23] = ""; + } + $stamp = strtotime($date); + } + return $stamp; + } +} diff --git a/Upload/inc/class_graph.php b/Upload/inc/class_graph.php new file mode 100644 index 0000000..e49f55f --- /dev/null +++ b/Upload/inc/class_graph.php @@ -0,0 +1,337 @@ += 2, create base image + if(gd_version() >= 2) + { + $this->im = imagecreatetruecolor($this->img_width, $this->img_height); + } + else + { + $this->im = imagecreate($this->img_width, $this->img_height); + } + + // No GD support, die. + if(!$this->im) + { + return false; + } + + if(function_exists("imageantialias")) + { + imageantialias($this->im, true); + } + + // Fill the background + imagefill($this->im, 0, 0, $this->color(239, 239, 239)); + + // Create our internal working graph box + $inside_end_x = $this->inside_x+$this->inside_width; + $inside_end_y = $this->inside_y+$this->inside_height; + $this->image_create_rectangle($this->inside_x, $this->inside_y, $inside_end_x, $inside_end_y, 4, $this->color(254, 254, 254)); + + // Draw our three lines inside our internal working graph area + for($i = 1; $i < 4; ++$i) + { + $y_value = $this->inside_y+(($this->inside_height/4)*$i); + imageline($this->im, $this->inside_x, $y_value, $inside_end_x, $y_value, $this->color(185, 185, 185)); + } + } + + /** + * Select and allocate a color to the internal image resource + * + * @param integer The red value + * @param integer The green value + * @param integer The blue value + * @return integer A color identifier + */ + private function color($red, $green, $blue) + { + return imagecolorallocate($this->im, $red, $green, $blue); + } + + /** + * Creates a filled rectangle with optional rounded corners + * + * @param integer The initial x value + * @param integer The initial y value + * @param integer The ending x value + * @param integer The ending y value + * @param integer The optional radius + * @param integer The optional rectangle color (defaults to black) + */ + private function image_create_rectangle($x1, $y1, $x2, $y2, $radius=1, $color=null) + { + if($color == null) + { + $color = $this->color(0, 0, 0); + } + + // Draw our rectangle + imagefilledrectangle($this->im, $x1, $y1+$radius, $x2, $y2-$radius, $color); + imagefilledrectangle($this->im, $x1+$radius, $y1, $x2-$radius, $y2, $color); + + if($radius > 0) + { + $diameter = $radius*2; + + // Now draw our four corners on the rectangle + imagefilledellipse($this->im, $x1+$radius, $y1+$radius, $diameter, $diameter, $color); + imagefilledellipse($this->im, $x1+$radius, $y2-$radius, $diameter, $diameter, $color); + imagefilledellipse($this->im, $x2-$radius, $y2-$radius, $diameter, $diameter, $color); + imagefilledellipse($this->im, $x2-$radius, $y1+$radius, $diameter, $diameter, $color); + } + } + + /** + * Creates a nicer thick line for angled lines + * + * @param integer The initial x value + * @param integer The initial y value + * @param integer The ending x value + * @param integer The ending y value + * @param integer The optional rectangle color (defaults to black) + * @param integer The optional thickness (defaults to 1) + */ + private function imagelinethick($x1, $y1, $x2, $y2, $color, $thick = 1) + { + if($thick == 1) + { + return imageline($this->im, $x1, $y1, $x2, $y2, $color); + } + + $t = $thick / 2 - 0.5; + if($x1 == $x2 || $y1 == $y2) + { + return imagefilledrectangle($this->im, round(min($x1, $x2) - $t), round(min($y1, $y2) - $t), round(max($x1, $x2) + $t), round(max($y1, $y2) + $t), $color); + } + + $k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q + $a = $t / sqrt(1 + pow($k, 2)); + $points = array( + round($x1 - (1+$k)*$a), round($y1 + (1-$k)*$a), + round($x1 - (1-$k)*$a), round($y1 - (1+$k)*$a), + round($x2 + (1+$k)*$a), round($y2 - (1-$k)*$a), + round($x2 + (1-$k)*$a), round($y2 + (1+$k)*$a), + ); + imagefilledpolygon($this->im, $points, 4, $color); + + return imagepolygon($this->im, $points, 4, $color); + } + + /** + * Adds an array of x, y points to the internal points array + * + * @param array The array of x, y points to add + */ + public function add_points($points) + { + $this->points = array_merge($this->points, $points); + } + + /** + * Adds an array of x labels to the internal labels array + * + * @param array The array of x labels to add + */ + public function add_x_labels($labels) + { + $this->x_labels = array_merge($this->x_labels, $labels); + } + + /** + * Sets a bottom label + * + * @param string The bottom label to set + */ + public function set_bottom_label($label) + { + $this->bottom_label = $label; + } + + /** + * Renders the graph to memory + * + */ + public function render() + { + // Get our max's and min's + $asorted = $this->points; + sort($asorted, SORT_NUMERIC); + $min = $asorted[0]; + $max = $asorted[count($asorted)-1]; + + // Scale based on how many points we need to shove into 930 pixels of width + $x_delta = $this->inside_width/count($this->points); + + // Scale our y axis to 220 pixels + $y_scale_factor = ($max-$min)/$this->inside_height; + + // Get our Y initial + $y_initial = $this->inside_y+$this->inside_height; + + // Get our scale for finding our points of reference to place our x axis labels + $x_label_scale = ceil(count($this->points)/20); + $x_label_points = array(); + + foreach($this->points as $x => $y) + { + if(($x_label_scale == 0 || (($x+1) % $x_label_scale) == 0) && $x != 0) + { + $x_label_points[] = $x; + + imagedashedline($this->im, $this->inside_x+($x_delta*$x), 30, $this->inside_x+($x_delta*$x), $y_initial, $this->color(185, 185, 185)); + + imagefilledellipse($this->im, $this->inside_x+($x_delta*$x), $y_initial-$next_y_scaled+0.5, 8, 8, $this->color(84, 92, 209)); + } + + // Look ahead to find our next point, if there is one + if(!array_key_exists($x+1, $this->points)) + { + break; + } + $next_y = $this->points[$x+1]; + + if($y_scale_factor == 0) + { + $y_scaled = $next_y_scaled = 0; + } + else + { + $y_scaled = ($y-$min)/$y_scale_factor; + $next_y_scaled = ($next_y-$min)/$y_scale_factor; + } + + // Draw our line + $this->imagelinethick($this->inside_x+($x_delta*$x), $y_initial-$y_scaled, $this->inside_x+($x_delta*($x+1)), $y_initial-$next_y_scaled, $this->color(84, 92, 209), 3); + } + + // Draw our x labels + foreach($x_label_points as $x) + { + $label = $this->x_labels[$x]; + $text_width = imagefontwidth(2)*strlen($label); + $x = $this->inside_x+($x_delta*$x)-($text_width/2); + + imagestring($this->im, 2, $x, $y_initial+5, $label, $this->color(0, 0, 0)); + } + + // Draw our bottom label + imagestring($this->im, 2, ($this->img_width / 2), $y_initial+25, $this->bottom_label, $this->color(0, 0, 0)); + + if($max > 4) + { + // Draw our y labels + for($i = 1; $i < 4; ++$i) + { + $y_value = $this->inside_y+(($this->inside_height/4)*$i); + imagestring($this->im, 2, 5, $y_value-7, my_number_format(round($min+(($max-$min)/4)*(4-$i))), $this->color(0, 0, 0)); + } + } + imagestring($this->im, 2, 5, $this->inside_y+$this->inside_height-7, my_number_format($min), $this->color(0, 0, 0)); + imagestring($this->im, 2, 5, $this->inside_y-7, my_number_format($max), $this->color(0, 0, 0)); + } + + /** + * Outputs the graph to the screen in PNG format + * + */ + public function output() + { + // Output the image + header("Content-type: image/png"); + imagepng($this->im); + imagedestroy($this->im); + exit; + } +} + diff --git a/Upload/inc/class_language.php b/Upload/inc/class_language.php new file mode 100644 index 0000000..1e22f89 --- /dev/null +++ b/Upload/inc/class_language.php @@ -0,0 +1,237 @@ +path = $path; + } + + /** + * Check if a specific language exists. + * + * @param string The language to check for. + * @return boolean True when exists, false when does not exist. + */ + function language_exists($language) + { + $language = preg_replace("#[^a-z0-9\-_]#i", "", $language); + if(file_exists($this->path."/".$language.".php")) + { + return true; + } + else + { + return false; + } + } + + /** + * Set the language for an area. + * + * @param string The language to use. + * @param string The area to set the language for. + */ + function set_language($language="english", $area="user") + { + global $mybb; + + $language = preg_replace("#[^a-z0-9\-_]#i", "", $language); + + // Default language is English. + if($language == "") + { + $language = "english"; + } + + // Check if the language exists. + if(!$this->language_exists($language)) + { + die("Language $language ($this->path/$language) is not installed"); + } + + $this->language = $language; + require $this->path."/".$language.".php"; + $this->settings = $langinfo; + + // Load the admin language files as well, if needed. + if($area == "admin") + { + if(!is_dir($this->path."/".$language."/{$area}")) + { + if(!is_dir($this->path."/".$mybb->settings['cplanguage']."/{$area}")) + { + if(!is_dir($this->path."/english/{$area}")) + { + die("Your forum does not contain an Administration set. Please reupload the english language administration pack."); + } + else + { + $language = "english"; + } + } + else + { + $language = $mybb->settings['cplanguage']; + } + } + $this->language = $language."/{$area}"; + $this->fallback = $this->fallback."/{$area}"; + } + } + + /** + * Load the language variables for a section. + * + * @param string The section name. + * @param boolean Is this a datahandler? + * @param boolean supress the error if the file doesn't exist? + */ + function load($section, $isdatahandler=false, $supress_error=false) + { + // Assign language variables. + // Datahandlers are never in admin lang directory. + if($isdatahandler === true) + { + $lfile = $this->path."/".str_replace('/admin', '', $this->language)."/".$section.".lang.php"; + } + else + { + $lfile = $this->path."/".$this->language."/".$section.".lang.php"; + } + + if(file_exists($lfile)) + { + require_once $lfile; + } + elseif(file_exists($this->path."/".$this->fallback."/".$section.".lang.php")) + { + require_once $this->path."/".$this->fallback."/".$section.".lang.php"; + } + else + { + if($supress_error != true) + { + die("$lfile does not exist"); + } + } + + // We must unite and protect our language variables! + $lang_keys_ignore = array('language', 'path', 'settings'); + + if(isset($l) && is_array($l)) + { + foreach($l as $key => $val) + { + if((empty($this->$key) || $this->$key != $val) && !in_array($key, $lang_keys_ignore)) + { + $this->$key = $val; + } + } + } + } + + function sprintf($string) + { + $arg_list = func_get_args(); + $num_args = count($arg_list); + + for($i = 1; $i < $num_args; $i++) + { + $string = str_replace('{'.$i.'}', $arg_list[$i], $string); + } + + return $string; + } + + /** + * Get the language variables for a section. + * + * @param boolean Admin variables when true, user when false. + * @return array The language variables. + */ + function get_languages($admin=0) + { + $dir = @opendir($this->path); + while($lang = readdir($dir)) + { + $ext = my_strtolower(get_extension($lang)); + if($lang != "." && $lang != ".." && $ext == "php") + { + $lname = str_replace(".".$ext, "", $lang); + require $this->path."/".$lang; + if(!$admin || ($admin && $langinfo['admin'])) + { + $languages[$lname] = $langinfo['name']; + } + } + } + @ksort($languages); + return $languages; + } + + /** + * Parse contents for language variables. + * + * @param string The contents to parse. + * @return string The parsed contents. + */ + function parse($contents) + { + $contents = preg_replace_callback("##", array($this, 'parse_replace'), $contents); + return $contents; + } + + /** + * Replace content with language variable. + * + * @param array Matches. + * @return string Language variable. + */ + function parse_replace($matches) + { + return $this->$matches[1]; + } +} diff --git a/Upload/inc/class_mailhandler.php b/Upload/inc/class_mailhandler.php new file mode 100644 index 0000000..80e9af0 --- /dev/null +++ b/Upload/inc/class_mailhandler.php @@ -0,0 +1,410 @@ +message = ''; + $this->headers = $headers; + + if($from) + { + $this->from = $from; + } + else + { + $this->from = ""; + + if($mybb->settings['mail_handler'] == 'smtp') + { + $this->from = $mybb->settings['adminemail']; + } + else + { + $this->from = '"'.$this->utf8_encode($mybb->settings['bbname']).'"'; + $this->from .= " <{$mybb->settings['adminemail']}>"; + } + } + + if($return_email) + { + $this->return_email = $return_email; + } + else + { + $this->return_email = ""; + if($mybb->settings['returnemail']) + { + $this->return_email = $mybb->settings['returnemail']; + } + else + { + $this->return_email = $mybb->settings['adminemail']; + } + } + + $this->set_to($to); + $this->set_subject($subject); + + if($charset) + { + $this->set_charset($charset); + } + + $this->parse_format = $format; + $this->set_common_headers(); + $this->set_message($message, $message_text); + } + + /** + * Sets the charset. + * + * @param string charset + */ + function set_charset($charset) + { + global $lang; + + if(empty($charset)) + { + $this->charset = $lang->settings['charset']; + } + else + { + $this->charset = $charset; + } + } + + /** + * Sets and formats the email message. + * + * @param string message + */ + function set_message($message, $message_text="") + { + $message = $this->cleanup_crlf($message); + + if($message_text) + { + $message_text = $this->cleanup_crlf($message_text); + } + + if($this->parse_format == "html" || $this->parse_format == "both") + { + $this->set_html_headers($message, $message_text); + } + else + { + $this->message = $message; + $this->set_plain_headers(); + } + } + + /** + * Sets and formats the email subject. + * + * @param string subject + */ + function set_subject($subject) + { + $this->orig_subject = $this->cleanup($subject); + $this->subject = $this->utf8_encode($this->orig_subject); + } + + /** + * Sets and formats the recipient address. + * + * @param string to + */ + function set_to($to) + { + $to = $this->cleanup($to); + + $this->to = $this->cleanup($to); + } + + /** + * Sets the plain headers, text/plain + */ + function set_plain_headers() + { + $this->headers .= "Content-Type: text/plain; charset={$this->charset}{$this->delimiter}"; + } + + /** + * Sets the alternative headers, text/html and text/plain. + * + * @param string message + */ + function set_html_headers($message, $message_text="") + { + if(!$message_text && $this->parse_format == 'both') + { + $message_text = strip_tags($message); + } + + if($this->parse_format == 'both') + { + $mime_boundary = "=_NextPart".md5(TIME_NOW); + + $this->headers .= "Content-Type: multipart/alternative; boundary=\"{$mime_boundary}\"{$this->delimiter}"; + $this->message = "This is a multi-part message in MIME format.{$this->delimiter}{$this->delimiter}"; + + $this->message .= "--{$mime_boundary}{$this->delimiter}"; + $this->message .= "Content-Type: text/plain; charset=\"{$this->charset}\"{$this->delimiter}"; + $this->message .= "Content-Transfer-Encoding: 8bit{$this->delimiter}{$this->delimiter}"; + $this->message .= $message_text."{$this->delimiter}{$this->delimiter}"; + + $this->message .= "--{$mime_boundary}{$this->delimiter}"; + + $this->message .= "Content-Type: text/html; charset=\"{$this->charset}\"{$this->delimiter}"; + $this->message .= "Content-Transfer-Encoding: 8bit{$this->delimiter}{$this->delimiter}"; + $this->message .= $message."{$this->delimiter}{$this->delimiter}"; + + $this->message .= "--{$mime_boundary}--{$this->delimiter}{$this->delimiter}"; + } + else + { + $this->headers .= "Content-Type: text/html; charset=\"{$this->charset}\"{$this->delimiter}"; + $this->headers .= "Content-Transfer-Encoding: 8bit{$this->delimiter}{$this->delimiter}"; + $this->message = $message."{$this->delimiter}{$this->delimiter}"; + } + } + + /** + * Sets the common headers. + */ + function set_common_headers() + { + global $mybb; + + // Build mail headers + $this->headers .= "From: {$this->from}{$this->delimiter}"; + + if($this->return_email) + { + $this->headers .= "Return-Path: {$this->return_email}{$this->delimiter}"; + $this->headers .= "Reply-To: {$this->return_email}{$this->delimiter}"; + } + + if(isset($_SERVER['SERVER_NAME'])) + { + $http_host = $_SERVER['SERVER_NAME']; + } + else if(isset($_SERVER['HTTP_HOST'])) + { + $http_host = $_SERVER['HTTP_HOST']; + } + else + { + $http_host = "unknown.local"; + } + + $msg_id = md5(uniqid(TIME_NOW, true)) . "@" . $http_host; + + if($mybb->settings['mail_message_id']) + { + $this->headers .= "Message-ID: <{$msg_id}>{$this->delimiter}"; + } + $this->headers .= "Content-Transfer-Encoding: 8bit{$this->delimiter}"; + $this->headers .= "X-Priority: 3{$this->delimiter}"; + $this->headers .= "X-Mailer: MyBB{$this->delimiter}"; + $this->headers .= "MIME-Version: 1.0{$this->delimiter}"; + } + + /** + * Log a fatal error message to the database. + * + * @param string The error message + * @param string Any additional information + */ + function fatal_error($error) + { + global $db; + + $mail_error = array( + "subject" => $db->escape_string($this->orig_subject), + "message" => $db->escape_string($this->message), + "toaddress" => $db->escape_string($this->to), + "fromaddress" => $db->escape_string($this->from), + "dateline" => TIME_NOW, + "error" => $db->escape_string($error), + "smtperror" => $db->escape_string($this->data), + "smtpcode" => (int)$this->code + ); + $db->insert_query("mailerrors", $mail_error); + + // Another neat feature would be the ability to notify the site administrator via email - but wait, with email down, how do we do that? How about private message and hope the admin checks their PMs? + } + + /** + * Rids pesky characters from subjects, recipients, from addresses etc (prevents mail injection too) + * + * @param string The string being checked + * @return string The cleaned string + */ + function cleanup($string) + { + $string = str_replace(array("\r", "\n", "\r\n"), "", $string); + $string = trim($string); + return $string; + } + + /** + * Converts message text to suit the correct delimiter + * See dev.mybb.com/issues/1735 (Jorge Oliveira) + * + * @param string The text being converted + * @return string The converted string + */ + function cleanup_crlf($text) + { + $text = str_replace("\r\n", "\n", $text); + $text = str_replace("\r", "\n", $text); + $text = str_replace("\n", "\r\n", $text); + + return $text; + } + + /** + * Encode a string based on the character set enabled. Used to encode subjects + * and recipients in email messages going out so that they show up correctly + * in email clients. + * + * @param string The string to be encoded. + * @return string The encoded string. + */ + function utf8_encode($string) + { + if(strtolower($this->charset) == 'utf-8' && preg_match('/[^\x20-\x7E]/', $string)) + { + $chunk_size = 47; // Derived from floor((75 - strlen("=?UTF-8?B??=")) * 0.75); + $len = strlen($string); + $output = ''; + $pos = 0; + + while($pos < $len) + { + $newpos = min($pos + $chunk_size, $len); + + while(ord($string[$newpos]) >= 0x80 && ord($string[$newpos]) < 0xC0) + { + // Reduce len until it's safe to split UTF-8. + $newpos--; + } + + $chunk = substr($string, $pos, $newpos - $pos); + $pos = $newpos; + + $output .= " =?UTF-8?B?".base64_encode($chunk)."?=\n"; + } + return trim($output); + } + return $string; + } +} diff --git a/Upload/inc/class_moderation.php b/Upload/inc/class_moderation.php new file mode 100644 index 0000000..e6a6d9f --- /dev/null +++ b/Upload/inc/class_moderation.php @@ -0,0 +1,3767 @@ +run_hooks("class_moderation_close_threads", $tids); + + $tid_list = implode(',', $tids); + + $openthread = array( + "closed" => 1, + ); + $db->update_query("threads", $openthread, "tid IN ($tid_list) AND closed NOT LIKE 'moved|%'"); + + return true; + } + + /** + * Open one or more threads + * + * @param int Thread IDs + * @return boolean true + */ + + function open_threads($tids) + { + global $db, $plugins; + + if(!is_array($tids)) + { + $tids = array($tids); + } + + if(empty($tids)) + { + return false; + } + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + + $plugins->run_hooks("class_moderation_open_threads", $tids); + + $tid_list = implode(',', $tids); + + $closethread = array( + "closed" => 0, + ); + $db->update_query("threads", $closethread, "tid IN ($tid_list)"); + + return true; + } + + /** + * Stick one or more threads + * + * @param int Thread IDs + * @return boolean true + */ + function stick_threads($tids) + { + global $db, $plugins; + + if(!is_array($tids)) + { + $tids = array($tids); + } + + if(empty($tids)) + { + return false; + } + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + + $plugins->run_hooks("class_moderation_stick_threads", $tids); + + $tid_list = implode(',', $tids); + + $stickthread = array( + "sticky" => 1, + ); + $db->update_query("threads", $stickthread, "tid IN ($tid_list)"); + + return true; + } + + /** + * Unstick one or more thread + * + * @param int Thread IDs + * @return boolean true + */ + function unstick_threads($tids) + { + global $db, $plugins; + + if(!is_array($tids)) + { + $tids = array($tids); + } + + if(empty($tids)) + { + return false; + } + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + + $plugins->run_hooks("class_moderation_unstick_threads", $tids); + + $tid_list = implode(',', $tids); + + $unstickthread = array( + "sticky" => 0, + ); + $db->update_query("threads", $unstickthread, "tid IN ($tid_list)"); + + return true; + } + + /** + * Remove redirects that redirect to the specified thread + * + * @param int Thread ID of the thread + * @return boolean true + */ + function remove_redirects($tid) + { + global $db, $plugins; + + $plugins->run_hooks("class_moderation_remove_redirects", $tid); + + // Delete the redirects + $tid = (int)$tid; + if(empty($tid)) + { + return false; + } + + $query = $db->simple_select('threads', 'tid', "closed='moved|$tid'"); + while($redirect_tid = $db->fetch_field($query, 'tid')) + { + $this->delete_thread($redirect_tid); + } + + return true; + } + + /** + * Delete a thread + * + * @param int Thread ID of the thread + * @return boolean true + */ + function delete_thread($tid) + { + global $db, $cache, $plugins; + + $tid = (int)$tid; + + $plugins->run_hooks("class_moderation_delete_thread_start", $tid); + + $thread = get_thread($tid); + if(!$thread) + { + return false; + } + $forum = get_forum($thread['fid']); + + $userposts = array(); + + // Find the pid, uid, visibility, and forum post count status + $query = $db->simple_select('posts', 'pid, uid, visible', "tid='{$tid}'"); + $pids = array(); + $num_unapproved_posts = $num_approved_posts = $num_deleted_posts = 0; + while($post = $db->fetch_array($query)) + { + $pids[] = $post['pid']; + + if(!function_exists("remove_attachments")) + { + require_once MYBB_ROOT."inc/functions_upload.php"; + } + + // Remove attachments + remove_attachments($post['pid']); + + // If the post is unapproved, count it! + if(($post['visible'] == 0 && $thread['visible'] != -1) || $thread['visible'] == 0) + { + $num_unapproved_posts++; + } + elseif($post['visible'] == -1 || $thread['visible'] == -1) + { + $num_deleted_posts++; + } + else + { + $num_approved_posts++; + + // Count the post counts for each user to be subtracted + if($forum['usepostcounts'] != 0) + { + if(!isset($userposts[$post['uid']]['num_posts'])) + { + $userposts[$post['uid']]['num_posts'] = 0; + } + ++$userposts[$post['uid']]['num_posts']; + } + } + } + + if($forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|') + { + if(!isset($userposts[$thread['uid']]['num_threads'])) + { + $userposts[$thread['uid']]['num_threads'] = 0; + } + ++$userposts[$thread['uid']]['num_threads']; + } + + // Remove post count from users + if($thread['visible'] == 1) + { + if(!empty($userposts)) + { + foreach($userposts as $uid => $subtract) + { + $update_array = array( + "postnum" => "-{$subtract['num_posts']}", + "threadnum" => "-{$subtract['num_threads']}", + ); + update_user_counters($uid, $update_array); + } + } + } + // Delete posts and their attachments + if(!empty($pids)) + { + $pids = implode(',', $pids); + $db->delete_query("posts", "pid IN ($pids)"); + $db->delete_query("attachments", "pid IN ($pids)"); + $db->delete_query("reportedcontent", "id IN ($pids) AND (type = 'post' OR type = '')"); + } + + // Delete threads, redirects, subscriptions, polls, and poll votes + $db->delete_query("threads", "tid='$tid'"); + $query = $db->simple_select('threads', 'tid', "closed='moved|$tid'"); + while($redirect_tid = $db->fetch_field($query, 'tid')) + { + $this->delete_thread($redirect_tid); + } + $db->delete_query("threadsubscriptions", "tid='$tid'"); + $db->delete_query("polls", "tid='$tid'"); + $db->delete_query("pollvotes", "pid='".$thread['poll']."'"); + $db->delete_query("threadsread", "tid='$tid'"); + $db->delete_query("threadratings", "tid='$tid'"); + + $updated_counters = array( + "posts" => "-{$num_approved_posts}", + "unapprovedposts" => "-{$num_unapproved_posts}", + "deletedposts" => "-{$num_deleted_posts}" + ); + + if($thread['visible'] == 1) + { + $updated_counters['threads'] = -1; + } + elseif($thread['visible'] == -1) + { + $updated_counters['deletedthreads'] = -1; + } + else + { + $updated_counters['unapprovedthreads'] = -1; + } + + if(strpos($thread['closed'], 'moved|') !== false) + { + // Redirect + if($thread['visible'] == 1) + { + $updated_counters['posts'] = -1; + } + elseif($thread['visible'] == -1) + { + $updated_counters['deletedposts'] = -1; + } + else + { + $updated_counters['unapprovedposts'] = -1; + } + } + + // Update forum count + update_forum_counters($thread['fid'], $updated_counters); + update_forum_lastpost($thread['fid']); + + $plugins->run_hooks("class_moderation_delete_thread", $tid); + + return true; + } + + /** + * Delete a poll + * + * @param int Poll id + * @return boolean true + */ + function delete_poll($pid) + { + global $db, $plugins; + + $pid = (int)$pid; + + if(empty($pid)) + { + return false; + } + + $plugins->run_hooks("class_moderation_delete_poll", $pid); + + $db->delete_query("polls", "pid='$pid'"); + $db->delete_query("pollvotes", "pid='$pid'"); + $pollarray = array( + 'poll' => '0', + ); + $db->update_query("threads", $pollarray, "poll='$pid'"); + + return true; + } + + /** + * Approve one or more threads + * + * @param array Thread IDs + * @return boolean true + */ + function approve_threads($tids) + { + global $db, $cache, $plugins; + + if(!is_array($tids)) + { + $tids = array($tids); + } + + if(empty($tids)) + { + return false; + } + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + + $tid_list = $forum_counters = $user_counters = $posts_to_approve = array(); + + foreach($tids as $tid) + { + $thread = get_thread($tid); + if(!$thread || $thread['visible'] == 1 || $thread['visible'] == -1) + { + continue; + } + $tid_list[] = $thread['tid']; + + $forum = get_forum($thread['fid']); + + if(!isset($forum_counters[$forum['fid']])) + { + $forum_counters[$forum['fid']] = array( + 'num_posts' => 0, + 'num_threads' => 0, + 'num_deleted_posts' => 0, + 'num_unapproved_posts' => 0 + ); + } + + if(!isset($user_counters[$thread['uid']])) + { + $user_counters[$thread['uid']] = array( + 'num_posts' => 0, + 'num_threads' => 0 + ); + } + + ++$forum_counters[$forum['fid']]['num_threads']; + $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Remove implied visible from count + $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['deletedposts']; + $forum_counters[$forum['fid']]['num_unapproved_posts'] += $thread['deletedposts']+$thread['replies']+1; + + if($forum['usepostcounts'] != 0) + { + // On approving thread restore user post counts + $query = $db->simple_select("posts", "COUNT(pid) as posts, uid", "tid='{$tid}' AND (visible='1' OR pid='{$thread['firstpost']}') AND uid > 0 GROUP BY uid"); + while($counter = $db->fetch_array($query)) + { + $user_counters[$counter['uid']]['num_posts'] += $counter['posts']; + } + } + + if($forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|') + { + ++$user_counters[$thread['uid']]['num_threads']; + } + + $posts_to_approve[] = $thread['firstpost']; + } + + if(!empty($tid_list)) + { + $tid_moved_list = ""; + $comma = ""; + foreach($tid_list as $tid) + { + $tid_moved_list .= "{$comma}'moved|{$tid}'"; + $comma = ","; + } + $tid_list = implode(',', $tid_list); + $approve = array( + "visible" => 1 + ); + $db->update_query("threads", $approve, "tid IN ($tid_list)"); + // Approve redirects, too + $redirect_tids = array(); + $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})"); + while($redirect_tid = $db->fetch_field($query, 'tid')) + { + $redirect_tids[] = $redirect_tid; + } + if(!empty($redirect_tids)) + { + $this->approve_threads($redirect_tids); + } + if(!empty($posts_to_approve)) + { + $db->update_query("posts", $approve, "pid IN (".implode(',', $posts_to_approve).")"); + } + + $plugins->run_hooks("class_moderation_approve_threads", $tids); + + if(!empty($forum_counters)) + { + foreach($forum_counters as $fid => $counters) + { + // Update stats + $update_array = array( + "threads" => "+{$counters['num_threads']}", + "unapprovedthreads" => "-{$counters['num_threads']}", + "posts" => "+{$counters['num_posts']}", + "unapprovedposts" => "-{$counters['num_unapproved_posts']}", + "deletedposts" => "+{$counters['num_deleted_posts']}" + ); + update_forum_counters($fid, $update_array); + update_forum_lastpost($fid); + } + } + + if(!empty($user_counters)) + { + foreach($user_counters as $uid => $counters) + { + $update_array = array( + "postnum" => "+{$counters['num_posts']}", + "threadnum" => "+{$counters['num_threads']}", + ); + update_user_counters($uid, $update_array); + } + } + } + return true; + } + + /** + * Unapprove one or more threads + * + * @param array Thread IDs + * @return boolean true + */ + function unapprove_threads($tids) + { + global $db, $cache, $plugins; + + if(!is_array($tids)) + { + $tids = array($tids); + } + + if(empty($tids)) + { + return false; + } + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + + $tid_list = implode(',', $tids); + $tid_moved_list = ""; + $comma = ""; + foreach($tids as $tid) + { + $tid_moved_list .= "{$comma}'moved|{$tid}'"; + $comma = ","; + } + + $forum_counters = $user_counters = $posts_to_unapprove = array(); + + foreach($tids as $tid) + { + $thread = get_thread($tid); + $forum = get_forum($thread['fid']); + + if($thread['visible'] == 1 || $thread['visible'] == -1) + { + if(!isset($forum_counters[$forum['fid']])) + { + $forum_counters[$forum['fid']] = array( + 'num_threads' => 0, + 'num_posts' => 0, + 'num_unapprovedthreads' => 0, + 'num_unapprovedposts' => 0, + 'num_deletedthreads' => 0, + 'num_deletedposts' => 0 + ); + } + + if(!isset($user_counters[$thread['uid']])) + { + $user_counters[$thread['uid']] = array( + 'num_posts' => 0, + 'num_threads' => 0 + ); + } + + ++$forum_counters[$forum['fid']]['num_unapprovedthreads']; + $forum_counters[$forum['fid']]['num_unapprovedposts'] += $thread['replies']+$thread['deletedposts']+1; + + if($thread['visible'] == 1) + { + ++$forum_counters[$forum['fid']]['num_threads']; + $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Add implied invisible to count + $forum_counters[$forum['fid']]['num_deletedposts'] += $thread['deletedposts']; + } + else + { + ++$forum_counters[$forum['fid']]['num_deletedthreads']; + $forum_counters[$forum['fid']]['num_deletedposts'] += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; // Add implied invisible to count + $forum_counters[$forum['fid']]['num_unapprovedposts'] += $thread['unapprovedposts']; + } + + // On unapproving thread update user post counts + if($thread['visible'] == 1 && $forum['usepostcounts'] != 0) + { + $query = $db->simple_select("posts", "COUNT(pid) AS posts, uid", "tid='{$tid}' AND (visible='1' OR pid='{$thread['firstpost']}') AND uid > 0 GROUP BY uid"); + while($counter = $db->fetch_array($query)) + { + $user_counters[$counter['uid']]['num_posts'] += $counter['posts']; + } + } + + if($thread['visible'] == 1 && $forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|') + { + ++$user_counters[$thread['uid']]['num_threads']; + } + + } + $posts_to_unapprove[] = $thread['firstpost']; + } + + $approve = array( + "visible" => 0 + ); + $db->update_query("threads", $approve, "tid IN ($tid_list)"); + // Unapprove redirects, too + $redirect_tids = array(); + $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})"); + while($redirect_tid = $db->fetch_field($query, 'tid')) + { + $redirect_tids[] = $redirect_tid; + } + if(!empty($redirect_tids)) + { + $this->unapprove_threads($redirect_tids); + } + if(!empty($posts_to_unapprove)) + { + $db->update_query("posts", $approve, "pid IN (".implode(',', $posts_to_unapprove).")"); + } + + $plugins->run_hooks("class_moderation_unapprove_threads", $tids); + + if(!empty($forum_counters)) + { + foreach($forum_counters as $fid => $counters) + { + // Update stats + $update_array = array( + "threads" => "-{$counters['num_threads']}", + "unapprovedthreads" => "+{$counters['num_unapprovedthreads']}", + "posts" => "-{$counters['num_posts']}", + "unapprovedposts" => "+{$counters['num_unapprovedposts']}", + "deletedthreads" => "-{$counters['num_deletedthreads']}", + "deletedposts" => "-{$counters['num_deletedposts']}" + ); + update_forum_counters($fid, $update_array); + update_forum_lastpost($fid); + } + } + + if(!empty($user_counters)) + { + foreach($user_counters as $uid => $counters) + { + $update_array = array( + "postnum" => "-{$counters['num_posts']}", + "threadnum" => "-{$counters['num_threads']}", + ); + update_user_counters($uid, $update_array); + } + } + + return true; + } + + /** + * Delete a specific post + * + * @param int Post ID + * @return boolean true + */ + function delete_post($pid) + { + global $db, $cache, $plugins; + + $pid = $plugins->run_hooks("class_moderation_delete_post_start", $pid); + // Get pid, uid, fid, tid, visibility, forum post count status of post + $pid = (int)$pid; + $query = $db->query(" + SELECT p.pid, p.uid, p.fid, p.tid, p.visible, t.visible as threadvisible + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + WHERE p.pid='$pid' + "); + $post = $db->fetch_array($query); + if(!$post) + { + return false; + } + + $forum = get_forum($post['fid']); + // If post counts enabled in this forum and it hasn't already been unapproved, remove 1 + if($forum['usepostcounts'] != 0 && $post['visible'] != -1 && $post['visible'] != 0 && $post['threadvisible'] != 0 && $post['threadvisible'] != -1) + { + update_user_counters($post['uid'], array('postnum' => "-1")); + } + + if(!function_exists("remove_attachments")) + { + require MYBB_ROOT."inc/functions_upload.php"; + } + + // Remove attachments + remove_attachments($pid); + + // Delete the post + $db->delete_query("posts", "pid='$pid'"); + + // Remove any reports attached to this post + $db->delete_query("reportedcontent", "id='{$pid}' AND (type = 'post' OR type = '')"); + + // Update unapproved post count + if($post['visible'] == 0) + { + $update_array = array( + "unapprovedposts" => "-1" + ); + } + elseif($post['visible'] == -1) + { + $update_array = array( + "deletedposts" => "-1" + ); + } + else + { + $update_array = array( + "replies" => "-1" + ); + } + + $plugins->run_hooks("class_moderation_delete_post", $post['pid']); + + update_thread_counters($post['tid'], $update_array); + update_last_post($post['tid']); + + // Update unapproved post count + if(($post['visible'] == 0 && $post['threadvisible'] != -1) || $post['threadvisible'] == 0) + { + $update_array = array( + "unapprovedposts" => "-1" + ); + } + elseif($post['visible'] == -1 || $post['threadvisible'] == -1) + { + $update_array = array( + "deletedposts" => "-1" + ); + } + else + { + $update_array = array( + "posts" => "-1" + ); + } + + update_forum_counters($post['fid'], $update_array); + update_forum_lastpost($post['fid']); + + return true; + } + + /** + * Merge posts within thread + * + * @param array Post IDs to be merged + * @param int Thread ID (Set to 0 if posts from multiple threads are + * selected) + * @return int ID of the post into which all other posts are merged + */ + function merge_posts($pids, $tid=0, $sep="new_line") + { + global $db, $plugins; + + // Make sure we only have valid values + $pids = array_map('intval', $pids); + + if(empty($pids) || count($pids) < 2) + { + return false; + } + + $pidin = implode(',', $pids); + $attachment_count = 0; + + $first = 1; + // Get the messages to be merged + $query = $db->query(" + SELECT p.pid, p.uid, p.fid, p.tid, p.visible, p.message, t.visible AS threadvisible, t.replies AS threadreplies, t.firstpost AS threadfirstpost, t.unapprovedposts AS threadunapprovedposts, COUNT(a.aid) AS attachmentcount + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + LEFT JOIN ".TABLE_PREFIX."attachments a ON (a.pid=p.pid AND a.visible=1) + WHERE p.pid IN($pidin) + GROUP BY p.pid + ORDER BY p.dateline ASC + "); + $message = ''; + $threads = $forum_counters = $thread_counters = $user_counters = array(); + while($post = $db->fetch_array($query)) + { + $threads[$post['tid']] = $post['tid']; + if(!isset($thread_counters[$post['tid']])) + { + $thread_counters[$post['tid']] = array( + 'replies' => 0, + 'unapprovedposts' => 0, + 'deletedposts' => 0, + 'attachmentcount' => 0 + ); + } + if($first == 1) + { // all posts will be merged into this one + $masterpid = $post['pid']; + $message = $post['message']; + $fid = $post['fid']; + $mastertid = $post['tid']; + $first = 0; + } + else + { + // these are the selected posts + if($sep == "new_line") + { + $message .= "\n\n {$post['message']}"; + } + else + { + $message .= "[hr]{$post['message']}"; + } + + if(!isset($forum_counters[$post['fid']])) + { + $forum_counters[$post['fid']] = array( + 'num_posts' => 0, + 'unapprovedposts' => 0, + 'deletedposts' => 0 + ); + } + + if($post['visible'] == 1) + { + --$thread_counters[$post['tid']]['replies']; + $forum = get_forum($post['fid']); + if(!isset($user_counters[$post['uid']])) + { + $user_counters[$post['uid']] = array( + 'num_posts' => 0, + 'num_threads' => 0 + ); + } + // Subtract 1 from user's post count + if($forum['usepostcounts'] != 0 && $post['threadvisible'] == 1) + { + // Update post count of the user of the merged posts + --$user_counters[$post['uid']]['num_posts']; + } + if($post['threadfirstpost'] == $post['pid'] && $forum['usethreadcounts'] != 0 && $post['threadvisible'] == 1) + { + --$user_counters[$post['uid']]['num_threads']; + } + } + elseif($post['visible'] == 0) + { + // Subtract 1 unapproved post from post's thread + --$thread_counters[$post['tid']]['unapprovedposts']; + } + elseif($post['visible'] == -1) + { + // Subtract 1 deleted post from post's thread + --$thread_counters[$post['tid']]['deletedposts']; + } + $thread_counters[$post['tid']]['attachmentcount'] -= $post['attachmentcount']; + + // Subtract 1 post from post's forum + if($post['threadvisible'] == 1 && $post['visible'] == 1) + { + --$forum_counters[$post['fid']]['num_posts']; + } + elseif($post['threadvisible'] == 0 || ($post['visible'] == 0 && $post['threadvisible'] != -1)) + { + --$forum_counters[$post['fid']]['unapprovedposts']; + } + else + { + --$forum_counters[$post['fid']]['deletedposts']; + } + } + } + + // Update the message + $mergepost = array( + "message" => $db->escape_string($message), + ); + $db->update_query("posts", $mergepost, "pid = '{$masterpid}'"); + + // Delete the extra posts + $db->delete_query("posts", "pid IN({$pidin}) AND pid != '{$masterpid}'"); + + // Update pid for attachments + $mergepost2 = array( + "pid" => $masterpid, + ); + $db->update_query("attachments", $mergepost2, "pid IN({$pidin})"); + + // If the first post of a thread is merged out, the first should be updated + $query = $db->simple_select("threads", "tid, uid, fid, visible", "firstpost IN({$pidin}) AND firstpost != '{$masterpid}'"); + while($thread = $db->fetch_array($query)) + { + // In some cases the first post of a thread changes + // Therefore resync the visible field to make sure they're the same if they're not + $query = $db->simple_select("posts", "pid, uid, visible", "tid='{$thread['tid']}'", array('order_by' => 'dateline', 'order_dir' => 'asc', 'limit' => 1)); + $new_firstpost = $db->fetch_array($query); + if($thread['visible'] != $new_firstpost['visible']) + { + $db->update_query("posts", array('visible' => $thread['visible']), "pid='{$new_firstpost['pid']}'"); + // Correct counters + if($new_firstpost['visible'] == 1) + { + --$thread_counters[$thread['tid']]['replies']; + } + elseif($new_firstpost['visible'] == -1) + { + --$thread_counters[$thread['tid']]['deletedposts']; + } + else + { + --$thread_counters[$thread['tid']]['unapprovedposts']; + } + if($thread['visible'] == 1) + { + ++$thread_counters[$thread['tid']]['replies']; + } + elseif($thread['visible'] == -1) + { + ++$thread_counters[$thread['tid']]['deletedposts']; + } + else + { + ++$thread_counters[$thread['tid']]['unapprovedposts']; + } + } + + if($new_firstpost['uid'] != $thread['uid'] && $forum['usethreadcounts'] != 0 && $thread['visible'] == 1) + { + if(!isset($user_counters[$new_firstpost['uid']])) + { + $user_counters[$new_firstpost['uid']] = array( + 'num_posts' => 0, + 'num_threads' => 0 + ); + } + ++$user_counters[$new_firstpost['uid']]['num_threads']; + } + update_first_post($thread['tid']); + } + + $arguments = array("pids" => $pids, "tid" => $tid); + $plugins->run_hooks("class_moderation_merge_posts", $arguments); + + if(!empty($thread_counters)) + { + foreach($thread_counters as $tid => $counters) + { + $counters = array( + 'replies' => signed($counters['replies']), + 'unapprovedposts' => signed($counters['unapprovedposts']), + 'deletedposts' => signed($counters['deletedposts']), + 'attachmentcount' => signed($counters['attachmentcount']) + ); + update_thread_counters($tid, $counters); + update_last_post($tid); + } + } + + if(!empty($forum_counters)) + { + foreach($forum_counters as $fid => $counters) + { + $updated_forum_stats = array( + 'posts' => signed($counters['num_posts']), + 'unapprovedposts' => signed($counters['unapprovedposts']), + 'deletedposts' => signed($counters['deletedposts']) + ); + update_forum_counters($fid, $updated_forum_stats); + update_forum_lastpost($fid); + } + } + + if(!empty($user_counters)) + { + foreach($user_counters as $uid => $counters) + { + $update_array = array( + "postnum" => "+{$counters['num_posts']}", + "threadnum" => "+{$counters['num_threads']}" + ); + update_user_counters($uid, $update_array); + } + } + + return $masterpid; + } + + /** + * Move/copy thread + * + * @param int Thread to be moved + * @param int Destination forum + * @param string Method of movement (redirect, copy, move) + * @param int Expiry timestamp for redirect + * @return int Thread ID + */ + function move_thread($tid, $new_fid, $method="redirect", $redirect_expire=0) + { + global $db, $plugins; + + // Get thread info + $tid = (int)$tid; + $new_fid = (int)$new_fid; + $redirect_expire = (int)$redirect_expire; + + $thread = get_thread($tid, true); + + $newforum = get_forum($new_fid); + if(!$thread || !$newforum) + { + return false; + } + $fid = $thread['fid']; + $forum = get_forum($fid); + + $num_threads = $num_unapproved_threads = $num_posts = $num_unapproved_posts = $num_deleted_posts = $num_deleted_threads = 0; + + if($thread['visible'] == 1) + { + $num_threads++; + $num_posts = $thread['replies']+1; + $num_unapproved_posts = $thread['unapprovedposts']; + $num_deleted_posts = $thread['deletedposts']; + } + elseif($thread['visible'] == -1) + { + $num_deleted_threads++; + // Implied forum deleted count for deleted threads + $num_deleted_posts = $thread['replies']+$thread['deletedposts']+$thread['unapprovedposts']+1; + } + else + { + $num_unapproved_threads++; + // Implied forum unapproved count for unapproved threads + $num_unapproved_posts = $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; + } + + switch($method) + { + case "redirect": // move (and leave redirect) thread + $arguments = array("tid" => $tid, "new_fid" => $new_fid); + $plugins->run_hooks("class_moderation_move_thread_redirect", $arguments); + + $query = $db->simple_select('threads', 'tid', "closed='moved|$tid' AND fid='$new_fid'"); + while($redirect_tid = $db->fetch_field($query, 'tid')) + { + $this->delete_thread($redirect_tid); + } + $changefid = array( + "fid" => $new_fid, + ); + $db->update_query("threads", $changefid, "tid='$tid'"); + $db->update_query("posts", $changefid, "tid='$tid'"); + + // If the thread has a prefix and the destination forum doesn't accept that prefix, remove the prefix + if($thread['prefix'] != 0) + { + switch($db->type) + { + case "pgsql": + case "sqlite": + $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'"); + break; + default: + $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'"); + } + if($db->fetch_field($query, "num_prefixes") == 0) + { + $sqlarray = array( + "prefix" => 0, + ); + $db->update_query("threads", $sqlarray, "tid='$tid'"); + } + } + + $threadarray = array( + "fid" => $thread['fid'], + "subject" => $db->escape_string($thread['subject']), + "icon" => $thread['icon'], + "uid" => $thread['uid'], + "username" => $db->escape_string($thread['username']), + "dateline" => $thread['dateline'], + "lastpost" => $thread['lastpost'], + "lastposteruid" => $thread['lastposteruid'], + "lastposter" => $db->escape_string($thread['lastposter']), + "views" => 0, + "replies" => 0, + "closed" => "moved|$tid", + "sticky" => $thread['sticky'], + "visible" => (int)$thread['visible'], + "notes" => '' + ); + $redirect_tid = $db->insert_query("threads", $threadarray); + if($redirect_expire) + { + $this->expire_thread($redirect_tid, $redirect_expire); + } + + // If we're moving back to a forum where we left a redirect, delete the rediect + $query = $db->simple_select("threads", "tid", "closed LIKE 'moved|".(int)$tid."' AND fid='".(int)$new_fid."'"); + while($redirect_tid = $db->fetch_field($query, 'tid')) + { + $this->delete_thread($redirect_tid); + } + break; + case "copy":// copy thread + + $threadarray = array( + "fid" => $new_fid, + "subject" => $db->escape_string($thread['subject']), + "icon" => $thread['icon'], + "uid" => $thread['uid'], + "username" => $db->escape_string($thread['username']), + "dateline" => $thread['dateline'], + "firstpost" => 0, + "lastpost" => $thread['lastpost'], + "lastposteruid" => $thread['lastposteruid'], + "lastposter" => $db->escape_string($thread['lastposter']), + "views" => $thread['views'], + "replies" => $thread['replies'], + "closed" => $thread['closed'], + "sticky" => $thread['sticky'], + "visible" => (int)$thread['visible'], + "unapprovedposts" => $thread['unapprovedposts'], + "deletedposts" => $thread['deletedposts'], + "attachmentcount" => $thread['attachmentcount'], + "prefix" => $thread['prefix'], + "notes" => '' + ); + + $arguments = array("tid" => $tid, "new_fid" => $new_fid); + $plugins->run_hooks("class_moderation_copy_thread", $arguments); + + // If the thread has a prefix and the destination forum doesn't accept that prefix, don't copy the prefix + if($threadarray['prefix'] != 0) + { + switch($db->type) + { + case "pgsql": + case "sqlite": + $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'"); + break; + default: + $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'"); + } + if($db->fetch_field($query, "num_prefixes") == 0) + { + $threadarray['prefix'] = 0; + } + } + + $newtid = $db->insert_query("threads", $threadarray); + + if($thread['poll'] != 0) + { + $query = $db->simple_select("polls", "*", "tid = '{$thread['tid']}'"); + $poll = $db->fetch_array($query); + + $poll_array = array( + 'tid' => $newtid, + 'question' => $db->escape_string($poll['question']), + 'dateline' => $poll['dateline'], + 'options' => $db->escape_string($poll['options']), + 'votes' => $poll['votes'], + 'numoptions' => $poll['numoptions'], + 'numvotes' => $poll['numvotes'], + 'timeout' => $poll['timeout'], + 'closed' => $poll['closed'], + 'multiple' => $poll['multiple'], + 'public' => $poll['public'] + ); + $new_pid = $db->insert_query("polls", $poll_array); + + $query = $db->simple_select("pollvotes", "*", "pid = '{$poll['pid']}'"); + while($pollvote = $db->fetch_array($query)) + { + $pollvote_array = array( + 'pid' => $new_pid, + 'uid' => $pollvote['uid'], + 'voteoption' => $pollvote['voteoption'], + 'dateline' => $pollvote['dateline'], + ); + $db->insert_query("pollvotes", $pollvote_array); + } + + $db->update_query("threads", array('poll' => $new_pid), "tid='{$newtid}'"); + } + + $query = $db->simple_select("posts", "*", "tid = '{$thread['tid']}'"); + while($post = $db->fetch_array($query)) + { + $post_array = array( + 'tid' => $newtid, + 'fid' => $new_fid, + 'subject' => $db->escape_string($post['subject']), + 'icon' => $post['icon'], + 'uid' => $post['uid'], + 'username' => $db->escape_string($post['username']), + 'dateline' => $post['dateline'], + 'ipaddress' => $db->escape_binary($post['ipaddress']), + 'includesig' => $post['includesig'], + 'smilieoff' => $post['smilieoff'], + 'edituid' => $post['edituid'], + 'edittime' => $post['edittime'], + 'visible' => $post['visible'], + 'message' => $db->escape_string($post['message']), + ); + $pid = $db->insert_query("posts", $post_array); + + // Properly set our new firstpost in our new thread + if($thread['firstpost'] == $post['pid']) + { + $db->update_query("threads", array('firstpost' => $pid), "tid='{$newtid}'"); + } + + // Insert attachments for this post + $query2 = $db->simple_select("attachments", "*", "pid = '{$post['pid']}'"); + while($attachment = $db->fetch_array($query2)) + { + $attachment_array = array( + 'pid' => $pid, + 'uid' => $attachment['uid'], + 'filename' => $db->escape_string($attachment['filename']), + 'filetype' => $attachment['filetype'], + 'filesize' => $attachment['filesize'], + 'attachname' => $attachment['attachname'], + 'downloads' => $attachment['downloads'], + 'visible' => $attachment['visible'], + 'thumbnail' => $attachment['thumbnail'] + ); + $new_aid = $db->insert_query("attachments", $attachment_array); + + $post['message'] = str_replace("[attachment={$attachment['aid']}]", "[attachment={$new_aid}]", $post['message']); + } + + if(strpos($post['message'], "[attachment=") !== false) + { + $db->update_query("posts", array('message' => $db->escape_string($post['message'])), "pid='{$pid}'"); + } + } + + update_thread_data($newtid); + + $the_thread = $newtid; + break; + default: + case "move": // plain move thread + $arguments = array("tid" => $tid, "new_fid" => $new_fid); + $plugins->run_hooks("class_moderation_move_simple", $arguments); + + $sqlarray = array( + "fid" => $new_fid, + ); + $db->update_query("threads", $sqlarray, "tid='$tid'"); + $db->update_query("posts", $sqlarray, "tid='$tid'"); + + // If the thread has a prefix and the destination forum doesn't accept that prefix, remove the prefix + if($thread['prefix'] != 0) + { + switch($db->type) + { + case "pgsql": + case "sqlite": + $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'"); + break; + default: + $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$new_fid,%' OR forums='-1') AND pid='".$thread['prefix']."'"); + } + if($db->fetch_field($query, "num_prefixes") == 0) + { + $sqlarray = array( + "prefix" => 0, + ); + $db->update_query("threads", $sqlarray, "tid='$tid'"); + } + } + + // If we're moving back to a forum where we left a redirect, delete the rediect + $query = $db->simple_select("threads", "tid", "closed LIKE 'moved|".(int)$tid."' AND fid='".(int)$new_fid."'"); + while($redirect_tid = $db->fetch_field($query, 'tid')) + { + $this->delete_thread($redirect_tid); + } + break; + } + + // Do post and thread count changes if changing between countable and non-countable forums + $query = $db->query(" + SELECT COUNT(p.pid) AS posts, u.uid + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) + WHERE p.tid='$tid' AND p.visible=1 + GROUP BY u.uid + ORDER BY posts DESC + "); + while($posters = $db->fetch_array($query)) + { + $pcount = 0; + if($forum['usepostcounts'] == 1 && $method != 'copy' && $newforum['usepostcounts'] == 0 && $thread['visible'] == 1) + { + $pcount -= $posters['posts']; + } + if(($forum['usepostcounts'] == 0 || $method == 'copy') && $newforum['usepostcounts'] == 1 && $thread['visible'] == 1) + { + $pcount += $posters['posts']; + } + + if($pcount > 0) + { + update_user_counters($posters['uid'], array('postnum' => "+$pcount")); + } + elseif($pcount < 0) + { + update_user_counters($posters['uid'], array('postnum' => $pcount)); + } + } + + if($forum['usethreadcounts'] == 1 && $method != 'copy' && $newforum['usethreadcounts'] == 0 && $thread['visible'] == 1) + { + update_user_counters($thread['uid'], array('threadnum' => "-1")); + } + elseif(($forum['usethreadcounts'] == 0 || $method == 'copy') && $newforum['usethreadcounts'] == 1 && $thread['visible'] == 1) + { + update_user_counters($thread['uid'], array('threadnum' => "+1")); + } + + // Update forum counts + $update_array = array( + "threads" => "+{$num_threads}", + "unapprovedthreads" => "+{$num_unapproved_threads}", + "posts" => "+{$num_posts}", + "unapprovedposts" => "+{$num_unapproved_posts}", + "deletedthreads" => "+{$num_deleted_threads}", + "deletedposts" => "+{$num_deleted_posts}" + ); + update_forum_counters($new_fid, $update_array); + update_forum_lastpost($new_fid); + + if($method != "copy") + { + // The redirect needs to be counted, too + if($method == "redirect") + { + if($thread['visible'] == -1) + { + --$num_deleted_threads; + --$num_deleted_posts; + } + elseif($thread['visible'] == 0) + { + --$num_unapproved_threads; + --$num_unapproved_posts; + } + else + { + --$num_threads; + --$num_posts; + } + } + $update_array = array( + "threads" => "-{$num_threads}", + "unapprovedthreads" => "-{$num_unapproved_threads}", + "posts" => "-{$num_posts}", + "unapprovedposts" => "-{$num_unapproved_posts}", + "deletedthreads" => "-{$num_deleted_threads}", + "deletedposts" => "-{$num_deleted_posts}" + ); + update_forum_counters($fid, $update_array); + update_forum_lastpost($fid); + } + + if(isset($newtid)) + { + return $newtid; + } + else + { + // Remove thread subscriptions for the users who no longer have permission to view the thread + $this->remove_thread_subscriptions($tid, false, $new_fid); + + return $tid; + } + } + + /** + * Merge one thread into another + * + * @param int Thread that will be merged into destination + * @param int Destination thread + * @param string New thread subject + * @return boolean true + */ + function merge_threads($mergetid, $tid, $subject) + { + global $db, $mybb, $mergethread, $thread, $plugins, $cache; + + $mergetid = (int)$mergetid; + $tid = (int)$tid; + + if(!isset($mergethread['tid']) || $mergethread['tid'] != $mergetid) + { + $mergethread = get_thread($mergetid); + } + if(!isset($thread['tid']) || $thread['tid'] != $tid) + { + $thread = get_thread($tid); + } + + if(!$mergethread || !$thread) + { + return false; + } + + $forum_cache = $cache->read('forums'); + + $threadarray = array(); + if(!$thread['poll'] && $mergethread['poll']) + { + $threadarray['poll'] = $mergethread['poll']; + $sqlarray = array( + "tid" => $tid, + ); + $db->update_query("polls", $sqlarray, "tid='".(int)$mergethread['tid']."'"); + } + // Both the old and the new thread have polls? Remove one + elseif($mergethread['poll']) + { + $db->delete_query("polls", "pid='{$mergethread['poll']}'"); + $db->delete_query("pollvotes", "pid='{$mergethread['poll']}'"); + } + + $subject = $db->escape_string($subject); + $threadarray['subject'] = $subject; + + $user_posts = array(); + if($thread['visible'] != $mergethread['visible'] || $forum_cache[$thread['fid']]['usepostcounts'] != $forum_cache[$mergethread['fid']]['usepostcounts']) + { + $query = $db->query(" + SELECT uid, COUNT(pid) AS postnum + FROM ".TABLE_PREFIX."posts + WHERE tid='{$mergetid}' AND visible=1 + GROUP BY uid + "); + while($post = $db->fetch_array($query)) + { + // Update user counters + if($mergethread['visible'] == 1 && $forum_cache[$mergethread['fid']]['usepostcounts'] == 1) + { + $user_posts[$post['uid']]['postnum'] -= $post['postnum']; + } + elseif($thread['visible'] == 1 && $forum_cache[$thread['fid']]['usepostcounts'] == 1) + { + $user_posts[$post['uid']]['postnum'] += $post['postnum']; + } + } + } + + $sqlarray = array( + "tid" => $tid, + "fid" => $thread['fid'], + "replyto" => 0, + ); + $db->update_query("posts", $sqlarray, "tid='{$mergetid}'"); + + $sqlarray = array( + "closed" => "moved|{$tid}", + ); + $db->update_query("threads", $sqlarray, "closed='moved|{$mergetid}'"); + $sqlarray = array( + "tid" => $tid, + ); + + // Update the thread ratings + $new_numrating = $thread['numratings'] + $mergethread['numratings']; + $new_threadrating = $thread['totalratings'] + $mergethread['totalratings']; + + $threadarray["numratings"] = $new_numrating; + $threadarray["totalratings"] = $new_threadrating; + $db->update_query("threads", $threadarray, "tid = '{$tid}'"); + + // Check if we have a thread subscription already for our new thread + $subscriptions = array(); + + $query = $db->simple_select("threadsubscriptions", "tid, uid", "tid='{$mergetid}' OR tid='{$tid}'"); + while($subscription = $db->fetch_array($query)) + { + if(!isset($subscriptions[$subscription['tid']])) + { + $subscriptions[$subscription['tid']] = array(); + } + $subscriptions[$subscription['tid']][] = $subscription['uid']; + } + + // Update any subscriptions for the merged thread + if(!empty($subscriptions[$mergetid])) + { + $update_users = array(); + foreach($subscriptions[$mergetid] as $user) + { + if(!isset($subscriptions[$tid]) || !in_array($user, $subscriptions[$tid])) + { + // User doesn't have a $tid subscription + $update_users[] = $user; + } + } + + if(!empty($update_users)) + { + $update_array = array( + "tid" => $tid + ); + + $update_users = implode(",", $update_users); + $db->update_query("threadsubscriptions", $update_array, "tid = '{$mergetid}' AND uid IN ({$update_users})"); + } + } + + // Remove source thread subscriptions + $db->delete_query("threadsubscriptions", "tid = '{$mergetid}'"); + + $arguments = array("mergetid" => $mergetid, "tid" => $tid, "subject" => $subject); + $plugins->run_hooks("class_moderation_merge_threads", $arguments); + + $this->delete_thread($mergetid); + + // Add the former first post + if($mergethread['visible'] == 1) + { + ++$mergethread['replies']; + } + elseif($mergethread['visible'] == -1) + { + ++$mergethread['deletedposts']; + } + else + { + ++$mergethread['unapprovedposts']; + } + + // In some cases the thread we may be merging with may cause us to have a new firstpost if it is an older thread + // Therefore resync the visible field to make sure they're the same if they're not + $query = $db->simple_select("posts", "pid, uid, visible", "tid='{$tid}'", array('order_by' => 'dateline', 'order_dir' => 'asc', 'limit' => 1)); + $new_firstpost = $db->fetch_array($query); + if($thread['visible'] != $new_firstpost['visible']) + { + $db->update_query("posts", array('visible' => $thread['visible']), "pid='{$new_firstpost['pid']}'"); + if($new_firstpost['visible'] == 1 && $forum_cache[$thread['fid']]['usepostcounts'] == 1) + { + --$user_posts[$post['uid']]['postnum']; + } + elseif($thread['visible'] == 1 && $forum_cache[$thread['fid']]['usepostcounts'] == 1) + { + ++$user_posts[$post['uid']]['postnum']; + } + } + // Update first post if needed + if($new_firstpost['pid'] != $thread['firstpost']) + { + update_first_post($thread['tid']); + } + + // Subtract merged thread from user counter + if($mergethread['visible'] == 1 && $forum_cache[$mergethread['fid']]['usethreadcounts'] == 1) + { + if(!isset($user_posts[$mergethread['uid']]['threadnum'])) + { + $user_posts[$mergethread['uid']]['threadnum'] = 0; + } + --$user_posts[$mergethread['uid']]['threadnum']; + } + + // Update thread count if thread has a new firstpost and is visible + if($thread['uid'] != $new_firstpost['uid'] && $thread['visible'] == 1 && $forum_cache[$thread['fid']]['usethreadcounts'] == 1) + { + if(!isset($user_posts[$thread['uid']]['threadnum'])) + { + $user_posts[$thread['uid']]['threadnum'] = 0; + } + --$user_posts[$thread['uid']]['threadnum']; + if(!isset($user_posts[$new_firstpost['uid']]['threadnum'])) + { + $user_posts[$new_firstpost['uid']]['threadnum'] = 0; + } + ++$user_posts[$new_firstpost['uid']]['threadnum']; + } + + // Thread is not in current forum + if($mergethread['fid'] != $thread['fid']) + { + // If new thread is unapproved, implied counter comes in to effect + if($thread['visible'] == 0) + { + $updated_stats = array( + "unapprovedposts" => '+'.($mergethread['replies']+$mergethread['unapprovedposts']+$mergethread['deletedposts']) + ); + } + elseif($thread['visible'] == -1) + { + $updated_stats = array( + "deletedposts" => '+'.($mergethread['replies']+$mergethread['deletedposts']+$mergethread['unapprovedposts']) + ); + } + else + { + $updated_stats = array( + "posts" => "+{$mergethread['replies']}", + "unapprovedposts" => "+{$mergethread['unapprovedposts']}", + "deletedposts" => "+{$mergethread['deletedposts']}" + ); + } + update_forum_counters($thread['fid'], $updated_stats); + + // If old thread is unapproved, implied counter comes in to effect + if($mergethread['visible'] == 0) + { + $updated_stats = array( + "unapprovedposts" => '-'.($mergethread['replies']+$mergethread['unapprovedposts']+$mergethread['deletedposts']) + ); + } + elseif($mergethread['visible'] == -1) + { + $updated_stats = array( + "deletedposts" => '-'.($mergethread['replies']+$mergethread['deletedposts']+$mergethread['unapprovedposts']) + ); + } + else + { + $updated_stats = array( + "posts" => "-{$mergethread['replies']}", + "unapprovedposts" => "-{$mergethread['unapprovedposts']}", + "deletedposts" => "-{$mergethread['deletedposts']}" + ); + } + update_forum_counters($mergethread['fid'], $updated_stats); + update_forum_lastpost($mergethread['fid']); + } + // Visibility changed + elseif($mergethread['visible'] != $thread['visible']) + { + $updated_stats = array( + 'posts' => 0, + 'unapprovedposts' => 0, + 'deletedposts' => 0 + ); + + // If old thread is unapproved, implied counter comes in to effect + if($mergethread['visible'] == 0) + { + $updated_stats['unapprovedposts'] -= $mergethread['replies']+$mergethread['deletedposts']; + $updated_stats['posts'] += $mergethread['replies']; + $updated_stats['deletedposts'] += $mergethread['deletedposts']; + } + elseif($mergethread['visible'] == -1) + { + $updated_stats['deletedposts'] -= $mergethread['replies']+$mergethread['unapprovedposts']; + $updated_stats['posts'] += $mergethread['replies']; + $updated_stats['unapprovedposts'] += $mergethread['unapprovedposts']; + } + + // If new thread is unapproved, implied counter comes in to effect + if($thread['visible'] == 0) + { + $updated_stats['unapprovedposts'] += $mergethread['replies']+$mergethread['deletedposts']; + $updated_stats['posts'] -= $mergethread['replies']; + $updated_stats['deletedposts'] -= $mergethread['deletedposts']; + } + elseif($thread['visible'] == -1) + { + $updated_stats['deletedposts'] += $mergethread['replies']+$mergethread['unapprovedposts']; + $updated_stats['posts'] -= $mergethread['replies']; + $updated_stats['unapprovedposts'] -= $mergethread['unapprovedposts']; + } + + $new_stats = array(); + if($updated_stats['posts'] < 0) + { + $new_stats['posts'] = $updated_stats['posts']; + } + elseif($updated_stats['posts'] > 0) + { + $new_stats['posts'] = "+{$updated_stats['posts']}"; + } + + if($updated_stats['unapprovedposts'] < 0) + { + $new_stats['unapprovedposts'] = $updated_stats['unapprovedposts']; + } + elseif($updated_stats['unapprovedposts'] > 0) + { + $new_stats['unapprovedposts'] = "+{$updated_stats['unapprovedposts']}"; + } + + if($updated_stats['deletedposts'] < 0) + { + $new_stats['deletedposts'] = $updated_stats['deletedposts']; + } + elseif($updated_stats['deletedposts'] > 0) + { + $new_stats['deletedposts'] = "+{$updated_stats['deletedposts']}"; + } + + if(!empty($new_stats)) + { + update_forum_counters($mergethread['fid'], $new_stats); + update_forum_lastpost($mergethread['fid']); + } + } + + if($thread['visible'] != $new_firstpost['visible']) + { + // Correct counters + if($new_firstpost['visible'] == 1) + { + --$mergethread['replies']; + } + elseif($new_firstpost['visible'] == -1) + { + --$mergethread['deletedposts']; + } + else + { + --$mergethread['unapprovedposts']; + } + if($thread['visible'] == 1) + { + ++$mergethread['replies']; + } + elseif($thread['visible'] == -1) + { + ++$mergethread['deletedposts']; + } + else + { + ++$mergethread['unapprovedposts']; + } + } + + // Update user counters + foreach($user_posts as $uid => $counters) + { + $update_array = array( + "postnum" => "+{$counters['postnum']}", + "threadnum" => "+{$counters['threadnum']}", + ); + update_user_counters($uid, $update_array); + } + + $updated_stats = array( + "replies" => "+{$mergethread['replies']}", + "attachmentcount" => "+{$mergethread['attachmentcount']}", + "unapprovedposts" => "+{$mergethread['unapprovedposts']}", + "deletedposts" => "+{$mergethread['unapprovedposts']}", + "deletedposts" => "+{$mergethread['deletedposts']}" + ); + update_thread_counters($tid, $updated_stats); + update_last_post($tid); + + // Forum last post has to be updated after thread + update_forum_lastpost($thread['fid']); + return true; + } + + /** + * Split posts into a new/existing thread + * + * @param array PIDs of posts to split + * @param int Original thread ID (this is only used as a base for the new + * thread; it can be set to 0 when the posts specified are coming from more + * than 1 thread) + * @param int Destination forum + * @param string New thread subject + * @param int TID if moving into existing thread + * @return int New thread ID + */ + function split_posts($pids, $tid, $moveto, $newsubject, $destination_tid=0) + { + global $db, $thread, $plugins, $cache; + + $tid = (int)$tid; + $moveto = (int)$moveto; + $newtid = (int)$destination_tid; + + // Make sure we only have valid values + $pids = array_map('intval', $pids); + + $pids_list = implode(',', $pids); + + // Get forum infos + $forum_cache = $cache->read('forums'); + + if(empty($pids) || !$forum_cache[$moveto]) + { + return false; + } + + // Get the first split post + $query = $db->simple_select('posts', 'pid,uid,visible,icon,username,dateline', 'pid IN ('.$pids_list.')', array('order_by' => 'dateline', 'order_dir' => 'asc', 'limit' => 1)); + + $post_info = $db->fetch_array($query); + + $visible = $post_info['visible']; + + $forum_counters[$moveto] = array( + 'threads' => 0, + 'deletedthreads' => 0, + 'unapprovedthreads' => 0, + 'posts' => 0, + 'unapprovedposts' => 0, + 'deletedposts' => 0 + ); + + if($destination_tid == 0) + { + // Splitting into a new thread + // Create the new thread + $newsubject = $db->escape_string($newsubject); + $newthread = array( + "fid" => $moveto, + "subject" => $newsubject, + "icon" => (int)$post_info['icon'], + "uid" => (int)$post_info['uid'], + "username" => $db->escape_string($post_info['username']), + "dateline" => (int)$post_info['dateline'], + "firstpost" => $post_info['pid'], + "lastpost" => 0, + "lastposter" => '', + "visible" => (int)$visible, + "notes" => '' + ); + $newtid = $db->insert_query("threads", $newthread); + + if($visible == 1) + { + ++$forum_counters[$moveto]['threads']; + if(!isset($user_counters[$newthread['uid']])) + { + $user_counters[$newthread['uid']] = array( + 'postnum' => 0, + 'threadnum' => 0 + ); + } + // Subtract thread from old thread opener + --$user_counters[$newthread['uid']]['threadnum']; + } + elseif($visible == -1) + { + ++$forum_counters[$moveto]['deletedthreads']; + } + else + { + // Unapproved thread? + ++$forum_counters[$moveto]['unapprovedthreads']; + } + } + else + { + $newthread = get_thread($newtid); + if(!$newthread) + { + return false; + } + $moveto = $newthread['fid']; + } + + // Get selected posts before moving forums to keep old fid + $original_posts_query = $db->query(" + SELECT p.pid, p.tid, p.fid, p.visible, p.uid, p.dateline, t.visible as threadvisible, t.firstpost, COUNT(a.aid) as postattachmentcount + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (p.tid=t.tid) + LEFT JOIN ".TABLE_PREFIX."attachments a ON (a.pid=p.pid AND a.visible=1) + WHERE p.pid IN ($pids_list) + GROUP BY p.pid + "); + + // Move the selected posts over + $sqlarray = array( + "tid" => $newtid, + "fid" => $moveto, + "replyto" => 0 + ); + $db->update_query("posts", $sqlarray, "pid IN ($pids_list)"); + + $thread_counters[$newtid] = array( + 'replies' => 0, + 'unapprovedposts' => 0, + 'deletedposts' => 0, + 'attachmentcount' => 0 + ); + + // Get posts being merged + while($post = $db->fetch_array($original_posts_query)) + { + if(!isset($thread_counters[$post['tid']])) + { + $thread_counters[$post['tid']] = array( + 'replies' => 0, + 'unapprovedposts' => 0, + 'deletedposts' => 0, + 'attachmentcount' => 0 + ); + } + if(!isset($forum_counters[$post['fid']])) + { + $forum_counters[$post['fid']] = array( + 'posts' => 0, + 'unapprovedposts' => 0, + 'deletedposts' => 0 + ); + } + if(!isset($user_counters[$post['uid']])) + { + $user_counters[$post['uid']] = array( + 'postnum' => 0, + 'threadnum' => 0 + ); + } + if($post['visible'] == 1) + { + // Modify users' post counts + if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usepostcounts'] == 1 && ($forum_cache[$moveto]['usepostcounts'] == 0 || $newthread['visible'] != 1)) + { + // Moving into a forum that doesn't count post counts + --$user_counters[$post['uid']]['postnum']; + } + + // Subtract 1 from the old thread's replies + --$thread_counters[$post['tid']]['replies']; + } + elseif($post['visible'] == 0) + { + // Unapproved post + // Subtract 1 from the old thread's unapproved posts + --$thread_counters[$post['tid']]['unapprovedposts']; + } + elseif($post['visible'] == -1) + { + // Soft deleted post + // Subtract 1 from the old thread's deleted posts + --$thread_counters[$post['tid']]['deletedposts']; + } + + // Subtract 1 from the old forum's posts + if($post['threadvisible'] == 1 && $post['visible'] == 1) + { + --$forum_counters[$post['fid']]['posts']; + } + elseif($post['threadvisible'] == 0 || ($post['visible'] == 0 && $post['threadvisible'] == 1)) + { + --$forum_counters[$post['fid']]['unapprovedposts']; + } + else + { + --$forum_counters[$post['fid']]['deletedposts']; + } + + // Subtract attachment counts from old thread and add to new thread (which are counted regardless of post or attachment unapproval at time of coding) + $thread_counters[$post['tid']]['attachmentcount'] -= $post['postattachmentcount']; + $thread_counters[$newtid]['attachmentcount'] += $post['postattachmentcount']; + + if($post['firstpost'] == $post['pid']) + { + // In some cases the first post of a thread changes + // Therefore resync the visible field to make sure they're the same if they're not + $query = $db->simple_select("posts", "pid, visible, uid", "tid='{$post['tid']}'", array('order_by' => 'dateline', 'order_dir' => 'asc', 'limit' => 1)); + $new_firstpost = $db->fetch_array($query); + + if(!isset($user_counters[$new_firstpost['uid']])) + { + $user_counters[$new_firstpost['uid']] = array( + 'postnum' => 0, + 'threadnum' => 0 + ); + } + + // Update post counters if visibility changes + if($post['threadvisible'] != $new_firstpost['visible']) + { + $db->update_query("posts", array('visible' => $post['threadvisible']), "pid='{$new_firstpost['pid']}'"); + // Subtract new first post + if($new_firstpost['visible'] == 1) + { + --$thread_counters[$post['tid']]['replies']; + if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usepostcounts'] == 1) + { + --$user_counters[$new_firstpost['uid']]['postnum']; + } + } + elseif($new_firstpost['visible'] == -1) + { + --$thread_counters[$post['tid']]['deletedposts']; + } + else + { + --$thread_counters[$post['tid']]['unapprovedposts']; + } + if($post['threadvisible'] == 0 || ($new_firstpost['visible'] == 0 && $post['threadvisible'] == 1)) + { + --$forum_counters[$post['fid']]['unapprovedposts']; + } + else + { + --$forum_counters[$post['fid']]['deletedposts']; + } + + // Add old first post + if($post['threadvisible'] == 1) + { + ++$thread_counters[$post['tid']]['replies']; + ++$forum_counters[$post['fid']]['posts']; + if($forum_cache[$post['fid']]['usepostcounts'] == 1) + { + ++$user_counters[$new_firstpost['uid']]['postnum']; + } + } + elseif($post['threadvisible'] == -1) + { + ++$thread_counters[$post['tid']]['deletedposts']; + ++$forum_counters[$post['fid']]['deletedposts']; + } + else + { + ++$thread_counters[$post['tid']]['unapprovedposts']; + ++$forum_counters[$post['fid']]['unapprovedposts']; + } + } + + // Update user thread counter if thread opener changes + if($post['threadvisible'] == 1 && $forum_cache[$post['fid']]['usethreadcounts'] == 1 && $post['uid'] != $new_firstpost['uid']) + { + // Subtract thread from old thread opener + --$user_counters[$post['uid']]['threadnum']; + // Add thread to new thread opener + ++$user_counters[$new_firstpost['uid']]['threadnum']; + } + update_first_post($post['tid']); + } + + // This is the new first post of an existing thread? + if($post['pid'] == $post_info['pid'] && $post['dateline'] < $newthread['dateline']) + { + // Update post counters if visibility changes + if($post['visible'] != $newthread['visible']) + { + $db->update_query("posts", array('visible' => $newthread['visible']), "pid='{$post['pid']}'"); + + // This is needed to update the forum counters correctly + $post['visible'] = $newthread['visible']; + } + + // Update user thread counter if thread opener changes + if($newthread['visible'] == 1 && $forum_cache[$newthread['fid']]['usethreadcounts'] == 1 && $post['uid'] != $newthread['uid']) + { + // Add thread to new thread opener + ++$user_counters[$post['uid']]['threadnum']; + if(!isset($user_counters[$newthread['uid']])) + { + $user_counters[$newthread['uid']] = array( + 'postnum' => 0, + 'threadnum' => 0 + ); + } + // Subtract thread from old thread opener + --$user_counters[$newthread['uid']]['threadnum']; + } + update_first_post($newtid); + } + + if($post['visible'] == 1) + { + // Modify users' post counts + if($newthread['visible'] == 1 && ($forum_cache[$post['fid']]['usepostcounts'] == 0 || $post['threadvisible'] != 1) && $forum_cache[$moveto]['usepostcounts'] == 1) + { + // Moving into a forum that does count post counts + ++$user_counters[$post['uid']]['postnum']; + } + + // Add 1 to the new thread's replies + ++$thread_counters[$newtid]['replies']; + } + elseif($post['visible'] == 0) + { + // Unapproved post + // Add 1 to the new thread's unapproved posts + ++$thread_counters[$newtid]['unapprovedposts']; + } + elseif($post['visible'] == -1) + { + // Soft deleted post + // Add 1 to the new thread's deleted posts + ++$thread_counters[$newtid]['deletedposts']; + } + + // Add 1 to the new forum's posts + if($newthread['visible'] == 1 && $post['visible'] == 1) + { + ++$forum_counters[$moveto]['posts']; + } + elseif($newthread['visible'] == 0 || ($post['visible'] == 0 && $newthread['visible'] == 1)) + { + ++$forum_counters[$moveto]['unapprovedposts']; + } + else + { + ++$forum_counters[$moveto]['deletedposts']; + } + } + + if($destination_tid == 0 && $newthread['visible'] == 1) + { + // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post + --$thread_counters[$newtid]['replies']; + } + elseif($destination_tid == 0 && $newthread['visible'] == 0) + { + // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post + --$thread_counters[$newtid]['unapprovedposts']; + } + elseif($destination_tid == 0 && $newthread['visible'] == -1) + { + // If splitting into a new thread, subtract one from the thread's reply count to compensate for the original post + --$thread_counters[$newtid]['deletedposts']; + } + + $arguments = array("pids" => $pids, "tid" => $tid, "moveto" => $moveto, "newsubject" => $newsubject, "destination_tid" => $destination_tid); + $plugins->run_hooks("class_moderation_split_posts", $arguments); + + // Update user post counts + if(!empty($user_counters)) + { + foreach($user_counters as $uid => $counters) + { + foreach($counters as $key => $counter) + { + if($counter >= 0) + { + $counters[$key] = "+{$counter}"; // add the addition operator for query + } + } + update_user_counters($uid, $counters); + } + } + + // Update thread counters + if(is_array($thread_counters)) + { + foreach($thread_counters as $tid => $counters) + { + if($tid == $newtid) + { + // Update the subject of the first post in the new thread + $query = $db->simple_select("posts", "pid", "tid='$newtid'", array('order_by' => 'dateline', 'limit' => 1)); + $newthread = $db->fetch_array($query); + $sqlarray = array( + "subject" => $newsubject, + "replyto" => 0 + ); + $db->update_query("posts", $sqlarray, "pid='{$newthread['pid']}'"); + } + else + { + // Update the subject of the first post in the old thread + $query = $db->query(" + SELECT p.pid, t.subject + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (p.tid=t.tid) + WHERE p.tid='{$tid}' + ORDER BY p.dateline ASC + LIMIT 1 + "); + $oldthread = $db->fetch_array($query); + $sqlarray = array( + "subject" => $db->escape_string($oldthread['subject']), + "replyto" => 0 + ); + $db->update_query("posts", $sqlarray, "pid='{$oldthread['pid']}'"); + } + + foreach($counters as $key => $counter) + { + if($counter >= 0) + { + $counters[$key] = "+{$counter}"; + } + } + update_thread_counters($tid, $counters); + update_last_post($tid); + } + } + + // Update forum counters + if(!empty($forum_counters)) + { + foreach($forum_counters as $fid => $counters) + { + foreach($counters as $key => $counter) + { + if($counter >= 0) + { + $counters[$key] = "+{$counter}"; + } + } + update_forum_counters($fid, $counters); + update_forum_lastpost($fid); + } + } + + return $newtid; + } + + /** + * Move multiple threads to new forum + * + * @param array Thread IDs + * @param int Destination forum + * @return boolean true + */ + function move_threads($tids, $moveto) + { + global $db, $plugins; + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + + $tid_list = implode(',', $tids); + + $moveto = (int)$moveto; + + $newforum = get_forum($moveto); + + if(empty($tids) || !$newforum) + { + return false; + } + + $total_posts = $total_unapproved_posts = $total_deleted_posts = $total_threads = $total_unapproved_threads = $total_deleted_threads = 0; + $forum_counters = $user_counters = array(); + $query = $db->simple_select("threads", "fid, visible, replies, unapprovedposts, deletedposts, tid, uid", "tid IN ($tid_list)"); + while($thread = $db->fetch_array($query)) + { + $forum = get_forum($thread['fid']); + + if(!isset($forum_counters[$thread['fid']])) + { + $forum_counters[$thread['fid']] = array( + 'posts' => 0, + 'threads' => 0, + 'unapprovedposts' => 0, + 'unapprovedthreads' => 0, + 'deletedthreads' => 0, + 'deletedposts' => 0 + ); + } + + if(!isset($user_counters[$thread['uid']]['num_threads'])) + { + $user_counters[$thread['uid']]['num_threads'] = 0; + } + + if($thread['visible'] == 1) + { + $total_posts += $thread['replies']+1; + $total_unapproved_posts += $thread['unapprovedposts']; + $total_deleted_posts += $thread['deletedposts']; + $forum_counters[$thread['fid']]['posts'] += $thread['replies']+1; + $forum_counters[$thread['fid']]['unapprovedposts'] += $thread['unapprovedposts']; + $forum_counters[$thread['fid']]['deletedposts'] += $thread['deletedposts']; + + $forum_counters[$thread['fid']]['threads']++; + ++$total_threads; + + if($newforum['usethreadcounts'] == 1 && $forum['usethreadcounts'] == 0) + { + ++$user_counters[$thread['uid']]['num_threads']; + } + else if($newforum['usethreadcounts'] == 0 && $forum['usethreadcounts'] == 1) + { + --$user_counters[$thread['uid']]['num_threads']; + } + + $query1 = $db->query(" + SELECT COUNT(p.pid) AS posts, u.uid + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) + WHERE p.tid = '{$thread['tid']}' AND p.visible=1 + GROUP BY u.uid + ORDER BY posts DESC + "); + while($posters = $db->fetch_array($query1)) + { + if(!isset($user_counters[$posters['uid']]['num_posts'])) + { + $user_counters[$posters['uid']]['num_posts'] = 0; + } + + if($newforum['usepostcounts'] != 0 && $forum['usepostcounts'] == 0) + { + $user_counters[$posters['uid']]['num_posts'] += $posters['posts']; + } + else if($newforum['usepostcounts'] == 0 && $forum['usepostcounts'] != 0) + { + $user_counters[$posters['uid']]['num_posts'] -= $posters['posts']; + } + } + } + elseif($thread['visible'] == -1) + { + $total_deleted_posts += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; + + $forum_counters[$thread['fid']]['deletedposts'] += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; // Implied deleted posts counter for deleted threads + + $forum_counters[$thread['fid']]['deletedthreads']++; + ++$total_deleted_threads; + } + else + { + $total_unapproved_posts += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; + + $forum_counters[$thread['fid']]['unapprovedposts'] += $thread['replies']+$thread['unapprovedposts']+$thread['deletedposts']+1; // Implied unapproved posts counter for unapproved threads + + $forum_counters[$thread['fid']]['unapprovedthreads']++; + ++$total_unapproved_threads; + } + + // Remove old redirects + $redirects_query = $db->simple_select('threads', 'tid', "closed='moved|{$thread['tid']}' AND fid='$moveto'"); + while($redirect_tid = $db->fetch_field($redirects_query, 'tid')) + { + $this->delete_thread($redirect_tid); + } + } + + $sqlarray = array( + "fid" => $moveto, + ); + $db->update_query("threads", $sqlarray, "tid IN ($tid_list)"); + $db->update_query("posts", $sqlarray, "tid IN ($tid_list)"); + + // If any of the thread has a prefix and the destination forum doesn't accept that prefix, remove the prefix + $query = $db->simple_select("threads", "tid, prefix", "tid IN ($tid_list) AND prefix != 0"); + while($thread = $db->fetch_array($query)) + { + switch($db->type) + { + case "pgsql": + case "sqlite": + $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(','||forums||',' LIKE '%,$moveto,%' OR forums='-1') AND pid='".$thread['prefix']."'"); + break; + default: + $query = $db->simple_select("threadprefixes", "COUNT(*) as num_prefixes", "(CONCAT(',',forums,',') LIKE '%,$moveto,%' OR forums='-1') AND pid='".$thread['prefix']."'"); + } + if($db->fetch_field($query, "num_prefixes") == 0) + { + $sqlarray = array( + "prefix" => 0, + ); + $db->update_query("threads", $sqlarray, "tid = '{$thread['tid']}'"); + } + } + + $arguments = array("tids" => $tids, "moveto" => $moveto); + $plugins->run_hooks("class_moderation_move_threads", $arguments); + + if(!empty($user_counters)) + { + foreach($user_counters as $uid => $counters) + { + $update_array = array( + "postnum" => "+{$counters['num_posts']}", + "threadnum" => "+{$counters['num_threads']}", + ); + update_user_counters($uid, $update_array); + } + } + + if(is_array($forum_counters)) + { + foreach($forum_counters as $fid => $counter) + { + $updated_count = array( + 'posts' => "-{$counter['posts']}", + 'threads' => "-{$counter['threads']}", + 'unapprovedposts' => "-{$counter['unapprovedposts']}", + 'unapprovedthreads' => "-{$counter['unapprovedthreads']}", + 'deletedposts' => "-{$counter['deletedposts']}", + 'deletedthreads' => "-{$counter['deletedthreads']}" + + ); + update_forum_counters($fid, $updated_count); + update_forum_lastpost($fid); + } + } + + $updated_count = array( + "threads" => "+{$total_threads}", + "unapprovedthreads" => "+{$total_unapproved_threads}", + "posts" => "+{$total_posts}", + "unapprovedposts" => "+{$total_unapproved_posts}", + 'deletedposts' => "+{$total_deleted_posts}", + "deletedthreads" => "+{$total_deleted_threads}" + ); + + update_forum_counters($moveto, $updated_count); + update_forum_lastpost($moveto); + + // Remove thread subscriptions for the users who no longer have permission to view the thread + $this->remove_thread_subscriptions($tid_list, false, $moveto); + + return true; + } + + /** + * Approve multiple posts + * + * @param array PIDs + * @return boolean true + */ + function approve_posts($pids) + { + global $db, $cache, $plugins; + + $num_posts = 0; + + if(empty($pids)) + { + return false; + } + + // Make sure we only have valid values + $pids = array_map('intval', $pids); + + $pid_list = implode(',', $pids); + $pids = $threads_to_update = array(); + + // Make visible + $approve = array( + "visible" => 1, + ); + + // We have three cases we deal with in these code segments: + // 1) We're approving specific unapproved posts + // 1.1) if the thread is approved + // 1.2) if the thread is unapproved + // 2) We're approving the firstpost of the thread, therefore approving the thread itself + // 3) We're doing both 1 and 2 + $query = $db->query(" + SELECT p.tid + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + WHERE p.pid IN ($pid_list) AND p.visible = '0' AND t.firstpost = p.pid AND t.visible = 0 + "); + while($post = $db->fetch_array($query)) + { + // This is the first post in the thread so we're approving the whole thread. + $threads_to_update[] = $post['tid']; + } + + if(!empty($threads_to_update)) + { + $this->approve_threads($threads_to_update); + } + + $thread_counters = $forum_counters = $user_counters = array(); + + $query = $db->query(" + SELECT p.pid, p.tid, p.fid, p.uid, t.visible AS threadvisible + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + WHERE p.pid IN ($pid_list) AND p.visible = '0' AND t.firstpost != p.pid + "); + while($post = $db->fetch_array($query)) + { + $pids[] = $post['pid']; + + if(!isset($thread_counters[$post['tid']])) + { + $thread_counters[$post['tid']] = array( + 'replies' => 0 + ); + } + + ++$thread_counters[$post['tid']]['replies']; + + // If the thread of this post is unapproved then we've already taken into account this counter as implied. + // Updating it again would cause it to double count + if($post['threadvisible'] == 1) + { + if(!isset($forum_counters[$post['fid']])) + { + $forum_counters[$post['fid']] = array( + 'num_posts' => 0 + ); + } + ++$forum_counters[$post['fid']]['num_posts']; + } + + $forum = get_forum($post['fid']); + + // If post counts enabled in this forum and the thread is approved, add 1 + if($forum['usepostcounts'] != 0 && $post['threadvisible'] == 1) + { + if(!isset($user_counters[$post['uid']])) + { + $user_counters[$post['uid']] = 0; + } + ++$user_counters[$post['uid']]; + } + } + + if(empty($pids) && empty($threads_to_update)) + { + return false; + } + + if(!empty($pids)) + { + $where = "pid IN (".implode(',', $pids).")"; + $db->update_query("posts", $approve, $where); + } + + $plugins->run_hooks("class_moderation_approve_posts", $pids); + + if(!empty($thread_counters)) + { + foreach($thread_counters as $tid => $counters) + { + $counters_update = array( + "unapprovedposts" => "-".$counters['replies'], + "replies" => "+".$counters['replies'] + ); + update_thread_counters($tid, $counters_update); + update_last_post($tid); + } + } + + if(!empty($forum_counters)) + { + foreach($forum_counters as $fid => $counters) + { + $updated_forum_stats = array( + 'posts' => "+{$counters['num_posts']}", + 'unapprovedposts' => "-{$counters['num_posts']}", + ); + update_forum_counters($fid, $updated_forum_stats); + update_forum_lastpost($fid); + } + } + + if(!empty($user_counters)) + { + foreach($user_counters as $uid => $counter) + { + update_user_counters($uid, array('postnum' => "+{$counter}")); + } + } + + return true; + } + + /** + * Unapprove multiple posts + * + * @param array PIDs + * @return boolean true + */ + function unapprove_posts($pids) + { + global $db, $cache, $plugins; + + if(empty($pids)) + { + return false; + } + + // Make sure we only have valid values + $pids = array_map('intval', $pids); + + $pid_list = implode(',', $pids); + $pids = $threads_to_update = array(); + + // Make invisible + $approve = array( + "visible" => 0, + ); + + // We have three cases we deal with in these code segments: + // 1) We're unapproving specific approved posts + // 1.1) if the thread is approved + // 1.2) if the thread is unapproved + // 1.3) if the thread is deleted + // 2) We're unapproving the firstpost of the thread, therefore unapproving the thread itself + // 3) We're doing both 1 and 2 + $query = $db->query(" + SELECT p.tid + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + WHERE p.pid IN ($pid_list) AND p.visible IN (-1,1) AND t.firstpost = p.pid AND t.visible IN (-1,1) + "); + while($post = $db->fetch_array($query)) + { + // This is the first post in the thread so we're unapproving the whole thread. + $threads_to_update[] = $post['tid']; + } + + if(!empty($threads_to_update)) + { + $this->unapprove_threads($threads_to_update); + } + + $thread_counters = $forum_counters = $user_counters = array(); + + $query = $db->query(" + SELECT p.pid, p.tid, p.visible, p.fid, p.uid, t.visible AS threadvisible + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + WHERE p.pid IN ($pid_list) AND p.visible IN (-1,1) AND t.firstpost != p.pid + "); + while($post = $db->fetch_array($query)) + { + $pids[] = $post['pid']; + + if(!isset($thread_counters[$post['tid']])) + { + $thread_counters[$post['tid']] = array( + 'replies' => 0, + 'unapprovedposts' => 0, + 'deletedposts' => 0 + ); + } + + ++$thread_counters[$post['tid']]['unapprovedposts']; + if($post['visible'] == 1) + { + ++$thread_counters[$post['tid']]['replies']; + } + else + { + ++$thread_counters[$post['tid']]['deletedposts']; + } + + if(!isset($forum_counters[$post['fid']])) + { + $forum_counters[$post['fid']] = array( + 'num_posts' => 0, + 'num_unapproved_posts' => 0, + 'num_deleted_posts' => 0 + ); + } + + // If the thread of this post is unapproved then we've already taken into account this counter as implied. + // Updating it again would cause it to double count + if($post['threadvisible'] != 0) + { + ++$forum_counters[$post['fid']]['num_unapproved_posts']; + if($post['visible'] == 1) + { + ++$forum_counters[$post['fid']]['num_posts']; + } + else + { + ++$forum_counters[$post['fid']]['num_deleted_posts']; + } + } + + $forum = get_forum($post['fid']); + + // If post counts enabled in this forum and the thread is approved, subtract 1 + if($forum['usepostcounts'] != 0 && $post['visible'] == 1 && $post['threadvisible'] == 1) + { + if(!isset($user_counters[$post['uid']])) + { + $user_counters[$post['uid']] = 0; + } + --$user_counters[$post['uid']]; + } + } + + if(empty($pids) && empty($threads_to_update)) + { + return false; + } + + if(!empty($pids)) + { + $where = "pid IN (".implode(',', $pids).")"; + $db->update_query("posts", $approve, $where); + } + + $plugins->run_hooks("class_moderation_unapprove_posts", $pids); + + if(!empty($thread_counters)) + { + foreach($thread_counters as $tid => $counters) + { + $counters_update = array( + "unapprovedposts" => "+".$counters['unapprovedposts'], + "replies" => "-".$counters['replies'], + "deletedposts" => "-".$counters['deletedposts'] + ); + + update_thread_counters($tid, $counters_update); + update_last_post($tid); + } + } + + if(!empty($forum_counters)) + { + foreach($forum_counters as $fid => $counters) + { + $updated_forum_stats = array( + 'posts' => "-{$counters['num_posts']}", + 'unapprovedposts' => "+{$counters['num_unapproved_posts']}", + 'deletedposts' => "-{$counters['num_deleted_posts']}" + ); + update_forum_counters($fid, $updated_forum_stats); + update_forum_lastpost($fid); + } + } + + if(!empty($user_counters)) + { + foreach($user_counters as $uid => $counter) + { + update_user_counters($uid, array('postnum' => "{$counter}")); + } + } + + return true; + } + + /** + * Change thread subject + * + * @param mixed Thread ID(s) + * @param string Format of new subject (with {subject}) + * @return boolean true + */ + function change_thread_subject($tids, $format) + { + global $db, $mybb, $plugins; + + // Get tids into list + if(!is_array($tids)) + { + $tids = array($tids); + } + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + + if(empty($tids)) + { + return false; + } + + $tid_list = implode(',', $tids); + + // Get original subject + $query = $db->simple_select("threads", "subject, tid", "tid IN ($tid_list)"); + while($thread = $db->fetch_array($query)) + { + // Update threads and first posts with new subject + $subject = str_replace('{username}', $mybb->user['username'], $format); + $subject = str_replace('{subject}', $thread['subject'], $subject); + $new_subject = array( + "subject" => $db->escape_string($subject) + ); + $db->update_query("threads", $new_subject, "tid='{$thread['tid']}'"); + $db->update_query("posts", $new_subject, "tid='{$thread['tid']}' AND replyto='0'"); + } + + $arguments = array("tids" => $tids, "format" => $format); + $plugins->run_hooks("class_moderation_change_thread_subject", $arguments); + + return true; + } + + /** + * Add thread expiry + * + * @param int Thread ID + * @param int Timestamp when the thread is deleted + * @return boolean true + */ + function expire_thread($tid, $deletetime) + { + global $db, $plugins; + + $tid = (int)$tid; + + if(empty($tid)) + { + return false; + } + + $update_thread = array( + "deletetime" => (int)$deletetime + ); + $db->update_query("threads", $update_thread, "tid='{$tid}'"); + + $arguments = array("tid" => $tid, "deletetime" => $deletetime); + $plugins->run_hooks("class_moderation_expire_thread", $arguments); + + return true; + } + + /** + * Toggle post visibility (approved/unapproved) + * + * @param array Post IDs + * @return boolean true + */ + function toggle_post_visibility($pids) + { + global $db; + + // Make sure we only have valid values + $pids = array_map('intval', $pids); + + $pid_list = implode(',', $pids); + $query = $db->simple_select("posts", 'pid, visible', "pid IN ($pid_list)"); + while($post = $db->fetch_array($query)) + { + if($post['visible'] != 0) + { + $unapprove[] = $post['pid']; + } + else + { + $approve[] = $post['pid']; + } + } + if(is_array($unapprove)) + { + $this->unapprove_posts($unapprove); + } + if(is_array($approve)) + { + $this->approve_posts($approve); + } + return true; + } + + /** + * Toggle post visibility (deleted/restored) + * + * @param array Post IDs + * @return boolean true + */ + function toggle_post_softdelete($pids) + { + global $db; + + // Make sure we only have valid values + $pids = array_map('intval', $pids); + + $pid_list = implode(',', $pids); + $query = $db->simple_select("posts", 'pid, visible', "pid IN ($pid_list)"); + while($post = $db->fetch_array($query)) + { + if($post['visible'] != -1) + { + $delete[] = $post['pid']; + } + else + { + $restore[] = $post['pid']; + } + } + if(is_array($delete)) + { + $this->soft_delete_posts($delete); + } + if(is_array($restore)) + { + $this->restore_posts($restore); + } + return true; + } + + /** + * Toggle thread visibility (approved/unapproved) + * + * @param array Thread IDs + * @param int Forum ID + * @return boolean true + */ + function toggle_thread_visibility($tids, $fid) + { + global $db; + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + $fid = (int)$fid; + + $tid_list = implode(',', $tids); + $query = $db->simple_select("threads", 'tid, visible', "tid IN ($tid_list)"); + while($thread = $db->fetch_array($query)) + { + if($thread['visible'] != 0) + { + $unapprove[] = $thread['tid']; + } + else + { + $approve[] = $thread['tid']; + } + } + if(is_array($unapprove)) + { + $this->unapprove_threads($unapprove, $fid); + } + if(is_array($approve)) + { + $this->approve_threads($approve, $fid); + } + return true; + } + + /** + * Toggle thread visibility (deleted/restored) + * + * @param array Thread IDs + * @param int Forum ID + * @return boolean true + */ + function toggle_thread_softdelete($tids, $fid) + { + global $db; + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + $fid = (int)$fid; + + $tid_list = implode(',', $tids); + $query = $db->simple_select("threads", 'tid, visible', "tid IN ($tid_list)"); + while($thread = $db->fetch_array($query)) + { + if($thread['visible'] != -1) + { + $delete[] = $thread['tid']; + } + else + { + $restore[] = $thread['tid']; + } + } + if(is_array($delete)) + { + $this->soft_delete_threads($delete, $fid); + } + if(is_array($restore)) + { + $this->restore_threads($restore, $fid); + } + return true; + } + + /** + * Toggle threads open/closed + * + * @param array Thread IDs + * @return boolean true + */ + function toggle_thread_status($tids) + { + global $db; + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + + $tid_list = implode(',', $tids); + $query = $db->simple_select("threads", 'tid, closed', "tid IN ($tid_list)"); + while($thread = $db->fetch_array($query)) + { + if($thread['closed'] == 1) + { + $open[] = $thread['tid']; + } + elseif($thread['closed'] == 0) + { + $close[] = $thread['tid']; + } + } + if(is_array($open)) + { + $this->open_threads($open); + } + if(is_array($close)) + { + $this->close_threads($close); + } + return true; + } + + /** + * Toggle threads stick/unstick + * + * @param array Thread IDs + * @return boolean true + */ + function toggle_thread_importance($tids) + { + global $db; + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + + $stick = array(); + $unstick = array(); + + $tid_list = implode(',', $tids); + $query = $db->simple_select("threads", 'tid, sticky', "tid IN ($tid_list)"); + while($thread = $db->fetch_array($query)) + { + if($thread['sticky'] == 0) + { + $stick[] = $thread['tid']; + } + elseif($thread['sticky'] == 1) + { + $unstick[] = $thread['tid']; + } + } + if(!empty($stick)) + { + $this->stick_threads($stick); + } + if(!empty($unstick)) + { + $this->unstick_threads($unstick); + } + return true; + } + + /** + * Remove thread subscriptions (from one or multiple threads in the same forum) + * + * @param int $tids Thread ID, or an array of thread IDs from the same forum. + * @param boolean $all True (default) to delete all subscriptions, false to only delete subscriptions from users with no permission to read the thread + * @param int $fid (Only applies if $all is false) The forum ID of the thread + * @return boolean true + */ + function remove_thread_subscriptions($tids, $all = true, $fid = 0) + { + global $db, $plugins; + + // Format thread IDs + if(!is_array($tids)) + { + $tids = array($tids); + } + + if(empty($tids)) + { + return false; + } + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + $fid = (int)$fid; + + $tids_csv = implode(',', $tids); + + // Delete only subscriptions from users who no longer have permission to read the thread. + if(!$all) + { + // Get groups that cannot view the forum or its threads + $forum_parentlist = get_parent_list($fid); + $query = $db->simple_select("forumpermissions", "gid", "fid IN ({$forum_parentlist}) AND (canview=0 OR canviewthreads=0)"); + $groups = array(); + while($group = $db->fetch_array($query)) + { + $groups[] = $group['gid']; + switch($db->type) + { + case "pgsql": + case "sqlite": + $additional_groups .= " OR ','||u.additionalgroups||',' LIKE ',{$group['gid']},'"; + break; + default: + $additional_groups .= " OR CONCAT(',',u.additionalgroups,',') LIKE ',{$group['gid']},'"; + } + } + // If there are groups found, delete subscriptions from users in these groups + if(count($groups) > 0) + { + $groups_csv = implode(',', $groups); + $query = $db->query(" + SELECT s.tid, u.uid + FROM ".TABLE_PREFIX."threadsubscriptions s + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=s.uid) + WHERE s.tid IN ({$tids_csv}) + AND (u.usergroup IN ({$groups_csv}){$additional_groups}) + "); + while($subscription = $db->fetch_array($query)) + { + $db->delete_query("threadsubscriptions", "uid='{$subscription['uid']}' AND tid='{$subscription['tid']}'"); + } + } + } + // Delete all subscriptions of this thread + else + { + $db->delete_query("threadsubscriptions", "tid IN ({$tids_csv})"); + } + + $arguments = array("tids" => $tids, "all" => $all, "fid" => $fid); + $plugins->run_hooks("class_moderation_remove_thread_subscriptions", $arguments); + + return true; + } + + /** + * Apply a thread prefix (to one or multiple threads in the same forum) + * + * @param int $tids Thread ID, or an array of thread IDs from the same forum. + * @param int $prefix Prefix ID to apply to the threads + */ + function apply_thread_prefix($tids, $prefix = 0) + { + global $db, $plugins; + + // Format thread IDs + if(!is_array($tids)) + { + $tids = array($tids); + } + + if(empty($tids)) + { + return false; + } + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + $tids_csv = implode(',', $tids); + + $update_thread = array('prefix' => (int)$prefix); + $db->update_query('threads', $update_thread, "tid IN ({$tids_csv})"); + + $arguments = array('tids' => $tids, 'prefix' => $prefix); + + $plugins->run_hooks('class_moderation_apply_thread_prefix', $arguments); + + return true; + } + + /** + * Soft delete multiple posts + * + * @param array PIDs + * @return boolean true + */ + function soft_delete_posts($pids) + { + global $db, $cache, $plugins; + + if(empty($pids)) + { + return false; + } + + // Make sure we only have valid values + $pids = array_map('intval', $pids); + + $pid_list = implode(',', $pids); + $pids = $threads_to_update = array(); + + // Make invisible + $update = array( + "visible" => -1, + ); + + // We have three cases we deal with in these code segments: + // 1) We're deleting specific approved posts + // 1.1) if the thread is approved + // 1.2) if the thread is unapproved + // 1.3) if the thread is deleted + // 2) We're deleting the firstpost of the thread, therefore deleting the thread itself + // 3) We're doing both 1 and 2 + $query = $db->query(" + SELECT p.tid + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + WHERE p.pid IN ($pid_list) AND p.visible IN (0,1) AND t.firstpost = p.pid AND t.visible IN (0,1) + "); + while($post = $db->fetch_array($query)) + { + // This is the first post in the thread so we're deleting the whole thread. + $threads_to_update[] = $post['tid']; + } + + if(!empty($threads_to_update)) + { + $this->soft_delete_threads($threads_to_update); + } + + $thread_counters = $forum_counters = $user_counters = array(); + + $query = $db->query(" + SELECT p.pid, p.tid, p.visible, f.fid, f.usepostcounts, p.uid, t.visible AS threadvisible + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid) + WHERE p.pid IN ($pid_list) AND p.visible IN (0,1) AND t.firstpost != p.pid + "); + while($post = $db->fetch_array($query)) + { + $pids[] = $post['pid']; + + if(!isset($thread_counters[$post['tid']])) + { + $thread_counters[$post['tid']] = array( + 'replies' => 0, + 'unapprovedposts' => 0, + 'deletedposts' => 0 + ); + } + + ++$thread_counters[$post['tid']]['deletedposts']; + if($post['visible'] == 1) + { + ++$thread_counters[$post['tid']]['replies']; + } + else + { + ++$thread_counters[$post['tid']]['unapprovedposts']; + } + + if(!isset($forum_counters[$post['fid']])) + { + $forum_counters[$post['fid']] = array( + 'num_posts' => 0, + 'num_unapproved_posts' => 0, + 'num_deleted_posts' => 0 + ); + } + + // If the thread of this post is deleted then we've already taken into account this counter as implied. + // Updating it again would cause it to double count + if($post['threadvisible'] == 1) + { + ++$forum_counters[$post['fid']]['num_deleted_posts']; + if($post['visible'] == 1) + { + ++$forum_counters[$post['fid']]['num_posts']; + } + else + { + ++$forum_counters[$post['fid']]['num_unapproved_posts']; + } + } + + // If post counts enabled in this forum and the thread is approved, subtract 1 + if($post['usepostcounts'] != 0 && $post['threadvisible'] == 1 && $post['visible'] == 1) + { + if(!isset($user_counters[$post['uid']])) + { + $user_counters[$post['uid']] = 0; + } + --$user_counters[$post['uid']]; + } + } + + if(empty($pids) && empty($threads_to_update)) + { + return false; + } + + if(!empty($pids)) + { + $where = "pid IN (".implode(',', $pids).")"; + $db->update_query("posts", $update, $where); + } + + $plugins->run_hooks("class_moderation_soft_delete_posts", $pids); + + if(is_array($thread_counters)) + { + foreach($thread_counters as $tid => $counters) + { + $counters_update = array( + "unapprovedposts" => "-".$counters['unapprovedposts'], + "replies" => "-".$counters['replies'], + "deletedposts" => "+".$counters['deletedposts'] + ); + + update_thread_counters($tid, $counters_update); + update_last_post($tid); + } + } + + if(is_array($forum_counters)) + { + foreach($forum_counters as $fid => $counters) + { + $updated_forum_stats = array( + 'posts' => "-{$counters['num_posts']}", + 'unapprovedposts' => "-{$counters['num_unapproved_posts']}", + 'deletedposts' => "+{$counters['num_deleted_posts']}" + ); + update_forum_counters($fid, $updated_forum_stats); + update_forum_lastpost($fid); + } + } + + if(!empty($user_counters)) + { + foreach($user_counters as $uid => $counter) + { + update_user_counters($uid, array('postnum' => "{$counter}")); + } + } + + return true; + } + + /** + * Restore multiple posts + * + * @param array PIDs + * @return boolean true + */ + function restore_posts($pids) + { + global $db, $cache, $plugins; + + $num_posts = 0; + + if(empty($pids)) + { + return false; + } + + // Make sure we only have valid values + $pids = array_map('intval', $pids); + + $pid_list = implode(',', $pids); + $pids = $threads_to_update = array(); + + // Make visible + $update = array( + "visible" => 1, + ); + + // We have three cases we deal with in these code segments: + // 1) We're approving specific restored posts + // 1.1) if the thread is deleted + // 1.2) if the thread is restored + // 2) We're restoring the firstpost of the thread, therefore restoring the thread itself + // 3) We're doing both 1 and 2 + $query = $db->query(" + SELECT p.tid + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + WHERE p.pid IN ($pid_list) AND p.visible = '-1' AND t.firstpost = p.pid AND t.visible = -1 + "); + while($post = $db->fetch_array($query)) + { + // This is the first post in the thread so we're approving the whole thread. + $threads_to_update[] = $post['tid']; + } + + if(!empty($threads_to_update)) + { + $this->restore_threads($threads_to_update); + } + + $thread_counters = $forum_counters = $user_counters = array(); + + $query = $db->query(" + SELECT p.pid, p.tid, f.fid, f.usepostcounts, p.uid, t.visible AS threadvisible + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + LEFT JOIN ".TABLE_PREFIX."forums f ON (f.fid=p.fid) + WHERE p.pid IN ($pid_list) AND p.visible = '-1' AND t.firstpost != p.pid + "); + while($post = $db->fetch_array($query)) + { + $pids[] = $post['pid']; + + if(!isset($thread_counters[$post['tid']])) + { + $thread_counters[$post['tid']] = array( + 'replies' => 0 + ); + } + + ++$thread_counters[$post['tid']]['replies']; + + // If the thread of this post is deleted then we've already taken into account this counter as implied. + // Updating it again would cause it to double count + if($post['threadvisible'] == 1) + { + if(!isset($forum_counters[$post['fid']])) + { + $forum_counters[$post['fid']] = array( + 'num_posts' => 0 + ); + } + ++$forum_counters[$post['fid']]['num_posts']; + } + + // If post counts enabled in this forum and the thread is approved, add 1 + if($post['usepostcounts'] != 0 && $post['threadvisible'] == 1) + { + if(!isset($user_counters[$post['uid']])) + { + $user_counters[$post['uid']] = 0; + } + ++$user_counters[$post['uid']]; + + } + } + + if(empty($pids) && empty($threads_to_update)) + { + return false; + } + + if(!empty($pids)) + { + $where = "pid IN (".implode(',', $pids).")"; + $db->update_query("posts", $update, $where); + } + + $plugins->run_hooks("class_moderation_restore_posts", $pids); + + if(is_array($thread_counters)) + { + foreach($thread_counters as $tid => $counters) + { + $counters_update = array( + "deletedposts" => "-".$counters['replies'], + "replies" => "+".$counters['replies'] + ); + update_thread_counters($tid, $counters_update); + update_last_post($tid); + } + } + + if(is_array($forum_counters)) + { + foreach($forum_counters as $fid => $counters) + { + $updated_forum_stats = array( + 'posts' => "+{$counters['num_posts']}", + 'deletedposts' => "-{$counters['num_posts']}" + ); + update_forum_counters($fid, $updated_forum_stats); + update_forum_lastpost($fid); + } + } + + if(!empty($user_counters)) + { + foreach($user_counters as $uid => $counter) + { + update_user_counters($uid, array('postnum' => "+{$counter}")); + } + } + + return true; + } + + /** + * Restore one or more threads + * + * @param array Thread IDs + * @return boolean true + */ + function restore_threads($tids) + { + global $db, $cache, $plugins; + + if(!is_array($tids)) + { + $tids = array($tids); + } + + if(empty($tids)) + { + return false; + } + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + + $tid_list = $forum_counters = $user_counters = $posts_to_restore = array(); + + foreach($tids as $tid) + { + $thread = get_thread($tid); + if(!$thread || $thread['visible'] != -1) + { + continue; + } + $tid_list[] = $thread['tid']; + + $forum = get_forum($thread['fid']); + + if(!isset($forum_counters[$forum['fid']])) + { + $forum_counters[$forum['fid']] = array( + 'num_posts' => 0, + 'num_threads' => 0, + 'num_deleted_posts' => 0, + 'num_unapproved_posts' => 0 + ); + } + + if(!isset($user_counters[$thread['uid']])) + { + $user_counters[$thread['uid']] = array( + 'num_posts' => 0, + 'num_threads' => 0 + ); + } + + ++$forum_counters[$forum['fid']]['num_threads']; + $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Remove implied visible from count + $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['replies']+$thread['unapprovedposts']+1; + $forum_counters[$forum['fid']]['num_unapproved_posts'] += $thread['unapprovedposts']; + + if($forum['usepostcounts'] != 0) + { + // On approving thread restore user post counts + $query = $db->simple_select("posts", "COUNT(pid) as posts, uid", "tid='{$tid}' AND (visible='1' OR pid='{$thread['firstpost']}') AND uid > 0 GROUP BY uid"); + while($counter = $db->fetch_array($query)) + { + if(!isset($user_counters[$counter['uid']]['num_posts'])) + { + $user_counters[$counter['uid']]['num_posts'] = 0; + } + $user_counters[$counter['uid']]['num_posts'] += $counter['posts']; + } + } + + if($forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|') + { + ++$user_counters[$thread['uid']]['num_threads']; + } + + $posts_to_restore[] = $thread['firstpost']; + } + + if(!empty($tid_list)) + { + $tid_moved_list = ""; + $comma = ""; + foreach($tid_list as $tid) + { + $tid_moved_list .= "{$comma}'moved|{$tid}'"; + $comma = ","; + } + $tid_list = implode(',', $tid_list); + $update = array( + "visible" => 1 + ); + $db->update_query("threads", $update, "tid IN ($tid_list)"); + // Restore redirects, too + $redirect_tids = array(); + $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})"); + while($redirect_tid = $db->fetch_field($query, 'tid')) + { + $redirect_tids[] = $redirect_tid; + } + if(!empty($redirect_tids)) + { + $this->restore_threads($redirect_tids); + } + if(!empty($posts_to_restore)) + { + $db->update_query("posts", $update, "pid IN (".implode(',', $posts_to_restore).")"); + } + + $plugins->run_hooks("class_moderation_restore_threads", $tids); + + if(is_array($forum_counters)) + { + foreach($forum_counters as $fid => $counters) + { + // Update stats + $update_array = array( + "threads" => "+{$counters['num_threads']}", + "posts" => "+{$counters['num_posts']}", + "unapprovedposts" => "+{$counters['num_unapproved_posts']}", + "deletedposts" => "-{$counters['num_deleted_posts']}", + "deletedthreads" => "-{$counters['num_threads']}" + ); + update_forum_counters($fid, $update_array); + update_forum_lastpost($fid); + } + } + + if(!empty($user_counters)) + { + foreach($user_counters as $uid => $counters) + { + $update_array = array( + "postnum" => "+{$counters['num_posts']}", + "threadnum" => "+{$counters['num_threads']}", + ); + update_user_counters($uid, $update_array); + } + } + } + return true; + } + + /** + * Soft delete one or more threads + * + * @param array Thread IDs + * @return boolean true + */ + function soft_delete_threads($tids) + { + global $db, $cache, $plugins; + + if(!is_array($tids)) + { + $tids = array($tids); + } + + if(empty($tids)) + { + return false; + } + + // Make sure we only have valid values + $tids = array_map('intval', $tids); + + $tid_list = implode(',', $tids); + $tid_moved_list = ""; + $comma = ""; + foreach($tids as $tid) + { + $tid_moved_list .= "{$comma}'moved|{$tid}'"; + $comma = ","; + } + + $forum_counters = $user_counters = $posts_to_delete = array(); + + foreach($tids as $tid) + { + $thread = get_thread($tid); + $forum = get_forum($thread['fid']); + + if($thread['visible'] == 1 || $thread['visible'] == 0) + { + if(!isset($forum_counters[$forum['fid']])) + { + $forum_counters[$forum['fid']] = array( + 'num_posts' => 0, + 'num_threads' => 0, + 'num_deleted_threads' => 0, + 'num_deleted_posts' => 0, + 'unapproved_threads' => 0, + 'unapproved_posts' => 0 + ); + } + + if(!isset($user_counters[$thread['uid']])) + { + $user_counters[$thread['uid']] = array( + 'num_posts' => 0, + 'num_threads' => 0 + ); + } + + ++$forum_counters[$forum['fid']]['num_deleted_threads']; + $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['replies']+$thread['unapprovedposts']+1; + + if($thread['visible'] == 1) + { + ++$forum_counters[$forum['fid']]['num_threads']; + $forum_counters[$forum['fid']]['num_posts'] += $thread['replies']+1; // Add implied invisible to count + $forum_counters[$forum['fid']]['unapproved_posts'] += $thread['unapprovedposts']; + } + else + { + ++$forum_counters[$forum['fid']]['unapproved_threads']; + $forum_counters[$forum['fid']]['unapproved_posts'] += $thread['replies']+$thread['deletedposts']+$thread['unapprovedposts']+1; // Add implied invisible to count + $forum_counters[$forum['fid']]['num_deleted_posts'] += $thread['deletedposts']; + } + + // On unapproving thread update user post counts + if($thread['visible'] == 1 && $forum['usepostcounts'] != 0) + { + $query = $db->simple_select("posts", "COUNT(pid) AS posts, uid", "tid='{$tid}' AND (visible='1' OR pid='{$thread['firstpost']}') AND uid > 0 GROUP BY uid"); + while($counter = $db->fetch_array($query)) + { + if(!isset($user_counters[$counter['uid']]['num_posts'])) + { + $user_counters[$counter['uid']]['num_posts'] = 0; + } + $user_counters[$counter['uid']]['num_posts'] += $counter['posts']; + } + } + + if($thread['visible'] == 1 && $forum['usethreadcounts'] != 0 && substr($thread['closed'], 0, 6) != 'moved|') + { + ++$user_counters[$thread['uid']]['num_threads']; + } + } + $posts_to_delete[] = $thread['firstpost']; + } + + $update = array( + "visible" => -1 + ); + $db->update_query("threads", $update, "tid IN ($tid_list)"); + // Soft delete redirects, too + $redirect_tids = array(); + $query = $db->simple_select('threads', 'tid', "closed IN ({$tid_moved_list})"); + while($redirect_tid = $db->fetch_field($query, 'tid')) + { + $redirect_tids[] = $redirect_tid; + } + if(!empty($redirect_tids)) + { + $this->soft_delete_threads($redirect_tids); + } + if(!empty($posts_to_delete)) + { + $db->update_query("posts", $update, "pid IN (".implode(',', $posts_to_delete).")"); + } + + $plugins->run_hooks("class_moderation_soft_delete_threads", $tids); + + if(is_array($forum_counters)) + { + foreach($forum_counters as $fid => $counters) + { + // Update stats + $update_array = array( + "threads" => "-{$counters['num_threads']}", + "unapprovedthreads" => "-{$counters['unapproved_threads']}", + "posts" => "-{$counters['num_posts']}", + "unapprovedposts" => "-{$counters['unapproved_posts']}", + "deletedposts" => "+{$counters['num_deleted_posts']}", + "deletedthreads" => "+{$counters['num_deleted_threads']}" + ); + update_forum_counters($fid, $update_array); + update_forum_lastpost($fid); + } + } + + if(!empty($user_counters)) + { + foreach($user_counters as $uid => $counters) + { + $update_array = array( + "postnum" => "-{$counters['num_posts']}", + "threadnum" => "-{$counters['num_threads']}", + ); + update_user_counters($uid, $update_array); + } + } + + return true; + } +} diff --git a/Upload/inc/class_parser.php b/Upload/inc/class_parser.php new file mode 100644 index 0000000..c75394f --- /dev/null +++ b/Upload/inc/class_parser.php @@ -0,0 +1,1671 @@ +base_url = $mybb->settings['bburl']; + + if($this->base_url != "") + { + if(my_substr($this->base_url, my_strlen($this->base_url) -1) != "/") + { + $this->base_url = $this->base_url."/"; + } + } + + // Set the options + $this->options = $options; + + $message = $plugins->run_hooks("parse_message_start", $message); + + // Get rid of cartridge returns for they are the workings of the devil + $message = str_replace("\r", "", $message); + + // Filter bad words if requested. + if(!empty($this->options['filter_badwords'])) + { + $message = $this->parse_badwords($message); + } + + // Filter CDATA tags if requested (syndication.php). + if(!empty($this->options['filter_cdata'])) + { + $message = $this->parse_cdata($message); + } + + if(empty($this->options['allow_html'])) + { + $message = $this->parse_html($message); + } + else + { + while(preg_match("#(.*)#is", $message)) + { + $message = preg_replace("#(.*)#is", "<s$1$2>$3</s$4$5>", $message); + } + + $find = array('', '?>', "
    \n", "
    \n"); + $replace = array('<?php', '<!--', '-->', '?>', "\n", "\n"); + $message = str_replace($find, $replace, $message); + } + + // If MyCode needs to be replaced, first filter out [code] and [php] tags. + if(!empty($this->options['allow_mycode']) && $mybb->settings['allowcodemycode'] == 1) + { + preg_match_all("#\[(code|php)\](.*?)\[/\\1\](\r\n?|\n?)#si", $message, $code_matches, PREG_SET_ORDER); + $message = preg_replace("#\[(code|php)\](.*?)\[/\\1\](\r\n?|\n?)#si", "\n", $message); + } + + // Always fix bad Javascript in the message. + $message = $this->fix_javascript($message); + + // Replace "me" code and slaps if we have a username + if(!empty($this->options['me_username']) && $mybb->settings['allowmemycode'] == 1) + { + global $lang; + + $message = preg_replace('#(>|^|\r|\n)/me ([^\r\n<]*)#i', "\\1* {$this->options['me_username']} \\2", $message); + $message = preg_replace('#(>|^|\r|\n)/slap ([^\r\n<]*)#i', "\\1* {$this->options['me_username']} {$lang->slaps} \\2 {$lang->with_trout}", $message); + } + + // If we can, parse smilies + if(!empty($this->options['allow_smilies'])) + { + $message = $this->parse_smilies($message, $this->options['allow_html']); + } + + // Replace MyCode if requested. + if(!empty($this->options['allow_mycode'])) + { + $message = $this->parse_mycode($message); + } + + // Parse Highlights + if(!empty($this->options['highlight'])) + { + $message = $this->highlight_message($message, $this->options['highlight']); + } + + // Run plugin hooks + $message = $plugins->run_hooks("parse_message", $message); + + if(!empty($this->options['allow_mycode'])) + { + // Now that we're done, if we split up any code tags, parse them and glue it all back together + if(count($code_matches) > 0) + { + foreach($code_matches as $text) + { + // Fix up HTML inside the code tags so it is clean + if(!empty($this->options['allow_html'])) + { + $text[2] = $this->parse_html($text[2]); + } + + if(my_strtolower($text[1]) == "code") + { + $code = $this->mycode_parse_code($text[2]); + } + elseif(my_strtolower($text[1]) == "php") + { + $code = $this->mycode_parse_php($text[2]); + } + $message = preg_replace("#\\n?#", $code, $message, 1); + } + } + } + + // Replace meta and base tags in our post - these are > dangerous < + if(!empty($this->options['allow_html'])) + { + $message = preg_replace_callback("#<((m[^a])|(b[^diloru>])|(s[^aemptu>]))(\s*[^>]*)>#si", create_function( + '$matches', + 'return htmlspecialchars_uni($matches[0]);' + ), $message); + } + + if(!isset($this->options['nl2br']) || $this->options['nl2br'] != 0) + { + $message = nl2br($message); + // Fix up new lines and block level elements + $message = preg_replace("#(]*>)\s*
    #i", "$1", $message); + $message = preg_replace("#( )+(]*>)#i", "$2", $message); + } + + $message = my_wordwrap($message); + + $message = $plugins->run_hooks("parse_message_end", $message); + + return $message; + } + + /** + * Converts HTML in a message to their specific entities whilst allowing unicode characters. + * + * @param string The message to be parsed. + * @return string The formatted message. + */ + function parse_html($message) + { + $message = preg_replace("#&(?!\#[0-9]+;)#si", "&", $message); // fix & but allow unicode + $message = str_replace("<","<",$message); + $message = str_replace(">",">",$message); + return $message; + } + + /** + * Generates a cache of MyCode, both standard and custom. + * + * @access private + */ + function cache_mycode() + { + global $cache, $lang, $mybb; + $this->mycode_cache = array(); + + $standard_mycode = $callback_mycode = $nestable_mycode = array(); + $standard_count = $callback_count = $nestable_count = 0; + + if($mybb->settings['allowbasicmycode'] == 1) + { + $standard_mycode['b']['regex'] = "#\[b\](.*?)\[/b\]#si"; + $standard_mycode['b']['replacement'] = "$1"; + + $standard_mycode['u']['regex'] = "#\[u\](.*?)\[/u\]#si"; + $standard_mycode['u']['replacement'] = "$1"; + + $standard_mycode['i']['regex'] = "#\[i\](.*?)\[/i\]#si"; + $standard_mycode['i']['replacement'] = "$1"; + + $standard_mycode['s']['regex'] = "#\[s\](.*?)\[/s\]#si"; + $standard_mycode['s']['replacement'] = "$1"; + + $standard_mycode['hr']['regex'] = "#\[hr\]#si"; + $standard_mycode['hr']['replacement'] = "
    "; + + ++$standard_count; + } + + if($mybb->settings['allowsymbolmycode'] == 1) + { + $standard_mycode['copy']['regex'] = "#\(c\)#i"; + $standard_mycode['copy']['replacement'] = "©"; + + $standard_mycode['tm']['regex'] = "#\(tm\)#i"; + $standard_mycode['tm']['replacement'] = "™"; + + $standard_mycode['reg']['regex'] = "#\(r\)#i"; + $standard_mycode['reg']['replacement'] = "®"; + + ++$standard_count; + } + + if($mybb->settings['allowlinkmycode'] == 1) + { + $callback_mycode['url_simple']['regex'] = "#\[url\]([a-z]+?://)([^\r\n\"<]+?)\[/url\]#si"; + $callback_mycode['url_simple']['replacement'] = array($this, 'mycode_parse_url_callback1'); + + $callback_mycode['url_simple2']['regex'] = "#\[url\]([^\r\n\"<]+?)\[/url\]#i"; + $callback_mycode['url_simple2']['replacement'] = array($this, 'mycode_parse_url_callback2'); + + $callback_mycode['url_complex']['regex'] = "#\[url=([a-z]+?://)([^\r\n\"<]+?)\](.+?)\[/url\]#si"; + $callback_mycode['url_complex']['replacement'] = array($this, 'mycode_parse_url_callback1'); + + $callback_mycode['url_complex2']['regex'] = "#\[url=([^\r\n\"<&\(\)]+?)\](.+?)\[/url\]#si"; + $callback_mycode['url_complex2']['replacement'] = array($this, 'mycode_parse_url_callback2'); + + ++$callback_count; + } + + if($mybb->settings['allowemailmycode'] == 1) + { + $callback_mycode['email_simple']['regex'] = "#\[email\](.*?)\[/email\]#i"; + $callback_mycode['email_simple']['replacement'] = array($this, 'mycode_parse_email_callback'); + + $callback_mycode['email_complex']['regex'] = "#\[email=(.*?)\](.*?)\[/email\]#i"; + $callback_mycode['email_complex']['replacement'] = array($this, 'mycode_parse_email_callback'); + + ++$callback_count; + } + + if($mybb->settings['allowcolormycode'] == 1) + { + $nestable_mycode['color']['regex'] = "#\[color=([a-zA-Z]*|\#?[\da-fA-F]{3}|\#?[\da-fA-F]{6})](.*?)\[/color\]#si"; + $nestable_mycode['color']['replacement'] = "$2"; + + ++$nestable_count; + } + + if($mybb->settings['allowsizemycode'] == 1) + { + $nestable_mycode['size']['regex'] = "#\[size=(xx-small|x-small|small|medium|large|x-large|xx-large)\](.*?)\[/size\]#si"; + $nestable_mycode['size']['replacement'] = "$2"; + + $callback_mycode['size_int']['regex'] = "#\[size=([0-9\+\-]+?)\](.*?)\[/size\]#si"; + $callback_mycode['size_int']['replacement'] = array($this, 'mycode_handle_size_callback'); + + ++$nestable_count; + ++$callback_count; + } + + if($mybb->settings['allowfontmycode'] == 1) + { + $nestable_mycode['font']['regex'] = "#\[font=([a-z0-9 ,\-_'\"]+)\](.*?)\[/font\]#si"; + $nestable_mycode['font']['replacement'] = "$2"; + + ++$nestable_count; + } + + if($mybb->settings['allowalignmycode'] == 1) + { + $nestable_mycode['align']['regex'] = "#\[align=(left|center|right|justify)\](.*?)\[/align\]#si"; + $nestable_mycode['align']['replacement'] = "
    $2
    "; + + ++$nestable_count; + } + + $custom_mycode = $cache->read("mycode"); + + // If there is custom MyCode, load it. + if(is_array($custom_mycode)) + { + foreach($custom_mycode as $key => $mycode) + { + $mycode['regex'] = str_replace("\x0", "", $mycode['regex']); + $custom_mycode[$key]['regex'] = "#".$mycode['regex']."#si"; + + ++$standard_count; + } + $mycode = array_merge($standard_mycode, $custom_mycode); + } + else + { + $mycode = $standard_mycode; + } + + // Assign the MyCode to the cache. + foreach($mycode as $code) + { + $this->mycode_cache['standard']['find'][] = $code['regex']; + $this->mycode_cache['standard']['replacement'][] = $code['replacement']; + } + + // Assign the nestable MyCode to the cache. + foreach($nestable_mycode as $code) + { + $this->mycode_cache['nestable'][] = array('find' => $code['regex'], 'replacement' => $code['replacement']); + } + + // Assign the nestable MyCode to the cache. + foreach($callback_mycode as $code) + { + $this->mycode_cache['callback'][] = array('find' => $code['regex'], 'replacement' => $code['replacement']); + } + + $this->mycode_cache['standard_count'] = $standard_count; + $this->mycode_cache['callback_count'] = $callback_count; + $this->mycode_cache['nestable_count'] = $nestable_count; + } + + /** + * Parses MyCode tags in a specific message with the specified options. + * + * @param string The message to be parsed. + * @param array Array of options in yes/no format. Options are allow_imgcode. + * @return string The parsed message. + */ + function parse_mycode($message, $options=array()) + { + global $lang, $mybb; + + if(empty($this->options)) + { + $this->options = $options; + } + + // Cache the MyCode globally if needed. + if($this->mycode_cache == 0) + { + $this->cache_mycode(); + } + + // Parse quotes first + $message = $this->mycode_parse_quotes($message); + + $message = $this->mycode_auto_url($message); + + $message = str_replace('$', '$', $message); + + // Replace the rest + if($this->mycode_cache['standard_count'] > 0) + { + $message = preg_replace($this->mycode_cache['standard']['find'], $this->mycode_cache['standard']['replacement'], $message); + } + + if($this->mycode_cache['callback_count'] > 0) + { + foreach($this->mycode_cache['callback'] as $replace) + { + $message = preg_replace_callback($replace['find'], $replace['replacement'], $message); + } + } + + // Replace the nestable mycode's + if($this->mycode_cache['nestable_count'] > 0) + { + foreach($this->mycode_cache['nestable'] as $mycode) + { + while(preg_match($mycode['find'], $message)) + { + $message = preg_replace($mycode['find'], $mycode['replacement'], $message); + } + } + } + + // Reset list cache + if($mybb->settings['allowlistmycode'] == 1) + { + $this->list_elements = array(); + $this->list_count = 0; + + // Find all lists + $message = preg_replace_callback("#(\[list(=(a|A|i|I|1))?\]|\[/list\])#si", array($this, 'mycode_prepare_list'), $message); + + // Replace all lists + for($i = $this->list_count; $i > 0; $i--) + { + // Ignores missing end tags + $message = preg_replace_callback("#\s?\[list(=(a|A|i|I|1))?&{$i}\](.*?)(\[/list&{$i}\]|$)(\r\n?|\n?)#si", array($this, 'mycode_parse_list_callback'), $message, 1); + } + } + + // Convert images when allowed. + if(!empty($this->options['allow_imgcode'])) + { + $message = preg_replace_callback("#\[img\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#is", array($this, 'mycode_parse_img_callback1'), $message); + $message = preg_replace_callback("#\[img=([0-9]{1,3})x([0-9]{1,3})\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#is", array($this, 'mycode_parse_img_callback2'), $message); + $message = preg_replace_callback("#\[img align=([a-z]+)\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#is", array($this, 'mycode_parse_img_callback3'), $message); + $message = preg_replace_callback("#\[img=([0-9]{1,3})x([0-9]{1,3}) align=([a-z]+)\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#is", array($this, 'mycode_parse_img_callback4'), $message); + } + else + { + $message = preg_replace_callback("#\[img\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#is", array($this, 'mycode_parse_img_disabled_callback1'), $message); + $message = preg_replace_callback("#\[img=([0-9]{1,3})x([0-9]{1,3})\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#is", array($this, 'mycode_parse_img_disabled_callback2'), $message); + $message = preg_replace_callback("#\[img align=([a-z]+)\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#is", array($this, 'mycode_parse_img_disabled_callback3'), $message); + $message = preg_replace_callback("#\[img=([0-9]{1,3})x([0-9]{1,3}) align=([a-z]+)\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#is", array($this, 'mycode_parse_img_disabled_callback4'), $message); + } + + // Convert videos when allow. + if(!empty($this->options['allow_videocode'])) + { + $message = preg_replace_callback("#\[video=(.*?)\](.*?)\[/video\]#i", array($this, 'mycode_parse_video_callback'), $message); + } + else + { + $message = preg_replace_callback("#\[video=(.*?)\](.*?)\[/video\]#i", array($this, 'mycode_parse_video_disabled_callback'), $message); + } + + return $message; + } + + /** + * Generates a cache of smilies + * + * @access private + */ + function cache_smilies() + { + global $cache, $mybb, $theme, $templates; + $this->smilies_cache = array(); + + $smilies = $cache->read("smilies"); + if(is_array($smilies)) + { + $extra_class = $onclick = ''; + foreach($smilies as $sid => $smilie) + { + $smilie['find'] = explode("\n", $smilie['find']); + $smilie['image'] = str_replace("{theme}", $theme['imgdir'], $smilie['image']); + $smilie['image'] = $mybb->get_asset_url($smilie['image']); + + foreach($smilie['find'] as $s) + { + $s = $this->parse_html($s); + eval("\$smilie_template = \"".$templates->get("smilie", 1, 0)."\";"); + $this->smilies_cache[$s] = $smilie_template; + // workaround for smilies starting with ; + if($s[0] == ";") + { + $this->smilies_cache += array( + "&$s" => "&$s", + "<$s" => "<$s", + ">$s" => ">$s", + ); + } + } + } + } + } + + /** + * Parses smilie code in the specified message. + * + * @param string The message being parsed. + * @param string Base URL for the image tags created by smilies. + * @param string Yes/No if HTML is allowed in the post + * @return string The parsed message. + */ + function parse_smilies($message, $allow_html=0) + { + if($this->smilies_cache == 0) + { + $this->cache_smilies(); + } + + // No smilies? + if(!count($this->smilies_cache)) + { + return $message; + } + + // First we take out any of the tags we don't want parsed between (url= etc) + preg_match_all("#\[(url(=[^\]]*)?\]|quote=([^\]]*)?\])|(http|ftp)(s|)://[^\s]*#i", $message, $bad_matches, PREG_PATTERN_ORDER); + if(count($bad_matches[0]) > 0) + { + $message = preg_replace("#\[(url(=[^\]]*)?\]|quote=([^\]]*)?\])|(http|ftp)(s|)://[^\s]*#si", "", $message); + } + + $message = strtr($message, $this->smilies_cache); + + // If we matched any tags previously, swap them back in + if(count($bad_matches[0]) > 0) + { + $message = explode("", $message); + $i = 0; + foreach($bad_matches[0] as $match) + { + $message[$i] .= $match; + $i++; + } + $message = implode("", $message); + } + + return $message; + } + + /** + * Generates a cache of badwords filters. + * + * @access private + */ + function cache_badwords() + { + global $cache; + $this->badwords_cache = array(); + $this->badwords_cache = $cache->read("badwords"); + } + + /** + * Parses a list of filtered/badwords in the specified message. + * + * @param string The message to be parsed. + * @param array Array of parser options in yes/no format. + * @return string The parsed message. + */ + function parse_badwords($message, $options=array()) + { + if(empty($this->options)) + { + $this->options = $options; + } + + if($this->badwords_cache == 0) + { + $this->cache_badwords(); + } + if(is_array($this->badwords_cache)) + { + reset($this->badwords_cache); + foreach($this->badwords_cache as $bid => $badword) + { + if(!$badword['replacement']) + { + $badword['replacement'] = "*****"; + } + + // Take into account the position offset for our last replacement. + $index = substr_count($badword['badword'], '*')+2; + $badword['badword'] = str_replace('\*', '([a-zA-Z0-9_]{1})', preg_quote($badword['badword'], "#")); + + // Ensure we run the replacement enough times but not recursively (i.e. not while(preg_match..)) + $count = preg_match_all("#(^|\W)".$badword['badword']."(\W|$)#i", $message, $matches); + for($i=0; $i < $count; ++$i) + { + $message = preg_replace("#(^|\W)".$badword['badword']."(\W|$)#i", "\\1".$badword['replacement'].'\\'.$index, $message); + } + } + } + if(!empty($this->options['strip_tags'])) + { + $message = strip_tags($message); + } + return $message; + } + + /** + * Resolves nested CDATA tags in the specified message. + * + * @param string The message to be parsed. + * @return string The parsed message. + */ + function parse_cdata($message) + { + $message = str_replace(']]>', ']]]]>', $message); + + return $message; + } + + /** + * Attempts to move any javascript references in the specified message. + * + * @param string The message to be parsed. + * @return string The parsed message. + */ + function fix_javascript($message) + { + $js_array = array( + "#(&\#(0*)106;?|&\#(0*)74;?|&\#x(0*)4a;?|&\#x(0*)6a;?|j)((&\#(0*)97;?|&\#(0*)65;?|a)(&\#(0*)118;?|&\#(0*)86;?|v)(&\#(0*)97;?|&\#(0*)65;?|a)(\s)?(&\#(0*)115;?|&\#(0*)83;?|s)(&\#(0*)99;?|&\#(0*)67;?|c)(&\#(0*)114;?|&\#(0*)82;?|r)(&\#(0*)105;?|&\#(0*)73;?|i)(&\#112;?|&\#(0*)80;?|p)(&\#(0*)116;?|&\#(0*)84;?|t)(&\#(0*)58;?|\:))#i", + "#(o)(nmouseover\s?=)#i", + "#(o)(nmouseout\s?=)#i", + "#(o)(nmousedown\s?=)#i", + "#(o)(nmousemove\s?=)#i", + "#(o)(nmouseup\s?=)#i", + "#(o)(nclick\s?=)#i", + "#(o)(ndblclick\s?=)#i", + "#(o)(nload\s?=)#i", + "#(o)(nsubmit\s?=)#i", + "#(o)(nblur\s?=)#i", + "#(o)(nchange\s?=)#i", + "#(o)(nfocus\s?=)#i", + "#(o)(nselect\s?=)#i", + "#(o)(nunload\s?=)#i", + "#(o)(nkeypress\s?=)#i", + "#(o)(nerror\s?=)#i", + "#(o)(nreset\s?=)#i", + "#(o)(nabort\s?=)#i" + ); + + $message = preg_replace($js_array, "$1$2$4", $message); + + return $message; + } + + /** + * Handles fontsize. + * + * @param string The original size. + * @param string The text within a size tag. + * @return string The parsed text. + */ + function mycode_handle_size($size, $text) + { + $size = (int)$size+10; + + if($size > 50) + { + $size = 50; + } + + $text = "".str_replace("\'", "'", $text).""; + + return $text; + } + + /** + * Handles fontsize. + * + * @param array Matches. + * @return string The parsed text. + */ + function mycode_handle_size_callback($matches) + { + return $this->mycode_handle_size($matches[1], $matches[2]); + } + + /** + * Parses quote MyCode. + * + * @param string The message to be parsed + * @param boolean Are we formatting as text? + * @return string The parsed message. + */ + function mycode_parse_quotes($message, $text_only=false) + { + global $lang, $templates, $theme, $mybb; + + // Assign pattern and replace values. + $pattern = "#\[quote\](.*?)\[\/quote\](\r\n?|\n?)#si"; + $pattern_callback = "#\[quote=([\"']|"|)(.*?)(?:\\1)(.*?)(?:[\"']|")?\](.*?)\[/quote\](\r\n?|\n?)#si"; + + if($text_only == false) + { + $replace = "
    $lang->quote$1
    \n"; + $replace_callback = array($this, 'mycode_parse_post_quotes_callback1'); + } + else + { + $replace = "\n{$lang->quote}\n--\n$1\n--\n"; + $replace_callback = array($this, 'mycode_parse_post_quotes_callback2'); + } + + do + { + // preg_replace has erased the message? Restore it... + $previous_message = $message; + $message = preg_replace($pattern, $replace, $message, -1, $count); + $message = preg_replace_callback($pattern_callback, $replace_callback, $message, -1, $count_callback); + if(!$message) + { + $message = $previous_message; + break; + } + } while($count || $count_callback); + + if($text_only == false) + { + $find = array( + "#(\r\n*|\n*)<\/cite>(\r\n*|\n*)#", + "#(\r\n*|\n*)<\/blockquote>#" + ); + + $replace = array( + "
    ", + "" + ); + $message = preg_replace($find, $replace, $message); + } + return $message; + } + + /** + * Parses quotes with post id and/or dateline. + * + * @param string The message to be parsed + * @param string The username to be parsed + * @param boolean Are we formatting as text? + * @return string The parsed message. + */ + function mycode_parse_post_quotes($message, $username, $text_only=false) + { + global $lang, $templates, $theme, $mybb; + + $linkback = $date = ""; + + $message = trim($message); + $message = preg_replace("#(^|$)#i", "", $message); + + if(!$message) + { + return ''; + } + + $username .= "'"; + $delete_quote = true; + + preg_match("#pid=(?:"|\"|')?([0-9]+)[\"']?(?:"|\"|')?#i", $username, $match); + if((int)$match[1]) + { + $pid = (int)$match[1]; + $url = $mybb->settings['bburl']."/".get_post_link($pid)."#pid$pid"; + if(defined("IN_ARCHIVE")) + { + $linkback = " [ -> ]"; + } + else + { + eval("\$linkback = \" ".$templates->get("postbit_gotopost", 1, 0)."\";"); + } + + $username = preg_replace("#(?:"|\"|')? pid=(?:"|\"|')?[0-9]+[\"']?(?:"|\"|')?#i", '', $username); + $delete_quote = false; + } + + unset($match); + preg_match("#dateline=(?:"|\"|')?([0-9]+)(?:"|\"|')?#i", $username, $match); + if((int)$match[1]) + { + if($match[1] < TIME_NOW) + { + $postdate = my_date('relative', (int)$match[1]); + $date = " ({$postdate})"; + } + $username = preg_replace("#(?:"|\"|')? dateline=(?:"|\"|')?[0-9]+(?:"|\"|')?#i", '', $username); + $delete_quote = false; + } + + if($delete_quote) + { + $username = my_substr($username, 0, my_strlen($username)-1); + } + + if($text_only) + { + return "\n".htmlspecialchars_uni($username)." $lang->wrote{$date}\n--\n{$message}\n--\n"; + } + else + { + $span = ""; + if(!$delete_quote) + { + $span = "{$date}"; + } + + return "
    {$span}".htmlspecialchars_uni($username)." $lang->wrote{$linkback}{$message}
    \n"; + } + } + + /** + * Parses quotes with post id and/or dateline. + * + * @param array Matches. + * @return string The parsed message. + */ + function mycode_parse_post_quotes_callback1($matches) + { + return $this->mycode_parse_post_quotes($matches[4],$matches[2].$matches[3]); + } + + /** + * Parses quotes with post id and/or dateline. + * + * @param array Matches. + * @return string The parsed message. + */ + function mycode_parse_post_quotes_callback2($matches) + { + return $this->mycode_parse_post_quotes($matches[4],$matches[2].$matches[3], true); + } + + /** + * Parses code MyCode. + * + * @param string The message to be parsed + * @param boolean Are we formatting as text? + * @return string The parsed message. + */ + function mycode_parse_code($code, $text_only=false) + { + global $lang; + + if($text_only == true) + { + return "\n{$lang->code}\n--\n{$code}\n--\n"; + } + + // Clean the string before parsing. + $code = preg_replace('#^(\t*)(\n|\r|\0|\x0B| )*#', '\\1', $code); + $code = rtrim($code); + $original = preg_replace('#^\t*#', '', $code); + + if(empty($original)) + { + return; + } + + $code = str_replace('$', '$', $code); + $code = preg_replace('#\$([0-9])#', '\\\$\\1', $code); + $code = str_replace('\\', '\', $code); + $code = str_replace("\t", '    ', $code); + $code = str_replace(" ", '  ', $code); + + return "
    \n
    ".$lang->code."\n
    ".$code."
    \n"; + } + + /** + * Parses code MyCode. + * + * @param array Matches. + * @return string The parsed message. + */ + function mycode_parse_code_callback($matches) + { + return $this->mycode_parse_code($matches[1], true); + } + + /** + * Parses PHP code MyCode. + * + * @param string The message to be parsed + * @param boolean Whether or not it should return it as pre-wrapped in a div or not. + * @param boolean Are we formatting as text? + * @return string The parsed message. + */ + function mycode_parse_php($str, $bare_return = false, $text_only = false) + { + global $lang; + + if($text_only == true) + { + return "\n{$lang->php_code}\n--\n$str\n--\n"; + } + + // Clean the string before parsing except tab spaces. + $str = preg_replace('#^(\t*)(\n|\r|\0|\x0B| )*#', '\\1', $str); + $str = rtrim($str); + + $original = preg_replace('#^\t*#', '', $str); + + if(empty($original)) + { + return; + } + + $str = str_replace('&', '&', $str); + $str = str_replace('<', '<', $str); + $str = str_replace('>', '>', $str); + + // See if open and close tags are provided. + $added_open_tag = false; + if(!preg_match("#^\s*<\?#si", $str)) + { + $added_open_tag = true; + $str = "\s*$#si", $str)) + { + $added_end_tag = true; + $str = $str." \n?>"; + } + + $code = @highlight_string($str, true); + + // Do the actual replacing. + $code = preg_replace('#\s*\s*#i', "", $code); + $code = preg_replace("#\s*#", "", $code); + $code = preg_replace("#(\r\n?|\n?)#", "", $code); + $code = str_replace("\\", '\', $code); + $code = str_replace('$', '$', $code); + $code = preg_replace("#&\#([0-9]+);#si", "&#$1;", $code); + + if($added_open_tag) + { + $code = preg_replace("#<\?php( | )(
    ?)#", "", $code); + } + + if($added_end_tag) + { + $code = str_replace("?>", "
    ", $code); + // Wait a minute. It fails highlighting? Stupid highlighter. + $code = str_replace("?>", "", $code); + } + + $code = preg_replace("##", "", $code); + $code = str_replace("", "
    ", $code); + $code = str_replace("", "
    ", $code); + $code = preg_replace("# *$#", "", $code); + + if($bare_return) + { + return $code; + } + + // Send back the code all nice and pretty + return "
    $lang->php_code\n
    ".$code."
    \n"; + } + + /** + * Parses PHP code MyCode. + * + * @param array Matches. + * @return string The parsed message. + */ + function mycode_parse_php_callback($matches) + { + return $this->mycode_parse_php($matches[1], false, true); + } + + /** + * Parses URL MyCode. + * + * @param string The URL to link to. + * @param string The name of the link. + * @return string The built-up link. + */ + function mycode_parse_url($url, $name="") + { + if(!preg_match("#^[a-z0-9]+://#i", $url)) + { + $url = "http://".$url; + } + $fullurl = $url; + + if(!$name) + { + $name = $url; + } + + if($name == $url && !empty($this->options['shorten_urls'])) + { + if(my_strlen($url) > 55) + { + $name = my_substr($url, 0, 40)."...".my_substr($url, -10); + } + } + + $nofollow = ''; + if(!empty($this->options['nofollow_on'])) + { + $nofollow = " rel=\"nofollow\""; + } + + // Fix some entities in URLs + $entities = array('$' => '%24', '$' => '%24', '^' => '%5E', '`' => '%60', '[' => '%5B', ']' => '%5D', '{' => '%7B', '}' => '%7D', '"' => '%22', '<' => '%3C', '>' => '%3E', ' ' => '%20'); + $fullurl = str_replace(array_keys($entities), array_values($entities), $fullurl); + + $name = preg_replace("#&\#([0-9]+);#si", "&#$1;", $name); // Fix & but allow unicode + $link = "$name"; + return $link; + } + + /** + * Parses URL MyCode. + * + * @param array Matches. + * @return string The built-up link. + */ + function mycode_parse_url_callback1($matches) + { + if(!isset($matches[3])) + { + $matches[3] = ''; + } + return $this->mycode_parse_url($matches[1].$matches[2], $matches[3]); + } + + /** + * Parses URL MyCode. + * + * @param array Matches. + * @return string The built-up link. + */ + function mycode_parse_url_callback2($matches) + { + if(!isset($matches[2])) + { + $matches[2] = ''; + } + return $this->mycode_parse_url($matches[1], $matches[2]); + } + + /** + * Parses IMG MyCode. + * + * @param string The URL to the image + * @param array Optional array of dimensions + */ + function mycode_parse_img($url, $dimensions=array(), $align='') + { + global $lang; + $url = trim($url); + $url = str_replace("\n", "", $url); + $url = str_replace("\r", "", $url); + if($align == "right") + { + $css_align = " style=\"float: right;\""; + } + else if($align == "left") + { + $css_align = " style=\"float: left;\""; + } + $alt = htmlspecialchars_uni(basename($url)); + if(my_strlen($alt) > 55) + { + $alt = my_substr($alt, 0, 40)."...".my_substr($alt, -10); + } + $alt = $lang->sprintf($lang->posted_image, $alt); + if($dimensions[0] > 0 && $dimensions[1] > 0) + { + return "\"{$alt}\"{$css_align}"; + } + else + { + return "\"{$alt}\"{$css_align}"; + } + } + + /** + * Parses IMG MyCode. + * + * @param array Matches. + * @return string Image code. + */ + function mycode_parse_img_callback1($matches) + { + return $this->mycode_parse_img($matches[2]); + } + + /** + * Parses IMG MyCode. + * + * @param array Matches. + * @return string Image code. + */ + function mycode_parse_img_callback2($matches) + { + return $this->mycode_parse_img($matches[4], array($matches[1], $matches[2])); + } + + /** + * Parses IMG MyCode. + * + * @param array Matches. + * @return string Image code. + */ + function mycode_parse_img_callback3($matches) + { + return $this->mycode_parse_img($matches[3], array(), $matches[1]); + } + + /** + * Parses IMG MyCode. + * + * @param array Matches. + * @return string Image code. + */ + function mycode_parse_img_callback4($matches) + { + return $this->mycode_parse_img($matches[5], array($matches[1], $matches[2]), $matches[3]); + } + + /** + * Parses IMG MyCode disabled. + * + * @param string The URL to the image + */ + function mycode_parse_img_disabled($url) + { + global $lang; + $url = trim($url); + $url = str_replace("\n", "", $url); + $url = str_replace("\r", "", $url); + $url = str_replace("\'", "'", $url); + + $image = $lang->sprintf($lang->posted_image, $this->mycode_parse_url($url)); + return $image; + } + + /** + * Parses IMG MyCode disabled. + * + * @param array Matches. + * @return string Image code. + */ + function mycode_parse_img_disabled_callback1($matches) + { + return $this->mycode_parse_img_disabled($matches[2]); + } + + /** + * Parses IMG MyCode disabled. + * + * @param array Matches. + * @return string Image code. + */ + function mycode_parse_img_disabled_callback2($matches) + { + return $this->mycode_parse_img_disabled($matches[4]); + } + + /** + * Parses IMG MyCode disabled. + * + * @param array Matches. + * @return string Image code. + */ + function mycode_parse_img_disabled_callback3($matches) + { + return $this->mycode_parse_img_disabled($matches[3]); + } + + /** + * Parses IMG MyCode disabled. + * + * @param array Matches. + * @return string Image code. + */ + function mycode_parse_img_disabled_callback4($matches) + { + return $this->mycode_parse_img_disabled($matches[5]); + } + + /** + * Parses email MyCode. + * + * @param string The email address to link to. + * @param string The name for the link. + * @return string The built-up email link. + */ + function mycode_parse_email($email, $name="") + { + if(!$name) + { + $name = $email; + } + if(preg_match("/^([a-zA-Z0-9-_\+\.]+?)@[a-zA-Z0-9-]+\.[a-zA-Z0-9\.-]+$/si", $email)) + { + return "".$name.""; + } + else + { + return $email; + } + } + + /** + * Parses email MyCode. + * + * @param array Matches + * @return string The built-up email link. + */ + function mycode_parse_email_callback($matches) + { + if(!isset($matches[2])) + { + $matches[2] = ''; + } + return $this->mycode_parse_email($matches[1], $matches[2]); + } + + /** + * Parses video MyCode. + * + * @param string The video provider. + * @param string The video to link to. + * @return string The built-up video code. + */ + function mycode_parse_video($video, $url) + { + global $templates; + + if(empty($video) || empty($url)) + { + return "[video={$video}]{$url}[/video]"; + } + + $parsed_url = @parse_url(urldecode($url)); + if($parsed_url == false) + { + return "[video={$video}]{$url}[/video]"; + } + + $fragments = array(); + if($parsed_url['fragment']) + { + $fragments = explode("&", $parsed_url['fragment']); + } + + $queries = explode("&", $parsed_url['query']); + + $input = array(); + foreach($queries as $query) + { + list($key, $value) = explode("=", $query); + $key = str_replace("amp;", "", $key); + $input[$key] = $value; + } + + $path = explode('/', $parsed_url['path']); + + switch($video) + { + case "dailymotion": + list($id, ) = split("_", $path[2], 1); // http://www.dailymotion.com/video/fds123_title-goes-here + break; + case "metacafe": + $id = $path[2]; // http://www.metacafe.com/watch/fds123/title_goes_here/ + $title = htmlspecialchars_uni($path[3]); + break; + case "myspacetv": + $id = $path[4]; // http://www.myspace.com/video/fds/fds/123 + break; + case "facebook": + $id = $input['v']; // http://www.facebook.com/video/video.php?v=123 + break; + case "veoh": + $id = $path[2]; // http://www.veoh.com/watch/123 + break; + case "liveleak": + $id = $input['i']; // http://www.liveleak.com/view?i=123 + break; + case "yahoo": + $id = $path[1]; // http://xy.screen.yahoo.com/fds-123.html + // Support for localized portals + $domain = explode('.', $parsed_url['host']); + if($domain[0] != 'screen' && preg_match('#^([a-z-]+)$#', $domain[0])) + { + $local = "{$domain[0]}."; + } + else + { + $local = ''; + } + break; + case "vimeo": + $id = $path[1]; // http://vimeo.com/fds123 + break; + case "youtube": + if($fragments[0]) + { + $id = str_replace('!v=', '', $fragments[0]); // http://www.youtube.com/watch#!v=fds123 + } + elseif($input['v']) + { + $id = $input['v']; // http://www.youtube.com/watch?v=fds123 + } + else + { + $id = $path[1]; // http://www.youtu.be/fds123 + } + break; + default: + return "[video={$video}]{$url}[/video]"; + } + + if(empty($id)) + { + return "[video={$video}]{$url}[/video]"; + } + + $id = htmlspecialchars_uni($id); + + eval("\$video_code = \"".$templates->get("video_{$video}_embed")."\";"); + + return $video_code; + } + + /** + * Parses video MyCode. + * + * @param array Matches. + * @return string The built-up video code. + */ + function mycode_parse_video_callback($matches) + { + return $this->mycode_parse_video($matches[1], $matches[2]); + } + + /** + * Parses video MyCode disabled. + * + * @param string The URL to the video + */ + function mycode_parse_video_disabled($url) + { + global $lang; + $url = trim($url); + $url = str_replace("\n", "", $url); + $url = str_replace("\r", "", $url); + $url = str_replace("\'", "'", $url); + + $video = $lang->sprintf($lang->posted_video, $this->mycode_parse_url($url)); + return $video; + } + + /** + * Parses video MyCode disabled. + * + * @param array Matches. + * @return string The built-up video code. + */ + function mycode_parse_video_disabled_callback($matches) + { + return $this->mycode_parse_video_disabled($matches[2]); + } + + /** + * Parses URLs automatically. + * + * @param string The message to be parsed + * @return string The parsed message. + */ + function mycode_auto_url($message) + { + $message = " ".$message; + // Links should end with slashes, numbers, characters and braces but not with dots, commas or question marks + $message = preg_replace_callback("#([\>\s\(\)])(http|https|ftp|news|irc|ircs|irc6){1}://([^\/\"\s\<\[\.]+\.([^\/\"\s\<\[\.]+\.)*[\w]+(:[0-9]+)?(/([^\"\s<\[]|\[\])*)?([\w\/\)]))#iu", array($this, 'mycode_auto_url_callback'), $message); + $message = preg_replace_callback("#([\>\s\(\)])(www|ftp)\.(([^\/\"\s\<\[\.]+\.)*[\w]+(:[0-9]+)?(/([^\"\s<\[]|\[\])*)?([\w\/\)]))#iu", array($this, 'mycode_auto_url_callback'), $message); + $message = my_substr($message, 1); + + return $message; + } + + /** + * Parses URLs automatically. + * + * @param array Matches + * @return string The parsed message. + */ + function mycode_auto_url_callback($matches) + { + $external = ''; + // Allow links like http://en.wikipedia.org/wiki/PHP_(disambiguation) but detect mismatching braces + while(my_substr($matches[3], -1) == ')') + { + if(substr_count($matches[3], ')') > substr_count($matches[3], '(')) + { + $matches[3] = my_substr($matches[3], 0, -1); + $external = ')'.$external; + } + else + { + break; + } + + // Example: ([...] http://en.wikipedia.org/Example_(disambiguation).) + $last_char = my_substr($matches[3], -1); + while($last_char == '.' || $last_char == ',' || $last_char == '?' || $last_char == '!') + { + $matches[3] = my_substr($matches[3], 0, -1); + $external = $last_char.$external; + $last_char = my_substr($matches[3], -1); + } + } + if($matches[2] == 'www' || $matches[2] == 'ftp') + { + return "{$matches[1]}[url]{$matches[2]}.{$matches[3]}[/url]{$external}"; + } + else + { + return "{$matches[1]}[url]{$matches[2]}://{$matches[3]}[/url]{$external}"; + } + } + + /** + * Parses list MyCode. + * + * @param string The message to be parsed + * @param string The list type + * @return string The parsed message. + */ + function mycode_parse_list($message, $type="") + { + // No list elements? That's invalid HTML + if(strpos($message, '[*]') === false) + { + $message = "[*]{$message}"; + } + + $message = preg_replace("#\s*\[\*\]\s*#", "\n
  • ", $message); + $message .= "
  • "; + + if($type) + { + $list = "\n
      $message
    \n"; + } + else + { + $list = "
      $message
    \n"; + } + $list = preg_replace("#<(ol type=\"$type\"|ul)>\s*#", "<$1>", $list); + return $list; + } + + /** + * Parses list MyCode. + * + * @param array Matches + * @return string The parsed message. + */ + function mycode_parse_list_callback($matches) + { + return $this->mycode_parse_list($matches[3], $matches[2]); + } + + /** + * Prepares list MyCode by finding the matching list tags. + * + * @param array Matches + * @return string Temporary replacements. + */ + function mycode_prepare_list($matches) + { + // Append number to identify matching list tags + if(strcasecmp($matches[1], '[/list]') == 0) + { + $count = array_pop($this->list_elements); + if($count !== NULL) + { + return "[/list&{$count}]"; + } + else + { + // No open list tag... + return $matches[0]; + } + } + else + { + ++$this->list_count; + $this->list_elements[] = $this->list_count; + if(!empty($matches[2])) + { + return "[list{$matches[2]}&{$this->list_count}]"; + } + else + { + return "[list&{$this->list_count}]"; + } + } + } + + /** + * Strips smilies from a string + * + * @param string The message for smilies to be stripped from + * @return string The message with smilies stripped + */ + function strip_smilies($message) + { + if($this->smilies_cache == 0) + { + $this->cache_smilies(); + } + if(is_array($this->smilies_cache)) + { + $message = str_replace($this->smilies_cache, array_keys($this->smilies_cache), $message); + } + return $message; + } + + /** + * Highlights a string + * + * @param string The message to be highligted + * @param string The highlight keywords + * @return string The message with highlight bbcodes + */ + function highlight_message($message, $highlight) + { + if(empty($this->highlight_cache)) + { + $this->highlight_cache = build_highlight_array($highlight); + } + + if(is_array($this->highlight_cache) && !empty($this->highlight_cache)) + { + $message = preg_replace(array_keys($this->highlight_cache), $this->highlight_cache, $message); + } + + return $message; + } + + /** + * Parses message to plain text equivalents of MyCode. + * + * @param string The message to be parsed + * @return string The parsed message. + */ + function text_parse_message($message, $options=array()) + { + global $plugins; + + if(empty($this->options)) + { + $this->options = $options; + } + + // Filter bad words if requested. + if(!empty($this->options['filter_badwords'])) + { + $message = $this->parse_badwords($message); + } + + // Parse quotes first + $message = $this->mycode_parse_quotes($message, true); + + $message = preg_replace_callback("#\[php\](.*?)\[/php\](\r\n?|\n?)#is", array($this, 'mycode_parse_php_callback'), $message); + $message = preg_replace_callback("#\[code\](.*?)\[/code\](\r\n?|\n?)#is", array($this, 'mycode_parse_code_callback'), $message); + + $find = array( + "#\[(b|u|i|s|url|email|color|img)\](.*?)\[/\\1\]#is", + "#\[img=([0-9]{1,3})x([0-9]{1,3})\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#is", + "#\[url=([a-z]+?://)([^\r\n\"<]+?)\](.+?)\[/url\]#si", + "#\[url=([^\r\n\"<&\(\)]+?)\](.+?)\[/url\]#si", + ); + + $replace = array( + "$2", + "$4", + "$3 ($1$2)", + "$2 ($1)", + ); + $message = preg_replace($find, $replace, $message); + + // Replace "me" code and slaps if we have a username + if(!empty($this->options['me_username'])) + { + global $lang; + + $message = preg_replace('#(>|^|\r|\n)/me ([^\r\n<]*)#i', "\\1* {$this->options['me_username']} \\2", $message); + $message = preg_replace('#(>|^|\r|\n)/slap ([^\r\n<]*)#i', "\\1* {$this->options['me_username']} {$lang->slaps} \\2 {$lang->with_trout}", $message); + } + + // Reset list cache + $this->list_elements = array(); + $this->list_count = 0; + + // Find all lists + $message = preg_replace_callback("#(\[list(=(a|A|i|I|1))?\]|\[/list\])#si", array($this, 'mycode_prepare_list'), $message); + + // Replace all lists + for($i = $this->list_count; $i > 0; $i--) + { + // Ignores missing end tags + $message = preg_replace_callback("#\s?\[list(=(a|A|i|I|1))?&{$i}\](.*?)(\[/list&{$i}\]|$)(\r\n?|\n?)#si", array($this, 'mycode_parse_list_callback'), $message, 1); + } + + // Run plugin hooks + $message = $plugins->run_hooks("text_parse_message", $message); + + return $message; + } +} diff --git a/Upload/inc/class_plugins.php b/Upload/inc/class_plugins.php new file mode 100644 index 0000000..2e0d17b --- /dev/null +++ b/Upload/inc/class_plugins.php @@ -0,0 +1,245 @@ +read("plugins"); + if(!empty($plugin_list['active']) && is_array($plugin_list['active'])) + { + foreach($plugin_list['active'] as $plugin) + { + if($plugin != "" && file_exists(MYBB_ROOT."inc/plugins/".$plugin.".php")) + { + require_once MYBB_ROOT."inc/plugins/".$plugin.".php"; + } + } + } + } + + /** + * Add a hook onto which a plugin can be attached. + * + * @param string $hook The hook name. + * @param array|string $function The function of this hook. + * @param int $priority The priority this hook has. + * @param string $file The optional file belonging to this hook. + * @return boolean Whether the hook was added. + */ + function add_hook($hook, $function, $priority=10, $file="") + { + if(is_array($function)) + { + if(!count($function) == 2) + { // must be an array of two items! + return false; + } + + if(is_string($function[0])) + { // Static class method + $method_representation = sprintf('%s::%s', $function[0], $function[1]); + } + elseif(is_object($function[0])) + { // Instance class method + $method_representation = sprintf('%s->%s', get_class($function[0]), $function[1]); + } + else + { // Unknown array type + return false; + } + + // Check to see if we already have this hook running at this priority + if(!empty($this->hooks[$hook][$priority][$method_representation]) && is_array($this->hooks[$hook][$priority][$method_representation])) + { + return true; + } + + // Add the hook + $this->hooks[$hook][$priority][$method_representation] = array( + 'class_method' => $function, + 'file' => $file + ); + } + else + { + // Check to see if we already have this hook running at this priority + if(!empty($this->hooks[$hook][$priority][$function]) && is_array($this->hooks[$hook][$priority][$function])) + { + return true; + } + + // Add the hook + $this->hooks[$hook][$priority][$function] = array( + 'function' => $function, + 'file' => $file + ); + } + + return true; + } + + /** + * Run the hooks that have plugins. + * + * @param string $hook The name of the hook that is run. + * @param string $arguments The argument for the hook that is run. The passed value MUST be a variable + * @return string The arguments for the hook. + */ + function run_hooks($hook, &$arguments="") + { + if(!isset($this->hooks[$hook]) || !is_array($this->hooks[$hook])) + { + return $arguments; + } + $this->current_hook = $hook; + ksort($this->hooks[$hook]); + foreach($this->hooks[$hook] as $priority => $hooks) + { + if(is_array($hooks)) + { + foreach($hooks as $key => $hook) + { + if($hook['file']) + { + require_once $hook['file']; + } + + if(array_key_exists('class_method', $hook)) + { + $return_args = call_user_func_array($hook['class_method'], array(&$arguments)); + } + else + { + $func = $hook['function']; + + $return_args = $func($arguments); + } + + if($return_args) + { + $arguments = $return_args; + } + } + } + } + $this->current_hook = ''; + + return $arguments; + } + + /** + * Remove a specific hook. + * + * @param string $hook The name of the hook. + * @param array|string $function The function of the hook. + * @param string $file The filename of the plugin. + * @param int $priority The priority of the hook. + * @return bool Whether the hook was removed successfully. + */ + function remove_hook($hook, $function, $file="", $priority=10) + { + if(is_array($function)) + { + if(is_string($function[0])) + { // Static class method + $method_representation = sprintf('%s::%s', $function[0], $function[1]); + } + elseif(is_object($function[0])) + { // Instance class method + $method_representation = sprintf('%s->%s', get_class($function[0]), $function[1]); + } + else + { // Unknown array type + return false; + } + + if(!isset($this->hooks[$hook][$priority][$method_representation])) + { + return true; + } + unset($this->hooks[$hook][$priority][$method_representation]); + } + else + { + // Check to see if we don't already have this hook running at this priority + if(!isset($this->hooks[$hook][$priority][$function])) + { + return true; + } + unset($this->hooks[$hook][$priority][$function]); + } + + return true; + } + + /** + * Establishes if a particular plugin is compatible with this version of MyBB. + * + * @param string $plugin The name of the plugin. + * @return boolean TRUE if compatible, FALSE if incompatible. + */ + function is_compatible($plugin) + { + global $mybb; + + // Ignore potentially missing plugins. + if(!file_exists(MYBB_ROOT."inc/plugins/".$plugin.".php")) + { + return true; + } + + require_once MYBB_ROOT."inc/plugins/".$plugin.".php"; + + $info_func = "{$plugin}_info"; + if(!function_exists($info_func)) + { + return false; + } + $plugin_info = $info_func(); + + // No compatibility set or compatibility = * - assume compatible + if(!$plugin_info['compatibility'] || $plugin_info['compatibility'] == "*") + { + return true; + } + $compatibility = explode(",", $plugin_info['compatibility']); + foreach($compatibility as $version) + { + $version = trim($version); + $version = str_replace("*", ".+", preg_quote($version)); + $version = str_replace("\.+", ".+", $version); + if(preg_match("#{$version}#i", $mybb->version_code)) + { + return true; + } + } + + // Nothing matches + return false; + } +} + diff --git a/Upload/inc/class_session.php b/Upload/inc/class_session.php new file mode 100644 index 0000000..f92622b --- /dev/null +++ b/Upload/inc/class_session.php @@ -0,0 +1,557 @@ +ipaddress = get_ip(); + $this->packedip = my_inet_pton($this->ipaddress); + + // Find out the user agent. + $this->useragent = $_SERVER['HTTP_USER_AGENT']; + + // Attempt to find a session id in the cookies. + if(isset($mybb->cookies['sid'])) + { + $sid = $db->escape_string($mybb->cookies['sid']); + // Load the session + $query = $db->simple_select("sessions", "*", "sid='{$sid}' AND ip=".$db->escape_binary($this->packedip)); + $session = $db->fetch_array($query); + if($session['sid']) + { + $this->sid = $session['sid']; + } + } + + // If we have a valid session id and user id, load that users session. + if(!empty($mybb->cookies['mybbuser'])) + { + $logon = explode("_", $mybb->cookies['mybbuser'], 2); + $this->load_user($logon[0], $logon[1]); + } + + // If no user still, then we have a guest. + if(!isset($mybb->user['uid'])) + { + // Detect if this guest is a search engine spider. (bots don't get a cookied session ID so we first see if that's set) + if(!$this->sid) + { + $spiders = $cache->read("spiders"); + if(is_array($spiders)) + { + foreach($spiders as $spider) + { + if(my_strpos(my_strtolower($this->useragent), my_strtolower($spider['useragent'])) !== false) + { + $this->load_spider($spider['sid']); + } + } + } + } + + // Still nothing? JUST A GUEST! + if(!$this->is_spider) + { + $this->load_guest(); + } + } + + // As a token of our appreciation for getting this far (and they aren't a spider), give the user a cookie + if($this->sid && (!isset($mybb->cookies['sid']) || $mybb->cookies['sid'] != $this->sid) && $this->is_spider != true) + { + my_setcookie("sid", $this->sid, -1, true); + } + } + + /** + * Load a user via the user credentials. + * + * @param int The user id. + * @param string The user's loginkey. + */ + function load_user($uid, $loginkey='') + { + global $mybb, $db, $time, $lang, $mybbgroups, $session, $cache; + + // Read the banned cache + $bannedcache = $cache->read("banned"); + + // If the banned cache doesn't exist, update it and re-read it + if(!is_array($bannedcache)) + { + $cache->update_banned(); + $bannedcache = $cache->read("banned"); + } + + $uid = (int)$uid; + $query = $db->query(" + SELECT u.*, f.* + FROM ".TABLE_PREFIX."users u + LEFT JOIN ".TABLE_PREFIX."userfields f ON (f.ufid=u.uid) + WHERE u.uid='$uid' + LIMIT 1 + "); + $mybb->user = $db->fetch_array($query); + + if(!empty($bannedcache[$uid])) + { + $banned_user = $bannedcache[$uid]; + $mybb->user['bandate'] = $banned_user['dateline']; + $mybb->user['banlifted'] = $banned_user['lifted']; + $mybb->user['banoldgroup'] = $banned_user['oldgroup']; + $mybb->user['banolddisplaygroup'] = $banned_user['olddisplaygroup']; + $mybb->user['banoldadditionalgroups'] = $banned_user['oldadditionalgroups']; + } + + // Check the password if we're not using a session + if(empty($loginkey) || $loginkey != $mybb->user['loginkey'] || !$mybb->user['uid']) + { + unset($mybb->user); + $this->uid = 0; + return false; + } + $this->uid = $mybb->user['uid']; + + // Set the logout key for this user + $mybb->user['logoutkey'] = md5($mybb->user['loginkey']); + + // Sort out the private message count for this user. + if(($mybb->user['totalpms'] == -1 || $mybb->user['unreadpms'] == -1) && $mybb->settings['enablepms'] != 0) // Forced recount + { + $update = 0; + if($mybb->user['totalpms'] == -1) + { + $update += 1; + } + if($mybb->user['unreadpms'] == -1) + { + $update += 2; + } + + require_once MYBB_ROOT."inc/functions_user.php"; + $pmcount = update_pm_count('', $update); + if(is_array($pmcount)) + { + $mybb->user = array_merge($mybb->user, $pmcount); + } + } + $mybb->user['pms_total'] = $mybb->user['totalpms']; + $mybb->user['pms_unread'] = $mybb->user['unreadpms']; + + if($mybb->user['lastip'] != $this->packedip && array_key_exists('lastip', $mybb->user)) + { + $lastip_add = ", lastip=".$db->escape_binary($this->packedip); + } + else + { + $lastip_add = ''; + } + + // If the last visit was over 900 seconds (session time out) ago then update lastvisit. + $time = TIME_NOW; + if($time - $mybb->user['lastactive'] > 900) + { + $db->shutdown_query("UPDATE ".TABLE_PREFIX."users SET lastvisit='{$mybb->user['lastactive']}', lastactive='$time'{$lastip_add} WHERE uid='{$mybb->user['uid']}'"); + $mybb->user['lastvisit'] = $mybb->user['lastactive']; + require_once MYBB_ROOT."inc/functions_user.php"; + update_pm_count('', 2); + } + else + { + $timespent = TIME_NOW - $mybb->user['lastactive']; + $db->shutdown_query("UPDATE ".TABLE_PREFIX."users SET lastactive='$time', timeonline=timeonline+$timespent{$lastip_add} WHERE uid='{$mybb->user['uid']}'"); + } + + // Sort out the language and forum preferences. + if($mybb->user['language'] && $lang->language_exists($mybb->user['language'])) + { + $mybb->settings['bblanguage'] = $mybb->user['language']; + } + if($mybb->user['dateformat'] != 0 && $mybb->user['dateformat'] != '') + { + global $date_formats; + if($date_formats[$mybb->user['dateformat']]) + { + $mybb->settings['dateformat'] = $date_formats[$mybb->user['dateformat']]; + } + } + + // Choose time format. + if($mybb->user['timeformat'] != 0 && $mybb->user['timeformat'] != '') + { + global $time_formats; + if($time_formats[$mybb->user['timeformat']]) + { + $mybb->settings['timeformat'] = $time_formats[$mybb->user['timeformat']]; + } + } + + // Find out the threads per page preference. + if($mybb->user['tpp']) + { + $mybb->settings['threadsperpage'] = $mybb->user['tpp']; + } + + // Find out the posts per page preference. + if($mybb->user['ppp']) + { + $mybb->settings['postsperpage'] = $mybb->user['ppp']; + } + + // Does this user prefer posts in classic mode? + if($mybb->user['classicpostbit']) + { + $mybb->settings['postlayout'] = 'classic'; + } + else + { + $mybb->settings['postlayout'] = 'horizontal'; + } + + // Check if this user is currently banned and if we have to lift it. + if(!empty($mybb->user['bandate']) && (isset($mybb->user['banlifted']) && !empty($mybb->user['banlifted'])) && $mybb->user['banlifted'] < $time) // hmmm...bad user... how did you get banned =/ + { + // must have been good.. bans up :D + $db->shutdown_query("UPDATE ".TABLE_PREFIX."users SET usergroup='".(int)$mybb->user['banoldgroup']."', additionalgroups='".$mybb->user['banoldadditionalgroups']."', displaygroup='".(int)$mybb->user['banolddisplaygroup']."' WHERE uid='".$mybb->user['uid']."'"); + $db->shutdown_query("DELETE FROM ".TABLE_PREFIX."banned WHERE uid='".$mybb->user['uid']."'"); + // we better do this..otherwise they have dodgy permissions + $mybb->user['usergroup'] = $mybb->user['banoldgroup']; + $mybb->user['displaygroup'] = $mybb->user['banolddisplaygroup']; + $mybb->user['additionalgroups'] = $mybb->user['banoldadditionalgroups']; + $cache->update_banned(); + + $mybbgroups = $mybb->user['usergroup']; + if($mybb->user['additionalgroups']) + { + $mybbgroups .= ','.$mybb->user['additionalgroups']; + } + } + else if(!empty($mybb->user['bandate']) && (empty($mybb->user['banlifted']) || !empty($mybb->user['banlifted']) && $mybb->user['banlifted'] > $time)) + { + $mybbgroups = $mybb->user['usergroup']; + } + else + { + // Gather a full permission set for this user and the groups they are in. + $mybbgroups = $mybb->user['usergroup']; + if($mybb->user['additionalgroups']) + { + $mybbgroups .= ','.$mybb->user['additionalgroups']; + } + } + + $mybb->usergroup = usergroup_permissions($mybbgroups); + if(!$mybb->user['displaygroup']) + { + $mybb->user['displaygroup'] = $mybb->user['usergroup']; + } + + $mydisplaygroup = usergroup_displaygroup($mybb->user['displaygroup']); + if(is_array($mydisplaygroup)) + { + $mybb->usergroup = array_merge($mybb->usergroup, $mydisplaygroup); + } + + if(!$mybb->user['usertitle']) + { + $mybb->user['usertitle'] = $mybb->usergroup['usertitle']; + } + + // Update or create the session. + if(!defined("NO_ONLINE")) + { + if(!empty($this->sid)) + { + $this->update_session($this->sid, $mybb->user['uid']); + } + else + { + $this->create_session($mybb->user['uid']); + } + } + return true; + } + + /** + * Load a guest user. + * + */ + function load_guest() + { + global $mybb, $time, $db, $lang; + + // Set up some defaults + $time = TIME_NOW; + $mybb->user['usergroup'] = 1; + $mybb->user['username'] = ''; + $mybb->user['uid'] = 0; + $mybbgroups = 1; + $mybb->user['displaygroup'] = 1; + + // Has this user visited before? Lastvisit need updating? + if(isset($mybb->cookies['mybb']['lastvisit'])) + { + if(!isset($mybb->cookies['mybb']['lastactive'])) + { + $mybb->user['lastactive'] = $time; + $mybb->cookies['mybb']['lastactive'] = $mybb->user['lastactive']; + } + else + { + $mybb->user['lastactive'] = (int)$mybb->cookies['mybb']['lastactive']; + } + if($time - $mybb->cookies['mybb']['lastactive'] > 900) + { + my_setcookie("mybb[lastvisit]", $mybb->user['lastactive']); + $mybb->user['lastvisit'] = $mybb->user['lastactive']; + } + else + { + $mybb->user['lastvisit'] = (int)$mybb->cookies['mybb']['lastactive']; + } + } + + // No last visit cookie, create one. + else + { + my_setcookie("mybb[lastvisit]", $time); + $mybb->user['lastvisit'] = $time; + } + + // Update last active cookie. + my_setcookie("mybb[lastactive]", $time); + + // Gather a full permission set for this guest + $mybb->usergroup = usergroup_permissions($mybbgroups); + $mydisplaygroup = usergroup_displaygroup($mybb->user['displaygroup']); + + $mybb->usergroup = array_merge($mybb->usergroup, $mydisplaygroup); + + // Update the online data. + if(!defined("NO_ONLINE")) + { + if(!empty($this->sid)) + { + $this->update_session($this->sid); + } + else + { + $this->create_session(); + } + } + } + + /** + * Load a search engine spider. + * + * @param int The ID of the search engine spider + */ + function load_spider($spider_id) + { + global $mybb, $time, $db, $lang; + + // Fetch the spider preferences from the database + $query = $db->simple_select("spiders", "*", "sid='{$spider_id}'"); + $spider = $db->fetch_array($query); + + // Set up some defaults + $time = TIME_NOW; + $this->is_spider = true; + if($spider['usergroup']) + { + $mybb->user['usergroup'] = $spider['usergroup']; + } + else + { + $mybb->user['usergroup'] = 1; + } + $mybb->user['username'] = ''; + $mybb->user['uid'] = 0; + $mybb->user['displaygroup'] = $mybb->user['usergroup']; + + // Set spider language + if($spider['language'] && $lang->language_exists($spider['language'])) + { + $mybb->settings['bblanguage'] = $spider['language']; + } + + // Set spider theme + if($spider['theme']) + { + $mybb->user['style'] = $spider['theme']; + } + + // Gather a full permission set for this spider. + $mybb->usergroup = usergroup_permissions($mybb->user['usergroup']); + $mydisplaygroup = usergroup_displaygroup($mybb->user['displaygroup']); + $mybb->usergroup = array_merge($mybb->usergroup, $mydisplaygroup); + + // Update spider last minute (only do so on two minute intervals - decrease load for quick spiders) + if($spider['lastvisit'] < TIME_NOW-120) + { + $updated_spider = array( + "lastvisit" => TIME_NOW + ); + $db->update_query("spiders", $updated_spider, "sid='{$spider_id}'"); + } + + // Update the online data. + if(!defined("NO_ONLINE")) + { + $this->sid = "bot=".$spider_id; + $this->create_session(); + } + + } + + /** + * Update a user session. + * + * @param int The session id. + * @param int The user id. + */ + function update_session($sid, $uid='') + { + global $db; + + // Find out what the special locations are. + $speciallocs = $this->get_special_locations(); + if($uid) + { + $onlinedata['uid'] = $uid; + } + else + { + $onlinedata['uid'] = 0; + } + $onlinedata['time'] = TIME_NOW; + $onlinedata['location'] = $db->escape_string(get_current_location()); + $useragent = $this->useragent; + if(my_strlen($useragent) > 100) + { + $useragent = my_substr($useragent, 0, 100); + } + $onlinedata['useragent'] = $db->escape_string($useragent); + $onlinedata['location1'] = (int)$speciallocs['1']; + $onlinedata['location2'] = (int)$speciallocs['2']; + $onlinedata['nopermission'] = 0; + $sid = $db->escape_string($sid); + + $db->update_query("sessions", $onlinedata, "sid='{$sid}'"); + } + + /** + * Create a new session. + * + * @param int The user id to bind the session to. + */ + function create_session($uid=0) + { + global $db; + $speciallocs = $this->get_special_locations(); + + // If there is a proper uid, delete by uid. + if($uid > 0) + { + $db->delete_query("sessions", "uid='{$uid}'"); + $onlinedata['uid'] = $uid; + } + // Is a spider - delete all other spider references + else if($this->is_spider == true) + { + $db->delete_query("sessions", "sid='{$this->sid}'"); + } + // Else delete by ip. + else + { + $db->delete_query("sessions", "ip=".$db->escape_binary($this->packedip)); + $onlinedata['uid'] = 0; + } + + // If the user is a search enginge spider, ... + if($this->is_spider == true) + { + $onlinedata['sid'] = $this->sid; + } + else + { + $onlinedata['sid'] = md5(uniqid(microtime(true), true)); + } + $onlinedata['time'] = TIME_NOW; + $onlinedata['ip'] = $db->escape_binary($this->packedip); + $onlinedata['location'] = $db->escape_string(get_current_location()); + $useragent = $this->useragent; + if(my_strlen($useragent) > 100) + { + $useragent = my_substr($useragent, 0, 100); + } + $onlinedata['useragent'] = $db->escape_string($useragent); + $onlinedata['location1'] = (int)$speciallocs['1']; + $onlinedata['location2'] = (int)$speciallocs['2']; + $onlinedata['nopermission'] = 0; + $db->replace_query("sessions", $onlinedata, "sid", false); + $this->sid = $onlinedata['sid']; + $this->uid = $onlinedata['uid']; + } + + /** + * Find out the special locations. + * + * @return array Special locations array. + */ + function get_special_locations() + { + global $mybb; + $array = array('1' => '', '2' => ''); + if(preg_match("#forumdisplay.php#", $_SERVER['PHP_SELF']) && $mybb->get_input('fid', 1) > 0) + { + $array[1] = $mybb->get_input('fid', 1); + $array[2] = ''; + } + elseif(preg_match("#showthread.php#", $_SERVER['PHP_SELF'])) + { + global $db; + + if($mybb->get_input('tid', 1) > 0) + { + $array[2] = $mybb->get_input('tid', 1); + } + + // If there is no tid but a pid, trick the system into thinking there was a tid anyway. + elseif(isset($mybb->input['pid']) && !empty($mybb->input['pid'])) + { + $options = array( + "limit" => 1 + ); + $query = $db->simple_select("posts", "tid", "pid=".$mybb->get_input('pid', 1), $options); + $post = $db->fetch_array($query); + $array[2] = $post['tid']; + } + + $thread = get_thread($array[2]); + $array[1] = $thread['fid']; + } + return $array; + } +} diff --git a/Upload/inc/class_stopforumspamchecker.php b/Upload/inc/class_stopforumspamchecker.php new file mode 100644 index 0000000..61086aa --- /dev/null +++ b/Upload/inc/class_stopforumspamchecker.php @@ -0,0 +1,160 @@ +plugins = $plugins; + $this->min_weighting_before_spam = (double)$min_weighting_before_spam; + $this->check_usernames = (bool)$check_usernames; + $this->check_emails = (bool)$check_emails; + $this->check_ips = (bool)$check_ips; + $this->log_blocks = (bool)$log_blocks; + } + + /** + * Check a user against the 3rd party service to determine whether they are a spammer. + * + * @param string $username The username of the user to check. + * @param string $email The email address of the user to check. + * @param string $ip_address The IP address sof the user to check. + * @return bool Whether the user is considered a spammer or not. + * @throws Exception Thrown when there's an error fetching from the StopForumSpam API or when the data cannot be decoded. + */ + public function is_user_a_spammer($username = '', $email = '', $ip_address = '') + { + $is_spammer = false; + $confidence = 0; + + if(filter_var($email, FILTER_VALIDATE_EMAIL) && filter_var($ip_address, FILTER_VALIDATE_IP)) // Calls to the API with invalid email/ip formats cause issues + { + $username_encoded = urlencode($username); + $email_encoded = urlencode($email); + + $check_url = sprintf(self::STOP_FORUM_SPAM_API_URL_FORMAT, $username_encoded, $email_encoded, $ip_address); + + $result = fetch_remote_file($check_url); + + if($result !== false) + { + $result_json = @json_decode($result); + + if($result_json != null && !isset($result_json->error)) + { + if($this->check_usernames && $result_json->username->appears) + { + $confidence += $result_json->username->confidence; + } + + if($this->check_emails && $result_json->email->appears) + { + $confidence += $result_json->email->confidence; + } + + if($this->check_ips && $result_json->ip->appears) + { + $confidence += $result_json->ip->confidence; + } + + if($confidence > $this->min_weighting_before_spam) + { + $is_spammer = true; + } + } + else + { + throw new Exception('stopforumspam_error_decoding'); + } + } + else + { + throw new Exception('stopforumspam_error_retrieving'); + } + } + + if($this->plugins) + { + $params = array( + 'username' => &$username, + 'email' => &$email, + 'ip_address' => &$ip_address, + 'is_spammer' => &$is_spammer, + 'confidence' => &$confidence, + ); + + $this->plugins->run_hooks('stopforumspam_check_spammer_pre_return', $params); + } + + if($this->log_blocks && $is_spammer) + { + log_spam_block( + $username, $email, $ip_address, array( + 'confidence' => (double)$confidence, + ) + ); + } + + return $is_spammer; + } +} diff --git a/Upload/inc/class_templates.php b/Upload/inc/class_templates.php new file mode 100644 index 0000000..48dd410 --- /dev/null +++ b/Upload/inc/class_templates.php @@ -0,0 +1,160 @@ + $title) + { + $sql .= " ,'".trim($title)."'"; + } + + $query = $db->simple_select("templates", "title,template", "title IN (''$sql) AND sid IN ('-2','-1','".$theme['templateset']."')", array('order_by' => 'sid', 'order_dir' => 'asc')); + while($template = $db->fetch_array($query)) + { + $this->cache[$template['title']] = $template['template']; + } + } + + /** + * Gets templates. + * + * @param string The title of the template to get. + * @param boolean True if template contents must be escaped, false if not. + * @param boolean True to output HTML comments, false to not output. + * @return string The template HTML. + */ + function get($title, $eslashes=1, $htmlcomments=1) + { + global $db, $theme, $mybb; + + // + // DEVELOPMENT MODE + // + if($mybb->dev_mode == 1) + { + $template = $this->dev_get($title); + if($template !== false) + { + $this->cache[$title] = $template; + } + } + + if(!isset($this->cache[$title])) + { + // Only load master and global templates if template is needed in Admin CP + if(empty($theme['templateset'])) + { + $query = $db->simple_select("templates", "template", "title='".$db->escape_string($title)."' AND sid IN ('-2','-1')", array('order_by' => 'sid', 'order_dir' => 'DESC', 'limit' => 1)); + } + else + { + $query = $db->simple_select("templates", "template", "title='".$db->escape_string($title)."' AND sid IN ('-2','-1','".$theme['templateset']."')", array('order_by' => 'sid', 'order_dir' => 'DESC', 'limit' => 1)); + } + + $gettemplate = $db->fetch_array($query); + if($mybb->debug_mode) + { + $this->uncached_templates[$title] = $title; + } + + if(!$gettemplate) + { + $gettemplate['template'] = ""; + } + + $this->cache[$title] = $gettemplate['template']; + } + $template = $this->cache[$title]; + + if($htmlcomments) + { + if($mybb->settings['tplhtmlcomments'] == 1) + { + $template = "\n{$template}\n"; + } + else + { + $template = "\n{$template}\n"; + } + } + + if($eslashes) + { + $template = str_replace("\\'", "'", addslashes($template)); + } + return $template; + } + + /** + * Prepare a template for rendering to a variable. + * + * @param string The name of the template to get. + * @param boolean True if template contents must be escaped, false if not. + * @param boolean True to output HTML comments, false to not output. + * @return string The eval()-ready PHP code for rendering the template + */ + function render($template, $eslashes=true, $htmlcomments=true) + { + return 'return "'.$this->get($template, $eslashes, $htmlcomments).'";'; + } + + /** + * Fetch a template directly from the install/resources/mybb_theme.xml directory if it exists (DEVELOPMENT MODE) + */ + function dev_get($title) + { + static $template_xml; + + if(!$template_xml) + { + if(@file_exists(MYBB_ROOT."install/resources/mybb_theme.xml")) + { + $template_xml = simplexml_load_file(MYBB_ROOT."install/resources/mybb_theme.xml"); + } + else + { + return false; + } + } + $res = $template_xml->xpath("//template[@name='{$title}']"); + return $res[0]; + } +} diff --git a/Upload/inc/class_timers.php b/Upload/inc/class_timers.php new file mode 100644 index 0000000..4894291 --- /dev/null +++ b/Upload/inc/class_timers.php @@ -0,0 +1,132 @@ +add(); + } + + /** + * Starts the timer. + * + */ + function add() + { + if(!$this->start) + { + $this->start = microtime(true); + } + } + + /** + * Gets the time for which the timer has run up until this point. + * + * @return string|boolean The formatted time up until now or false when timer is no longer running. + */ + function getTime() + { + if($this->end) // timer has been stopped + { + return $this->totaltime; + } + elseif($this->start && !$this->end) // timer is still going + { + $currenttime = microtime(true); + $totaltime = $currenttime - $this->start; + return $this->format($totaltime); + } + else + { + return false; + } + } + + /** + * Stops the timer. + * + * @return string The formatted total time. + */ + function stop() + { + if($this->start) + { + $this->end = microtime(true); + $totaltime = $this->end - $this->start; + $this->totaltime = $totaltime; + $this->formatted = $this->format($totaltime); + return $this->formatted; + } + } + + /** + * Removes the timer. + * + */ + function remove() + { + $this->name = ""; + $this->start = ""; + $this->end = ""; + $this->totaltime = ""; + $this->formatted = ""; + } + + /** + * Formats the timer time in a pretty way. + * + * @param string The time string. + * @return The formatted time string. + */ + function format($string) + { + return number_format($string, 7); + } +} diff --git a/Upload/inc/class_xml.php b/Upload/inc/class_xml.php new file mode 100644 index 0000000..22ed2e3 --- /dev/null +++ b/Upload/inc/class_xml.php @@ -0,0 +1,168 @@ +data = $data; + } + + /** + * Build a tree based structure based from the parsed data + * + * @return array The tree based structure + */ + function get_tree() + { + $parser = xml_parser_create(); + xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0); + xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0); + if(!xml_parse_into_struct($parser, $this->data, $vals, $index)) + { + return false; + } + + $i = -1; + return $this->get_children($vals, $i); + } + + /** + * Private: Build a completed tag by fetching all child nodes and attributes + * + * @param array Array of values from the current tag + * @param array Array of child nodes + * @param int Internal counter + * @param string Type of tag. Complete is a single line tag with attributes + * @return array Completed tag array + */ + function build_tag($thisvals, $vals, &$i, $type) + { + $tag = array('tag' => $thisvals['tag']); + + if(isset($thisvals['attributes'])) + { + $tag['attributes'] = $thisvals['attributes']; + } + + if($type == "complete") + { + if(isset($thisvals['value'])) + { + $tag['value'] = $thisvals['value']; + } + } + else + { + $tag = array_merge($tag, $this->get_children($vals, $i)); + } + return $tag; + } + + /** + * Fetch the children for from a specific node array + * + * @param array Array of children + * @param int Internal counter + * @return array Array of child nodes + */ + function get_children($vals, &$i) + { + $children = array(); + + if($i > -1 && isset($vals[$i]['value'])) + { + $children['value'] = $vals[$i]['value']; + } + + while(++$i < count($vals)) + { + $type = $vals[$i]['type']; + if($type == "cdata") + { + $children['value'] .= $vals[$i]['value']; + } + elseif($type == "complete" || $type == "open") + { + $tag = $this->build_tag($vals[$i], $vals, $i, $type); + if($this->index_numeric) + { + $tag['tag'] = $vals[$i]['tag']; + $children[] = $tag; + } + else + { + $children[$tag['tag']][] = $tag; + } + } + else if($type == "close") + { + break; + } + } + if($this->collapse_dups) + { + foreach($children as $key => $value) + { + if(is_array($value) && (count($value) == 1)) + { + $children[$key] = $value[0]; + } + } + } + return $children; + } +} + +/** + * Kill off unnecessary tags and return a clean array of XML data + * + * @param array Array of parsed XML data + * @return array Cleaned array of XML data + */ +function kill_tags($array) +{ + foreach($array as $key => $val) + { + if($key == "tag" || $key == "value") + { + unset($array[$key]); + } + else if(is_array($val)) + { + // kill any nested tag or value indexes + $array[$key] = kill_tags($val); + + // if the array no longer has any key/val sets + // and therefore is at the deepest level, then + // store the string value + if(count($array[$key]) <= 0) + { + $array[$key] = $val['value']; + } + } + } + + return $array; +} diff --git a/Upload/inc/config.default.php b/Upload/inc/config.default.php new file mode 100644 index 0000000..e69de29 diff --git a/Upload/inc/datahandler.php b/Upload/inc/datahandler.php new file mode 100644 index 0000000..e050f92 --- /dev/null +++ b/Upload/inc/datahandler.php @@ -0,0 +1,215 @@ +method = $method; + } + + /** + * Sets the data to be used for the data handler + * + * @param array The data. + */ + function set_data($data) + { + if(!is_array($data)) + { + return false; + } + $this->data = $data; + return true; + } + + /** + * Add an error to the error array. + * + * @param string The error name. + */ + function set_error($error, $data='') + { + $this->errors[$error] = array( + "error_code" => $error, + "data" => $data + ); + } + + /** + * Returns the error(s) that occurred when handling data. + * + * @return string|array An array of errors. + */ + function get_errors() + { + return $this->errors; + } + + /** + * Returns the error(s) that occurred when handling data + * in a format that MyBB can handle. + * + * @return An array of errors in a MyBB format. + */ + function get_friendly_errors() + { + global $lang; + + // Load the language pack we need + if($this->language_file) + { + $lang->load($this->language_file, true); + } + // Prefix all the error codes with the language prefix. + $errors = array(); + foreach($this->errors as $error) + { + $lang_string = $this->language_prefix.'_'.$error['error_code']; + if(!$lang->$lang_string) + { + $errors[] = $error['error_code']; + continue; + } + + if(!empty($error['data']) && !is_array($error['data'])) + { + $error['data'] = array($error['data']); + } + + if(is_array($error['data'])) + { + array_unshift($error['data'], $lang->$lang_string); + $errors[] = call_user_func_array(array($lang, "sprintf"), $error['data']); + } + else + { + $errors[] = $lang->$lang_string; + } + } + return $errors; + } + + /** + * Sets whether or not we are done validating. + * + * @param boolean True when done, false when not done. + */ + function set_validated($validated = true) + { + $this->is_validated = $validated; + } + + /** + * Returns whether or not we are done validating. + * + * @return boolean True when done, false when not done. + */ + function get_validated() + { + if($this->is_validated == true) + { + return true; + } + else + { + return false; + } + } + + /** + * Verifies if yes/no options haven't been modified. + * + * @param array The user options array. + * @param string The specific option to check. + * @param string Optionally specify if the default should be used. + */ + function verify_yesno_option(&$options, $option, $default=1) + { + if($this->method == "insert" || array_key_exists($option, $options)) + { + if(isset($options[$option]) && $options[$option] != $default && $options[$option] != "") + { + if($default == 1) + { + $options[$option] = 0; + } + else + { + $options[$option] = 1; + } + } + else if(@array_key_exists($option, $options) && $options[$option] == '') + { + $options[$option] = 0; + } + else + { + $options[$option] = $default; + } + } + } +} diff --git a/Upload/inc/datahandlers/event.php b/Upload/inc/datahandlers/event.php new file mode 100644 index 0000000..77174e9 --- /dev/null +++ b/Upload/inc/datahandlers/event.php @@ -0,0 +1,635 @@ +
    Please make sure IN_MYBB is defined."); +} + +/** + * Event handling class, provides common structure to handle event data. + * + */ +class EventDataHandler extends DataHandler +{ + /** + * The language file used in the data handler. + * + * @var string + */ + public $language_file = 'datahandler_event'; + + /** + * The prefix for the language variables used in the data handler. + * + * @var string + */ + public $language_prefix = 'eventdata'; + + /** + * Array of data inserted in to an event. + * + * @var array + */ + public $event_insert_data = array(); + + /** + * Array of data used to update an event. + * + * @var array + */ + public $event_update_data = array(); + + /** + * Event ID currently being manipulated by the datahandlers. + */ + public $eid = 0; + + /** + * Values to be returned after inserting/updating an event. + * + * @var array + */ + public $return_values = array(); + + /** + * Verifies if an event name is valid or not and attempts to fix it + * + * @return boolean True if valid, false if invalid. + */ + function verify_name() + { + $name = &$this->data['name']; + $name = trim($name); + if(!$name) + { + $this->set_error("missing_name"); + return false; + } + return true; + } + + /** + * Verifies if an event description is valid or not and attempts to fix it + * + * @return boolean True if valid, false if invalid. + */ + function verify_description() + { + $description = &$this->data['description']; + $description = trim($description); + if(!$description) + { + $this->set_error("missing_description"); + return false; + } + return true; + } + + /** + * Verifies if an event date is valid or not and attempts to fix it + * + * @return boolean True if valid, false if invalid. + */ + function verify_date() + { + $event = &$this->data; + + // All types of events require a start date + if(!$event['start_date']['day'] || !$event['start_date']['month'] || !$event['start_date']['year']) + { + $this->set_error("invalid_start_date"); + return false; + } + + $event['start_date']['day'] = (int)$event['start_date']['day']; + $event['start_date']['month'] = (int)$event['start_date']['month']; + $event['start_date']['year'] = (int)$event['start_date']['year']; + + if($event['start_date']['day'] > date("t", mktime(0, 0, 0, $event['start_date']['month'], 1, $event['start_date']['year']))) + { + $this->set_error("invalid_start_date"); + return false; + } + + // Calendar events can only be within the next 5 years + if($event['start_date']['year'] > date("Y") + 5) + { + $this->set_error("invalid_start_year"); + return false; + } + + //Check to see if the month is within 1 and 12 + if($event['start_date']['month'] > 12 || $event['start_date']['month'] < 1) + { + $this->set_error("invalid_start_month"); + return false; + } + + // For ranged events, we check the end date & times too + if($event['type'] == "ranged") + { + if(!$event['end_date']['day'] || !$event['end_date']['month'] || !$event['end_date']['year']) + { + $this->set_error("invalid_end_date"); + return false; + } + + $event['end_date']['day'] = (int)$event['end_date']['day']; + $event['end_date']['month'] = (int)$event['end_date']['month']; + $event['end_date']['year'] = (int)$event['end_date']['year']; + + if($event['end_date']['day'] > date("t", mktime(0, 0, 0, $event['end_date']['month'], 1, $event['end_date']['year']))) + { + $this->set_error("invalid_end_date"); + return false; + } + + // Calendar events can only be within the next 5 years + if($event['end_date']['year'] > date("Y") + 5) + { + $this->set_error("invalid_end_year"); + return false; + } + + //Check to see if the month is within 1 and 12 + if($event['end_date']['month'] > 12 || $event['end_date']['month'] < 1) + { + $this->set_error("invalid_end_month"); + return false; + } + + // Validate time input + if($event['start_date']['time'] || $event['end_date']['time']) + { + if(($event['start_date']['time'] && !$event['end_date']['time']) || ($event['end_date']['time'] && !$event['start_date']['time'])) + { + $this->set_error("cant_specify_one_time"); + return false; + } + + // Begin start time validation + $start_time = $this->verify_time($event['start_date']['time']); + if(!is_array($start_time)) + { + $this->set_error("start_time_invalid"); + return false; + } + + // End time validation + $end_time = $this->verify_time($event['end_date']['time']); + if(!is_array($end_time)) + { + $this->set_error("end_time_invalid"); + return false; + } + $event['usingtime'] = 1; + } + else + { + $start_time = array("hour" => 0, "min" => 0); + $end_time = array("hour" => 23, "min" => 59); + $event['usingtime'] = 0; + } + } + + if(array_key_exists('timezone', $event)) + { + $event['timezone'] = (float)$event['timezone']; + if($event['timezone'] > 12 || $event['timezone'] < -12) + { + $this->set_error("invalid_timezone"); + return false; + } + $start_time['hour'] -= $event['timezone']; + $end_time['hour'] -= $event['timezone']; + } + + if(!isset($start_time)) + { + $start_time = array("hour" => 0, "min" => 0); + } + + $start_timestamp = gmmktime($start_time['hour'], $start_time['min'], 0, $event['start_date']['month'], $event['start_date']['day'], $event['start_date']['year']); + + if($event['type'] == "ranged") + { + $end_timestamp = gmmktime($end_time['hour'], $end_time['min'], 0, $event['end_date']['month'], $event['end_date']['day'], $event['end_date']['year']); + + if($end_timestamp <= $start_timestamp) + { + $this->set_error("end_in_past"); + return false; + } + } + + if(!isset($end_timestamp)) + { + $end_timestamp = 0; + } + + // Save our time stamps for saving + $event['starttime'] = $start_timestamp; + $event['endtime'] = $end_timestamp; + + return true; + } + + function verify_time($time) + { + preg_match('#^(0?[1-9]|1[012])\s?([:\.]?)\s?([0-5][0-9])?(\s?[ap]m)|([01][0-9]|2[0-3])\s?([:\.])\s?([0-5][0-9])$#i', $time, $matches); + if(count($matches) == 0) + { + return false; + } + + // 24h time + if(count($matches) == 8) + { + $hour = $matches[5]; + $min = $matches[7]; + } + // 12 hour time + else + { + $hour = $matches[1]; + $min = (int)$matches[3]; + $matches[4] = trim($matches[4]); + if(my_strtolower($matches[4]) == "pm" && $hour != 12) + { + $hour += 12; + } + else if(my_strtolower($matches[4]) == "am" && $hour == 12) + { + $hour = 0; + } + } + return array("hour" => $hour, "min" => $min); + } + + function verify_repeats() + { + global $mybb; + $event = &$this->data; + + if(!is_array($event['repeats']) || !$event['repeats']['repeats']) + { + return true; + } + + if(!$event['endtime']) + { + $this->set_error("only_ranged_events_repeat"); + return false; + } + + switch($event['repeats']['repeats']) + { + case 1: + $event['repeats']['days'] = (int)$event['repeats']['days']; + if($event['repeats']['days'] <= 0) + { + $this->set_error("invalid_repeat_day_interval"); + return false; + } + case 2: + break; + case 3: + $event['repeats']['weeks'] = (int)$event['repeats']['weeks']; + if($event['repeats']['weeks'] <= 0) + { + $this->set_error("invalid_repeat_week_interval"); + return false; + } + if(count($event['repeats']['days']) == 0) + { + $this->set_error("invalid_repeat_weekly_days"); + return false; + } + asort($event['repeats']['days']); + break; + case 4: + if($event['repeats']['day']) + { + $event['repeats']['day'] = (int)$event['repeats']['day']; + if($event['repeats']['day'] <= 0 || $event['repeats']['day'] > 31) + { + $this->set_error("invalid_repeat_day_interval"); + return false; + } + } + else + { + if($event['repeats']['occurance'] != "last") + { + $event['repeats']['occurance'] = (int)$event['repeats']['occurance']; + } + $event['repeats']['weekday'] = (int)$event['repeats']['weekday']; + } + $event['repeats']['months'] = (int)$event['repeats']['months']; + if($event['repeats']['months'] <= 0 || $event['repeats']['months'] > 12) + { + $this->set_error("invalid_repeat_month_interval"); + return false; + } + break; + case 5: + if($event['repeats']['day']) + { + $event['repeats']['day'] = (int)$event['repeats']['day']; + if($event['repeats']['day'] <= 0 || $event['repeats']['day'] > 31) + { + $this->set_error("invalid_repeat_day_interval"); + return false; + } + } + else + { + if($event['repeats']['occurance'] != "last") + { + $event['repeats']['occurance'] = (int)$event['repeats']['occurance']; + } + $event['repeats']['weekday'] = (int)$event['repeats']['weekday']; + } + $event['repeats']['month'] = (int)$event['repeats']['month']; + if($event['repeats']['month'] <= 0 || $event['repeats']['month'] > 12) + { + $this->set_error("invalid_repeat_month_interval"); + return false; + } + $event['repeats']['years'] = (int)$event['repeats']['years']; + if($event['repeats']['years'] <= 0 || $event['repeats']['years'] > 4) + { + $this->set_error("invalid_repeat_year_interval"); + return false; + } + break; + default: + $event['repeats'] = array(); + } + require_once MYBB_ROOT."inc/functions_calendar.php"; + $event['starttime_user'] = $event['starttime']; + $event['endtime_user'] = $event['endtime']; + $next_occurance = fetch_next_occurance($event, array('start' => $event['starttime'], 'end' => $event['endtime']), $event['starttime'], true); + if($next_occurance > $event['endtime']) + { + $this->set_error("event_wont_occur"); + return false; + } + return true; + } + + /** + * Validate an event. + * + * @param array The event data array. + */ + function validate_event() + { + global $plugins; + + $event = &$this->data; + + if($this->method == "insert" || array_key_exists('name', $event)) + { + $this->verify_name(); + } + + if($this->method == "insert" || array_key_exists('description', $event)) + { + $this->verify_description(); + } + + if($this->method == "insert" || array_key_exists('start_date', $event) || array_key_exists('end_date', $event)) + { + $this->verify_date(); + } + + if(($this->method == "insert" && $event['endtime']) || array_key_exists('repeats', $event)) + { + $this->verify_repeats(); + } + + $plugins->run_hooks("datahandler_event_validate", $this); + + // We are done validating, return. + $this->set_validated(true); + if(count($this->get_errors()) > 0) + { + return false; + } + else + { + return true; + } + } + + /** + * Insert an event into the database. + * + * @param array The array of event data. + * @return array Array of new event details, eid and private. + */ + function insert_event() + { + global $db, $mybb, $plugins; + + // Yes, validating is required. + if(!$this->get_validated()) + { + die("The event needs to be validated before inserting it into the DB."); + } + + if(count($this->get_errors()) > 0) + { + die("The event is not valid."); + } + + $event = &$this->data; + + $query = $db->simple_select("calendars", "*", "cid='".(int)$event['cid']."'"); + $calendar_moderation = $db->fetch_field($query, "moderation"); + if($calendar_moderation == 1 && (int)$event['private'] != 1) + { + $visible = 0; + if($event['uid'] == $mybb->user['uid']) + { + $calendar_permissions = get_calendar_permissions($event['cid']); + if($calendar_permissions['canbypasseventmod'] == 1) + { + $visible = 1; + } + } + } + else + { + $visible = 1; + } + + // Prepare an array for insertion into the database. + $this->event_insert_data = array( + 'cid' => (int)$event['cid'], + 'uid' => (int)$event['uid'], + 'name' => $db->escape_string($event['name']), + 'description' => $db->escape_string($event['description']), + 'visible' => $visible, + 'private' => (int)$event['private'], + 'dateline' => TIME_NOW, + 'starttime' => (int)$event['starttime'], + 'endtime' => (int)$event['endtime'] + ); + + if(isset($event['timezone'])) + { + $this->event_insert_data['timezone'] = $db->escape_string((float)$event['timezone']); + } + + if(isset($event['ignoretimezone'])) + { + $this->event_insert_data['ignoretimezone'] = (int)$event['ignoretimezone']; + } + + if(isset($event['usingtime'])) + { + $this->event_insert_data['usingtime'] = (int)$event['usingtime']; + } + + if(isset($event['repeats'])) + { + $this->event_insert_data['repeats'] = $db->escape_string(serialize($event['repeats'])); + } + else + { + $this->event_insert_data['repeats'] = ''; + } + + $plugins->run_hooks("datahandler_event_insert", $this); + + $this->eid = $db->insert_query("events", $this->event_insert_data); + + // Return the event's eid and whether or not it is private. + $this->return_values = array( + 'eid' => $this->eid, + 'private' => $event['private'], + 'visible' => $visible + ); + + $plugins->run_hooks("datahandler_event_insert_end", $this); + + return $this->return_values; + } + + /** + * Updates an event that is already in the database. + * + * @param array The event data array. + */ + function update_event() + { + global $db, $plugins; + + // Yes, validating is required. + if(!$this->get_validated()) + { + die("The event needs to be validated before inserting it into the DB."); + } + + if(count($this->get_errors()) > 0) + { + die("The event is not valid."); + } + + $event = &$this->data; + + $this->eid = $event['eid']; + + if(isset($event['cid'])) + { + $this->event_update_data['cid'] = $db->escape_string($event['cid']); + } + + if(isset($event['name'])) + { + $this->event_update_data['name'] = $db->escape_string($event['name']); + } + + if(isset($event['description'])) + { + $this->event_update_data['description'] = $db->escape_string($event['description']); + } + + if(isset($event['starttime'])) + { + $this->event_update_data['starttime'] = (int)$event['starttime']; + $this->event_update_data['usingtime'] = (int)$event['usingtime']; + } + + if(isset($event['endtime'])) + { + $this->event_update_data['endtime'] = (int)$event['endtime']; + $this->event_update_data['usingtime'] = (int)$event['usingtime']; + } + else + { + $this->event_update_data['endtime'] = 0; + $this->event_update_data['usingtime'] = 0; + } + + if(isset($event['repeats'])) + { + if(!empty($event['repeats'])) + { + $event['repeats'] = serialize($event['repeats']); + } + $this->event_update_data['repeats'] = $db->escape_string($event['repeats']); + } + + if(isset($event['timezone'])) + { + $this->event_update_data['timezone'] = $db->escape_string((float)$event['timezone']); + } + + if(isset($event['ignoretimezone'])) + { + $this->event_update_data['ignoretimezone'] = (int)$event['ignoretimezone']; + } + + if(isset($event['private'])) + { + $this->event_update_data['private'] = (int)$event['private']; + } + + if(isset($event['visible'])) + { + $this->event_update_data['visible'] = $db->escape_string($event['visible']); + } + + if(isset($event['uid'])) + { + $this->event_update_data['uid'] = (int)$event['uid']; + } + + $plugins->run_hooks("datahandler_event_update", $this); + + $db->update_query("events", $this->event_update_data, "eid='".(int)$event['eid']."'"); + + // Return the event's eid and whether or not it is private. + $this->return_values = array( + 'eid' => $event['eid'], + 'private' => $event['private'] + ); + + $plugins->run_hooks("datahandler_event_update_end", $this); + + return $this->return_values; + } +} + diff --git a/Upload/inc/datahandlers/index.html b/Upload/inc/datahandlers/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/datahandlers/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/datahandlers/login.php b/Upload/inc/datahandlers/login.php new file mode 100644 index 0000000..9e5a180 --- /dev/null +++ b/Upload/inc/datahandlers/login.php @@ -0,0 +1,302 @@ +
    Please make sure IN_MYBB is defined."); +} + +/** + * Login handling class, provides common structure to handle login events. + * + */ +class LoginDataHandler extends DataHandler +{ + /** + * The language file used in the data handler. + * + * @var string + */ + public $language_file = 'datahandler_login'; + + /** + * The prefix for the language variables used in the data handler. + * + * @var string + */ + public $language_prefix = 'logindata'; + + /** + * Array of data used via login events. + * + * @var array + */ + public $login_data = array(); + + public $captcha_verified = true; + + private $captcha = false; + + public $username_method = null; + + function verify_attempts($check_captcha = 0) + { + global $db, $mybb; + + $user = &$this->data; + + if($check_captcha) + { + if(!isset($mybb->cookies['loginattempts'])) + { + $mybb->cookies['loginattempts'] = 0; + } + if($mybb->settings['failedcaptchalogincount'] > 0 && ($user['loginattempts'] > $mybb->settings['failedcaptchalogincount'] || (int)$mybb->cookies['loginattempts'] > $mybb->settings['failedcaptchalogincount'])) + { + $this->captcha_verified = false; + $this->verify_captcha(); + } + } + } + + function verify_captcha() + { + global $db, $mybb; + + $user = &$this->data; + + if($user['imagestring'] || $mybb->settings['captchaimage'] != 1) + { + // Check their current captcha input - if correct, hide the captcha input area + require_once MYBB_ROOT.'inc/class_captcha.php'; + $this->captcha = new captcha; + + if($this->captcha->validate_captcha() == false) + { + // CAPTCHA validation failed + foreach($this->captcha->get_errors() as $error) + { + $this->set_error($error); + } + return false; + } + else + { + $this->captcha_verified = true; + return true; + } + } + else if($mybb->input['quick_login'] == 1 && $mybb->input['quick_password'] && $mybb->input['quick_username']) + { + $this->set_error('regimagerequired'); + return false; + } + else + { + $this->set_error('regimageinvalid'); + return false; + } + } + + function verify_username() + { + $this->get_login_data(); + + if(!$this->login_data['uid']) + { + $this->invalid_combination(); + return false; + } + } + + function verify_password($strict = true) + { + global $db, $mybb; + + $this->get_login_data(); + + if(empty($this->login_data['username'])) + { + // Username must be validated to apply a password to + $this->invalid_combination(); + return false; + } + + $user = &$this->data; + + $password = md5($user['password']); + + if(!$this->login_data['uid'] || $this->login_data['uid'] && !$this->login_data['salt'] && $strict == false) + { + $this->invalid_combination(); + } + + if($strict == true) + { + if(!$this->login_data['salt']) + { + // Generate a salt for this user and assume the password stored in db is a plain md5 password + $this->login_data['salt'] = generate_salt(); + $this->login_data['password'] = salt_password($this->login_data['password'], $this->login_data['salt']); + + $sql_array = array( + "salt" => $this->login_data['salt'], + "password" => $this->login_data['password'] + ); + + $db->update_query("users", $sql_array, "uid = '{$this->login_data['uid']}'"); + } + + if(!$this->login_data['loginkey']) + { + $this->login_data['loginkey'] = generate_loginkey(); + + $sql_array = array( + "loginkey" => $this->login_data['loginkey'] + ); + + $db->update_query("users", $sql_array, "uid = '{$this->login_data['uid']}'"); + } + } + + $salted_password = md5(md5($this->login_data['salt']).$password); + + if($salted_password != $this->login_data['password']) + { + $this->invalid_combination(true); + return false; + } + } + + function invalid_combination($show_login_attempts = false) + { + global $db, $lang, $mybb; + + // Don't show an error when the captcha was wrong! + if(!$this->captcha_verified) + { + return; + } + + $login_text = ''; + if($show_login_attempts) + { + if($mybb->settings['failedlogincount'] != 0 && $mybb->settings['failedlogintext'] == 1) + { + $logins = login_attempt_check(false) + 1; + $login_text = $lang->sprintf($lang->failed_login_again, $mybb->settings['failedlogincount'] - $logins); + } + } + + switch($mybb->settings['username_method']) + { + case 1: + $this->set_error('invalidpwordusernameemail', $login_text); + break; + case 2: + $this->set_error('invalidpwordusernamecombo', $login_text); + break; + default: + $this->set_error('invalidpwordusername', $login_text); + break; + } + } + + function get_login_data() + { + global $db, $settings; + + $user = &$this->data; + + $options = array( + 'fields' => array('uid', 'username', 'password', 'salt', 'loginkey', 'coppauser', 'usergroup', 'loginattempts'), + 'username_method' => (int)$settings['username_method'] + ); + + if($this->username_method !== null) + { + $options['username_method'] = (int)$this->username_method; + } + + $this->login_data = get_user_by_username($user['username'], $options); + } + + function validate_login() + { + global $plugins, $mybb; + + $user = &$this->data; + + $plugins->run_hooks('datahandler_login_validate_start', $this); + + $this->verify_attempts($mybb->settings['captchaimage']); + + if(array_key_exists('username', $user)) + { + $this->verify_username(); + } + + if(array_key_exists('password', $user)) + { + $this->verify_password(); + } + + $plugins->run_hooks('datahandler_login_validate_end', $this); + + $this->set_validated(true); + if(count($this->get_errors()) > 0) + { + return false; + } + + return true; + } + + function complete_login() + { + global $plugins, $db, $mybb, $session; + + $user = &$this->login_data; + + $plugins->run_hooks('datahandler_login_complete_start', $this); + + // Login to MyBB + my_setcookie('loginattempts', 1); + my_setcookie("sid", $session->sid, -1, true); + + $ip_address = $db->escape_binary($session->packedip); + $db->delete_query("sessions", "ip = {$ip_address} AND sid != '{$session->sid}'"); + + $newsession = array( + "uid" => $user['uid'], + ); + + $db->update_query("sessions", $newsession, "sid = '{$session->sid}'"); + $db->update_query("users", array("loginattempts" => 1), "uid = '{$user['uid']}'"); + + $remember = null; + if(!isset($mybb->input['remember']) || $mybb->input['remember'] != "yes") + { + $remember = -1; + } + + my_setcookie("mybbuser", $user['uid']."_".$user['loginkey'], $remember, true); + + if($this->captcha !== false) + { + $this->captcha->invalidate_captcha(); + } + + $plugins->run_hooks('datahandler_login_complete_end', $this); + + return true; + } +} \ No newline at end of file diff --git a/Upload/inc/datahandlers/pm.php b/Upload/inc/datahandlers/pm.php new file mode 100644 index 0000000..67d3d81 --- /dev/null +++ b/Upload/inc/datahandlers/pm.php @@ -0,0 +1,752 @@ +
    Please make sure IN_MYBB is defined."); +} + +/** + * PM handling class, provides common structure to handle private messaging data. + * + */ +class PMDataHandler extends DataHandler +{ + /** + * The language file used in the data handler. + * + * @var string + */ + public $language_file = 'datahandler_pm'; + + /** + * The prefix for the language variables used in the data handler. + * + * @var string + */ + public $language_prefix = 'pmdata'; + + /** + * Array of data inserted in to a private message. + * + * @var array + */ + public $pm_insert_data = array(); + + /** + * Array of data used to update a private message. + * + * @var array + */ + public $pm_update_data = array(); + + /** + * PM ID currently being manipulated by the datahandlers. + */ + public $pmid = 0; + + /** + * Values to be returned after inserting a PM. + * + * @var array + */ + public $return_values = array(); + + /** + * Verifies a private message subject. + * + * @return boolean True when valid, false when invalid. + */ + function verify_subject() + { + $subject = &$this->data['subject']; + + // Subject is over 85 characters, too long. + if(my_strlen($subject) > 85) + { + $this->set_error("too_long_subject"); + return false; + } + // No subject, apply the default [no subject] + if(!trim_blank_chrs($subject)) + { + $this->set_error("missing_subject"); + return false; + } + return true; + } + + /** + * Verifies if a message for a PM is valid. + * + * @return boolean True when valid, false when invalid. + */ + function verify_message() + { + $message = &$this->data['message']; + + // No message, return an error. + if(trim_blank_chrs($message) == '') + { + $this->set_error("missing_message"); + return false; + } + return true; + } + + /** + * Verifies if the specified sender is valid or not. + * + * @return boolean True when valid, false when invalid. + */ + function verify_sender() + { + global $db, $mybb, $lang; + + $pm = &$this->data; + + // Return if we've already validated + if(!empty($pm['sender'])) + { + return true; + } + + // Fetch the senders profile data. + $sender = get_user($pm['fromid']); + + // Collect user permissions for the sender. + $sender_permissions = user_permissions($pm['fromid']); + + // Check if the sender is over their quota or not - if they are, disable draft sending + if(isset($pm['options']['savecopy']) && $pm['options']['savecopy'] != 0 && empty($pm['saveasdraft'])) + { + if($sender_permissions['pmquota'] != "0" && $sender['totalpms'] >= $sender_permissions['pmquota'] && $this->admin_override != true) + { + $pm['options']['savecopy'] = 0; + } + } + + // Assign the sender information to the data. + $pm['sender'] = array( + "uid" => $sender['uid'], + "username" => $sender['username'] + ); + + return true; + } + + /** + * Verifies if an array of recipients for a private message are valid + * + * @return boolean True when valid, false when invalid. + */ + function verify_recipient() + { + global $cache, $db, $mybb, $lang; + + $pm = &$this->data; + + $recipients = array(); + + $invalid_recipients = array(); + // We have our recipient usernames but need to fetch user IDs + if(array_key_exists("to", $pm)) + { + foreach(array("to", "bcc") as $recipient_type) + { + if(!isset($pm[$recipient_type])) + { + $pm[$recipient_type] = array(); + } + if(!is_array($pm[$recipient_type])) + { + $pm[$recipient_type] = array($pm[$recipient_type]); + } + + $pm[$recipient_type] = array_map('trim', $pm[$recipient_type]); + $pm[$recipient_type] = array_filter($pm[$recipient_type]); + + // No recipients? Skip query + if(empty($pm[$recipient_type])) + { + if($recipient_type == 'to' && !$pm['saveasdraft']) + { + $this->set_error("no_recipients"); + return false; + } + continue; + } + + $recipientUsernames = array_map(array($db, 'escape_string'), $pm[$recipient_type]); + $recipientUsernames = "'".implode("','", $recipientUsernames)."'"; + + $query = $db->simple_select('users', '*', 'username IN('.$recipientUsernames.')'); + + $validUsernames = array(); + + while($user = $db->fetch_array($query)) + { + if($recipient_type == "bcc") + { + $user['bcc'] = 1; + } + + $recipients[] = $user; + $validUsernames[] = $user['username']; + } + + foreach($pm[$recipient_type] as $username) + { + if(!in_array($username, $validUsernames)) + { + $invalid_recipients[] = $username; + } + } + } + } + // We have recipient IDs + else + { + foreach(array("toid", "bccid") as $recipient_type) + { + if(!isset($pm[$recipient_type])) + { + $pm[$recipient_type] = array(); + } + if(!is_array($pm[$recipient_type])) + { + $pm[$recipient_type] = array($pm[$recipient_type]); + } + $pm[$recipient_type] = array_map('intval', $pm[$recipient_type]); + $pm[$recipient_type] = array_filter($pm[$recipient_type]); + + // No recipients? Skip query + if(empty($pm[$recipient_type])) + { + if($recipient_type == 'toid' && !$pm['saveasdraft']) + { + $this->set_error("no_recipients"); + return false; + } + continue; + } + + $recipientUids = "'".implode("','", $pm[$recipient_type])."'"; + + $query = $db->simple_select('users', '*', 'uid IN('.$recipientUids.')'); + + $validUids = array(); + + while($user = $db->fetch_array($query)) + { + if($recipient_type == "bccid") + { + $user['bcc'] = 1; + } + + $recipients[] = $user; + $validUids[] = $user['uid']; + } + + foreach($pm[$recipient_type] as $uid) + { + if(!in_array($uid, $validUids)) + { + $invalid_recipients[] = $uid; + } + } + } + } + + // If we have one or more invalid recipients and we're not saving a draft, error + if(count($invalid_recipients) > 0) + { + $invalid_recipients = implode(", ", array_map("htmlspecialchars_uni", $invalid_recipients)); + $this->set_error("invalid_recipients", array($invalid_recipients)); + return false; + } + + $sender_permissions = user_permissions($pm['fromid']); + + // Are we trying to send this message to more users than the permissions allow? + if($sender_permissions['maxpmrecipients'] > 0 && count($recipients) > $sender_permissions['maxpmrecipients'] && $this->admin_override != true) + { + $this->set_error("too_many_recipients", array($sender_permissions['maxpmrecipients'])); + } + + // Now we're done with that we loop through each recipient + foreach($recipients as $user) + { + // Collect group permissions for this recipient. + $recipient_permissions = user_permissions($user['uid']); + + // See if the sender is on the recipients ignore list and that either + // - admin_override is set or + // - sender is an administrator + if(($this->admin_override != true && $sender_permissions['cancp'] != 1) && $sender_permissions['canoverridepm'] != 1) + { + $ignorelist = explode(",", $user['ignorelist']); + if(!empty($ignorelist) && in_array($pm['fromid'], $ignorelist)) + { + $this->set_error("recipient_is_ignoring", array($user['username'])); + } + + // Is the recipient only allowing private messages from their buddy list? + if($mybb->settings['allowbuddyonly'] == 1 && $user['receivefrombuddy'] == 1) + { + $buddylist = explode(",", $user['buddylist']); + if(!empty($buddylist) && !in_array($pm['fromid'], $buddylist)) + { + $this->set_error("recipient_has_buddy_only", array(htmlspecialchars_uni($user['username']))); + } + } + + // Can the recipient actually receive private messages based on their permissions or user setting? + if(($user['receivepms'] == 0 || $recipient_permissions['canusepms'] == 0) && empty($pm['saveasdraft'])) + { + $this->set_error("recipient_pms_disabled", array($user['username'])); + return false; + } + } + + // Check to see if the user has reached their private message quota - if they have, email them. + if($recipient_permissions['pmquota'] != "0" && $user['totalpms'] >= $recipient_permissions['pmquota'] && $recipient_permissions['cancp'] != 1 && $sender_permissions['cancp'] != 1 && empty($pm['saveasdraft']) && !$this->admin_override) + { + if(trim($user['language']) != '' && $lang->language_exists($user['language'])) + { + $uselang = trim($user['language']); + } + elseif($mybb->settings['bblanguage']) + { + $uselang = $mybb->settings['bblanguage']; + } + else + { + $uselang = "english"; + } + if($uselang == $mybb->settings['bblanguage'] || !$uselang) + { + $emailsubject = $lang->emailsubject_reachedpmquota; + $emailmessage = $lang->email_reachedpmquota; + } + else + { + $userlang = new MyLanguage; + $userlang->set_path(MYBB_ROOT."inc/languages"); + $userlang->set_language($uselang); + $userlang->load("messages"); + $emailsubject = $userlang->emailsubject_reachedpmquota; + $emailmessage = $userlang->email_reachedpmquota; + } + $emailmessage = $lang->sprintf($emailmessage, $user['username'], $mybb->settings['bbname'], $mybb->settings['bburl']); + $emailsubject = $lang->sprintf($emailsubject, $mybb->settings['bbname'], $pm['subject']); + + $new_email = array( + "mailto" => $db->escape_string($user['email']), + "mailfrom" => '', + "subject" => $db->escape_string($emailsubject), + "message" => $db->escape_string($emailmessage), + "headers" => '' + ); + + $db->insert_query("mailqueue", $new_email); + $cache->update_mailqueue(); + + if($this->admin_override != true) + { + $this->set_error("recipient_reached_quota", array($user['username'])); + } + } + + // Everything looks good, assign some specifics about the recipient + $pm['recipients'][$user['uid']] = array( + "uid" => $user['uid'], + "username" => $user['username'], + "email" => $user['email'], + "lastactive" => $user['lastactive'], + "pmnotice" => $user['pmnotice'], + "pmnotify" => $user['pmnotify'], + "language" => $user['language'] + ); + + // If this recipient is defined as a BCC recipient, save it + if(isset($user['bcc']) && $user['bcc'] == 1) + { + $pm['recipients'][$user['uid']]['bcc'] = 1; + } + } + return true; + } + + /** + * Verify that the user is not flooding the system. + * + * @return boolean True + */ + function verify_pm_flooding() + { + global $mybb, $db; + + $pm = &$this->data; + + // Check if post flooding is enabled within MyBB or if the admin override option is specified. + if($mybb->settings['pmfloodsecs'] > 0 && $pm['fromid'] != 0 && $this->admin_override == false) + { + // Fetch the senders profile data. + $sender = get_user($pm['fromid']); + + // Calculate last post + $query = $db->simple_select("privatemessages", "dateline", "fromid='".$db->escape_string($pm['fromid'])."' AND toid != '0'", array('order_by' => 'dateline', 'order_dir' => 'desc', 'limit' => 1)); + $sender['lastpm'] = $db->fetch_field($query, "dateline"); + + // A little bit of calculation magic and moderator status checking. + if(TIME_NOW-$sender['lastpm'] <= $mybb->settings['pmfloodsecs'] && !is_moderator("", "", $pm['fromid'])) + { + // Oops, user has been flooding - throw back error message. + $time_to_wait = ($mybb->settings['pmfloodsecs'] - (TIME_NOW-$sender['lastpm'])) + 1; + if($time_to_wait == 1) + { + $this->set_error("pm_flooding_one_second"); + } + else + { + $this->set_error("pm_flooding", array($time_to_wait)); + } + return false; + } + } + // All is well that ends well - return true. + return true; + } + + /** + * Verifies if the various 'options' for sending PMs are valid. + * + * @return boolean True when valid, false when invalid. + */ + function verify_options() + { + $options = &$this->data['options']; + + $this->verify_yesno_option($options, 'signature', 1); + $this->verify_yesno_option($options, 'savecopy', 1); + $this->verify_yesno_option($options, 'disablesmilies', 0); + + // Requesting a read receipt? + if(isset($options['readreceipt']) && $options['readreceipt'] == 1) + { + $options['readreceipt'] = 1; + } + else + { + $options['readreceipt'] = 0; + } + return true; + } + + /** + * Validate an entire private message. + * + * @return boolean True when valid, false when invalid. + */ + function validate_pm() + { + global $plugins; + + $pm = &$this->data; + + if(empty($pm['savedraft'])) + { + $this->verify_pm_flooding(); + } + + // Verify all PM assets. + $this->verify_subject(); + + $this->verify_sender(); + + $this->verify_recipient(); + + $this->verify_message(); + + $this->verify_options(); + + $plugins->run_hooks("datahandler_pm_validate", $this); + + // Choose the appropriate folder to save in. + if(!empty($pm['saveasdraft'])) + { + $pm['folder'] = 3; + } + else + { + $pm['folder'] = 1; + } + + // We are done validating, return. + $this->set_validated(true); + if(count($this->get_errors()) > 0) + { + return false; + } + else + { + return true; + } + } + + /** + * Insert a new private message. + * + * @return array Array of PM useful data. + */ + function insert_pm() + { + global $cache, $db, $mybb, $plugins, $lang; + + // Yes, validating is required. + if(!$this->get_validated()) + { + die("The PM needs to be validated before inserting it into the DB."); + } + if(count($this->get_errors()) > 0) + { + die("The PM is not valid."); + } + + // Assign data to common variable + $pm = &$this->data; + + if(empty($pm['pmid'])) + { + $pm['pmid'] = 0; + } + $pm['pmid'] = (int)$pm['pmid']; + + if(empty($pm['icon']) || $pm['icon'] < 0) + { + $pm['icon'] = 0; + } + + $uid = 0; + + if(!is_array($pm['recipients'])) + { + $recipient_list = array(); + } + else + { + // Build recipient list + foreach($pm['recipients'] as $recipient) + { + if(!empty($recipient['bcc'])) + { + $recipient_list['bcc'][] = $recipient['uid']; + } + else + { + $recipient_list['to'][] = $recipient['uid']; + $uid = $recipient['uid']; + } + } + } + + $this->pm_insert_data = array( + 'fromid' => (int)$pm['sender']['uid'], + 'folder' => $pm['folder'], + 'subject' => $db->escape_string($pm['subject']), + 'icon' => (int)$pm['icon'], + 'message' => $db->escape_string($pm['message']), + 'dateline' => TIME_NOW, + 'status' => 0, + 'includesig' => $pm['options']['signature'], + 'smilieoff' => $pm['options']['disablesmilies'], + 'receipt' => (int)$pm['options']['readreceipt'], + 'readtime' => 0, + 'recipients' => $db->escape_string(serialize($recipient_list)), + 'ipaddress' => $db->escape_binary($pm['ipaddress']) + ); + + // Check if we're updating a draft or not. + $query = $db->simple_select("privatemessages", "pmid, deletetime", "folder='3' AND uid='".(int)$pm['sender']['uid']."' AND pmid='{$pm['pmid']}'"); + $draftcheck = $db->fetch_array($query); + + // This PM was previously a draft + if($draftcheck['pmid']) + { + if($draftcheck['deletetime']) + { + // This draft was a reply to a PM + $pm['pmid'] = $draftcheck['deletetime']; + $pm['do'] = "reply"; + } + + // Delete the old draft as we no longer need it + $db->delete_query("privatemessages", "pmid='{$draftcheck['pmid']}'"); + } + + // Saving this message as a draft + if(!empty($pm['saveasdraft'])) + { + $this->pm_insert_data['uid'] = $pm['sender']['uid']; + + // If this is a reply, then piggyback into the deletetime to let us know in the future + if($pm['do'] == "reply" || $pm['do'] == "replyall") + { + $this->pm_insert_data['deletetime'] = $pm['pmid']; + } + + $plugins->run_hooks("datahandler_pm_insert_updatedraft", $this); + $db->insert_query("privatemessages", $this->pm_insert_data); + + // If this is a draft, end it here - below deals with complete messages + return array( + "draftsaved" => 1 + ); + } + + $this->pmid = array(); + + // Save a copy of the PM for each of our recipients + foreach($pm['recipients'] as $recipient) + { + // Send email notification of new PM if it is enabled for the recipient + $query = $db->simple_select("privatemessages", "dateline", "uid='".$recipient['uid']."' AND folder='1'", array('order_by' => 'dateline', 'order_dir' => 'desc', 'limit' => 1)); + $lastpm = $db->fetch_array($query); + if($recipient['pmnotify'] == 1 && $recipient['lastactive'] > $lastpm['dateline']) + { + if($recipient['language'] != "" && $lang->language_exists($recipient['language'])) + { + $uselang = $recipient['language']; + } + elseif($mybb->settings['bblanguage']) + { + $uselang = $mybb->settings['bblanguage']; + } + else + { + $uselang = "english"; + } + if($uselang == $mybb->settings['bblanguage'] && !empty($lang->emailsubject_newpm)) + { + $emailsubject = $lang->emailsubject_newpm; + $emailmessage = $lang->email_newpm; + } + else + { + $userlang = new MyLanguage; + $userlang->set_path(MYBB_ROOT."inc/languages"); + $userlang->set_language($uselang); + $userlang->load("messages"); + $emailsubject = $userlang->emailsubject_newpm; + $emailmessage = $userlang->email_newpm; + } + + if(!$pm['sender']['username']) + { + $pm['sender']['username'] = $lang->mybb_engine; + } + + require_once MYBB_ROOT.'inc/class_parser.php'; + $parser = new Postparser; + $pm['message'] = $parser->text_parse_message($pm['message'], array('me_username' => $pm['sender']['username'], 'filter_badwords' => 1, 'safe_html' => 1)); + + $emailmessage = $lang->sprintf($emailmessage, $recipient['username'], $pm['sender']['username'], $mybb->settings['bbname'], $mybb->settings['bburl'], $pm['message']); + $emailsubject = $lang->sprintf($emailsubject, $mybb->settings['bbname'], $pm['subject']); + + $new_email = array( + "mailto" => $db->escape_string($recipient['email']), + "mailfrom" => '', + "subject" => $db->escape_string($emailsubject), + "message" => $db->escape_string($emailmessage), + "headers" => '' + ); + + $db->insert_query("mailqueue", $new_email); + $cache->update_mailqueue(); + } + + $this->pm_insert_data['uid'] = $recipient['uid']; + $this->pm_insert_data['toid'] = $recipient['uid']; + + $plugins->run_hooks("datahandler_pm_insert", $this); + $this->pmid[] = $db->insert_query("privatemessages", $this->pm_insert_data); + + // If PM noices/alerts are on, show! + if($recipient['pmnotice'] == 1) + { + $updated_user = array( + "pmnotice" => 2 + ); + $db->update_query("users", $updated_user, "uid='{$recipient['uid']}'"); + } + + // Update private message count (total, new and unread) for recipient + require_once MYBB_ROOT."/inc/functions_user.php"; + update_pm_count($recipient['uid'], 7, $recipient['lastactive']); + } + + // Are we replying or forwarding an existing PM? + if($pm['pmid']) + { + if($pm['do'] == "reply" || $pm['do'] == "replyall") + { + $sql_array = array( + 'status' => 3, + 'statustime' => TIME_NOW + ); + $db->update_query("privatemessages", $sql_array, "pmid={$pm['pmid']} AND uid={$pm['sender']['uid']}"); + } + elseif($pm['do'] == "forward") + { + $sql_array = array( + 'status' => 4, + 'statustime' => TIME_NOW + ); + $db->update_query("privatemessages", $sql_array, "pmid={$pm['pmid']} AND uid={$pm['sender']['uid']}"); + } + } + + // If we're saving a copy + if($pm['options']['savecopy'] != 0) + { + if(isset($recipient_list['to']) && count($recipient_list['to']) == 1) + { + $this->pm_insert_data['toid'] = $uid; + } + else + { + $this->pm_insert_data['toid'] = 0; + } + $this->pm_insert_data['uid'] = (int)$pm['sender']['uid']; + $this->pm_insert_data['folder'] = 2; + $this->pm_insert_data['status'] = 1; + $this->pm_insert_data['receipt'] = 0; + + $plugins->run_hooks("datahandler_pm_insert_savedcopy", $this); + $db->insert_query("privatemessages", $this->pm_insert_data); + + // Because the sender saved a copy, update their total pm count + require_once MYBB_ROOT."/inc/functions_user.php"; + update_pm_count($pm['sender']['uid'], 1); + } + + // Return back with appropriate data + $this->return_values = array( + "messagesent" => 1, + "pmids" => $this->pmid + ); + + $plugins->run_hooks("datahandler_pm_insert_end", $this); + + return $this->return_values; + } +} diff --git a/Upload/inc/datahandlers/post.php b/Upload/inc/datahandlers/post.php new file mode 100644 index 0000000..426c74e --- /dev/null +++ b/Upload/inc/datahandlers/post.php @@ -0,0 +1,1903 @@ +
    Please make sure IN_MYBB is defined."); +} + +/* +EXAMPLE USE: + +$post = get from POST data +$thread = get from DB using POST data id + +$postHandler = new postDataHandler(); +if($postHandler->validate_post($post)) +{ + $postHandler->insert_post($post); +} + +*/ + +/** + * Post handling class, provides common structure to handle post data. + * + */ +class PostDataHandler extends DataHandler +{ + /** + * The language file used in the data handler. + * + * @var string + */ + public $language_file = 'datahandler_post'; + + /** + * The prefix for the language variables used in the data handler. + * + * @var string + */ + public $language_prefix = 'postdata'; + + /** + * What are we performing? + * post = New post + * thread = New thread + * edit = Editing a thread or post + */ + public $action; + + /** + * Array of data inserted in to a post. + * + * @var array + */ + public $post_insert_data = array(); + + /** + * Array of data used to update a post. + * + * @var array + */ + public $post_update_data = array(); + + /** + * Post ID currently being manipulated by the datahandlers. + * + * @var int + */ + public $pid = 0; + + /** + * Array of data inserted in to a thread. + * + * @var array + */ + public $thread_insert_data = array(); + + /** + * Array of data used to update a thread. + * + * @var array + */ + public $thread_update_data = array(); + + /** + * Thread ID currently being manipulated by the datahandlers. + * + * @var int + */ + public $tid = 0; + + /** + * Values to be returned after inserting/updating a post/thread. + * + * @var array + */ + public $return_values = array(); + + /** + * Verifies the author of a post and fetches the username if necessary. + * + * @return boolean True if the author information is valid, false if invalid. + */ + function verify_author() + { + global $mybb; + + $post = &$this->data; + + // Don't have a user ID at all - not good (note, a user id of 0 will still work). + if(!isset($post['uid'])) + { + $this->set_error("invalid_user_id"); + return false; + } + // If we have a user id but no username then fetch the username. + else if($post['uid'] > 0 && empty($post['username'])) + { + $user = get_user($post['uid']); + $post['username'] = $user['username']; + } + // if the uid is 0 verify the username + else if($post['uid'] == 0 && $post['username'] != $lang->guest) + { + // Set up user handler + require_once MYBB_ROOT."inc/datahandlers/user.php"; + $userhandler = new UserDataHandler(); + + $data_array = array('username' => $post['username']); + $userhandler->set_data($data_array); + + if(!$userhandler->verify_username()) + { + // invalid username + $this->errors = array_merge($this->errors, $userhandler->get_errors()); + return false; + } + } + + // After all of this, if we still don't have a username, force the username as "Guest" (Note, this is not translatable as it is always a fallback) + if(!$post['username']) + { + $post['username'] = "Guest"; + } + + // Sanitize the username + $post['username'] = htmlspecialchars_uni($post['username']); + return true; + } + + /** + * Verifies a post subject. + * + * @param string True if the subject is valid, false if invalid. + * @return boolean True when valid, false when not valid. + */ + function verify_subject() + { + global $db; + $post = &$this->data; + $subject = &$post['subject']; + $subject = trim_blank_chrs($subject); + + // Are we editing an existing thread or post? + if($this->method == "update" && $post['pid']) + { + if(empty($post['tid'])) + { + $query = $db->simple_select("posts", "tid", "pid='".(int)$post['pid']."'"); + $post['tid'] = $db->fetch_field($query, "tid"); + } + // Here we determine if we're editing the first post of a thread or not. + $options = array( + "limit" => 1, + "limit_start" => 0, + "order_by" => "dateline", + "order_dir" => "asc" + ); + $query = $db->simple_select("posts", "pid", "tid='".$post['tid']."'", $options); + $first_check = $db->fetch_array($query); + if($first_check['pid'] == $post['pid']) + { + $first_post = true; + } + else + { + $first_post = false; + } + + // If this is the first post there needs to be a subject, else make it the default one. + if(my_strlen($subject) == 0 && $first_post) + { + $this->set_error("firstpost_no_subject"); + return false; + } + elseif(my_strlen($subject) == 0) + { + $thread = get_thread($post['tid']); + $subject = "RE: ".$thread['subject']; + } + } + + // This is a new post + else if($this->action == "post") + { + if(my_strlen($subject) == 0) + { + $thread = get_thread($post['tid']); + $subject = "RE: ".$thread['subject']; + } + } + + // This is a new thread and we require that a subject is present. + else + { + if(my_strlen($subject) == 0) + { + $this->set_error("missing_subject"); + return false; + } + } + + // If post is reply and begins with "RE: ", remove 4 from subject length. + $subject_length = my_strlen($subject); + if($this->action == "post") + { + $position_re = my_strpos($subject, "RE: "); + if($position_re !== false && $position_re == 0) + { + $subject_length = $subject_length - 4; + } + } + + if($subject_length > 85) + { + // Subject is too long + $this->set_error('subject_too_long', my_strlen($subject)); + return false; + } + + // Subject is valid - return true. + return true; + } + + /** + * Verifies a post message. + * + * @param string The message content. + */ + function verify_message() + { + global $mybb; + + $post = &$this->data; + $post['message'] = trim_blank_chrs($post['message']); + + // Do we even have a message at all? + if(my_strlen($post['message']) == 0) + { + $this->set_error("missing_message"); + return false; + } + + // If this board has a maximum message length check if we're over it. Use strlen because SQL limits are in bytes + else if(strlen($post['message']) > $mybb->settings['maxmessagelength'] && $mybb->settings['maxmessagelength'] > 0 && !is_moderator($post['fid'], "", $post['uid'])) + { + $this->set_error("message_too_long", array($mybb->settings['maxmessagelength'], strlen($post['message']))); + return false; + } + + // And if we've got a minimum message length do we meet that requirement too? + else + { + if(!isset($post['fid'])) + { + $post['fid'] = 0; + } + if(!$mybb->settings['mycodemessagelength']) + { + // Check to see of the text is full of MyCode + require_once MYBB_ROOT."inc/class_parser.php"; + $parser = new postParser; + + $message = $parser->text_parse_message($post['message']); + + if(my_strlen($message) < $mybb->settings['minmessagelength'] && $mybb->settings['minmessagelength'] > 0 && !is_moderator($post['fid'], "", $post['uid'])) + { + $this->set_error("message_too_short", array($mybb->settings['minmessagelength'])); + return false; + } + } + else if(my_strlen($post['message']) < $mybb->settings['minmessagelength'] && $mybb->settings['minmessagelength'] > 0 && !is_moderator($post['fid'], "", $post['uid'])) + { + $this->set_error("message_too_short", array($mybb->settings['minmessagelength'])); + return false; + } + } + return true; + } + + /** + * Verifies the specified post options are correct. + * + * @return boolean True + */ + function verify_options() + { + $options = &$this->data['options']; + + // Verify yes/no options. + $this->verify_yesno_option($options, 'signature', 0); + $this->verify_yesno_option($options, 'disablesmilies', 0); + + return true; + } + + /** + * Verify that the user is not flooding the system. + * + * @return boolean True + */ + function verify_post_flooding() + { + global $mybb; + + $post = &$this->data; + + // Check if post flooding is enabled within MyBB or if the admin override option is specified. + if($mybb->settings['postfloodcheck'] == 1 && $post['uid'] != 0 && $this->admin_override == false) + { + if($this->verify_post_merge(true) !== true) + { + return true; + } + + // Fetch the user information for this post - used to check their last post date. + $user = get_user($post['uid']); + + // A little bit of calculation magic and moderator status checking. + if(TIME_NOW-$user['lastpost'] <= $mybb->settings['postfloodsecs'] && !is_moderator($post['fid'], "", $user['uid'])) + { + // Oops, user has been flooding - throw back error message. + $time_to_wait = ($mybb->settings['postfloodsecs'] - (TIME_NOW-$user['lastpost'])) + 1; + if($time_to_wait == 1) + { + $this->set_error("post_flooding_one_second"); + } + else + { + $this->set_error("post_flooding", array($time_to_wait)); + } + return false; + } + } + // All is well that ends well - return true. + return true; + } + + function verify_post_merge($simple_mode=false) + { + global $mybb, $db, $session; + + $post = &$this->data; + + // Are we starting a new thread? + if(empty($post['tid'])) + { + return true; + } + + // Are we even turned on? + if(empty($mybb->settings['postmergemins'])) + { + return true; + } + + // Assign a default separator if none is specified + if(trim($mybb->settings['postmergesep']) == "") + { + $mybb->settings['postmergesep'] = "[hr]"; + } + + // Check to see if this person is in a usergroup that is excluded + if($mybb->settings['postmergeuignore'] == -1) + { + return true; + } + elseif($mybb->settings['postmergeuignore'] != '' && is_member($mybb->settings['postmergeuignore'], $post['uid'])) + { + return true; + } + + // Select the lastpost and fid information for this thread + $query = $db->simple_select("threads", "lastpost,fid", "lastposteruid='".$post['uid']."' AND tid='".$post['tid']."'", array('limit' => '1')); + $thread = $db->fetch_array($query); + + // Check to see if the same author has posted within the merge post time limit + if(((int)$mybb->settings['postmergemins'] != 0 && trim($mybb->settings['postmergemins']) != "") && (TIME_NOW-$thread['lastpost']) > ((int)$mybb->settings['postmergemins']*60)) + { + return true; + } + + if($mybb->settings['postmergefignore'] == -1) + { + return true; + } + elseif($mybb->settings['postmergefignore'] != '') + { + $fids = explode(',', (string)$mybb->settings['postmergefignore']); + + if(is_array($fids)) + { + foreach($fids as &$fid) + { + $fid = (int)$fid; + } + unset($fid); + + if(in_array($thread['fid'], $fids)) + { + return true; + } + } + } + + if($simple_mode == true) + { + return false; + } + + if($post['uid']) + { + $user_check = "uid='".$post['uid']."'"; + } + else + { + $user_check = "ipaddress=".$db->escape_binary($session->packedip); + } + + $query = $db->simple_select("posts", "pid,message,visible", "{$user_check} AND tid='".$post['tid']."' AND dateline='".$thread['lastpost']."'", array('order_by' => 'pid', 'order_dir' => 'DESC', 'limit' => 1)); + return $db->fetch_array($query); + } + + /** + * Verifies the image count. + * + * @return boolean True when valid, false when not valid. + */ + function verify_image_count() + { + global $mybb, $db; + + $post = &$this->data; + + // Get the permissions of the user who is making this post or thread + $permissions = user_permissions($post['uid']); + + // Fetch the forum this post is being made in + if(!$post['fid']) + { + $query = $db->simple_select('posts', 'fid', "pid = '{$post['pid']}'"); + $post['fid'] = $db->fetch_field($query, 'fid'); + } + $forum = get_forum($post['fid']); + + // Check if this post contains more images than the forum allows + if((!isset($post['savedraft']) || $post['savedraft'] != 1) && $mybb->settings['maxpostimages'] != 0 && $permissions['cancp'] != 1) + { + require_once MYBB_ROOT."inc/class_parser.php"; + $parser = new postParser; + + // Parse the message. + $parser_options = array( + "allow_html" => $forum['allowhtml'], + "allow_mycode" => $forum['allowmycode'], + "allow_imgcode" => $forum['allowimgcode'], + "allow_videocode" => $forum['allowvideocode'], + "filter_badwords" => 1 + ); + + if($post['options']['disablesmilies'] != 1) + { + $parser_options['allow_smilies'] = $forum['allowsmilies']; + } + else + { + $parser_options['allow_smilies'] = 0; + } + + $image_check = $parser->parse_message($post['message'], $parser_options); + + // And count the number of image tags in the message. + $image_count = substr_count($image_check, " $mybb->settings['maxpostimages']) + { + // Throw back a message if over the count with the number of images as well as the maximum number of images per post. + $this->set_error("too_many_images", array(1 => $image_count, 2 => $mybb->settings['maxpostimages'])); + return false; + } + } + } + + /** + * Verifies the video count. + * + * @return boolean True when valid, false when not valid. + */ + function verify_video_count() + { + global $mybb, $db; + + $post = &$this->data; + + // Get the permissions of the user who is making this post or thread + $permissions = user_permissions($post['uid']); + + // Check if this post contains more videos than the forum allows + if((!isset($post['savedraft']) || $post['savedraft'] != 1) && $mybb->settings['maxpostvideos'] != 0 && $permissions['cancp'] != 1) + { + // And count the number of video tags in the message. + $video_count = substr_count($post['message'], "[video="); + if($video_count > $mybb->settings['maxpostvideos']) + { + // Throw back a message if over the count with the number of images as well as the maximum number of images per post. + $this->set_error("too_many_videos", array(1 => $video_count, 2 => $mybb->settings['maxpostvideos'])); + return false; + } + } + } + + /** + * Verify the reply-to post. + * + * @return boolean True when valid, false when not valid. + */ + function verify_reply_to() + { + global $db; + $post = &$this->data; + + // Check if the post being replied to actually exists in this thread. + if($post['replyto']) + { + $query = $db->simple_select("posts", "pid", "pid='".(int)$post['replyto']."'"); + $valid_post = $db->fetch_array($query); + if(!$valid_post['pid']) + { + $post['replyto'] = 0; + } + else + { + return true; + } + } + + // If this post isn't a reply to a specific post, attach it to the first post. + if(!$post['replyto']) + { + $options = array( + "limit_start" => 0, + "limit" => 1, + "order_by" => "dateline", + "order_dir" => "asc" + ); + $query = $db->simple_select("posts", "pid", "tid='{$post['tid']}'", $options); + $reply_to = $db->fetch_array($query); + $post['replyto'] = $reply_to['pid']; + } + + return true; + } + + /** + * Verify the post icon. + * + * @return boolean True when valid, false when not valid. + */ + function verify_post_icon() + { + global $cache; + + $post = &$this->data; + + $posticons_cache = $cache->read("posticons"); + + // If we don't have a post icon assign it as 0. + if(empty($post['icon']) || !isset($posticons_cache[$post['icon']])) + { + $post['icon'] = 0; + } + return true; + } + + /** + * Verify the dateline. + * + * @return boolean True when valid, false when not valid. + */ + function verify_dateline() + { + $dateline = &$this->data['dateline']; + + // The date has to be numeric and > 0. + if($dateline < 0 || is_numeric($dateline) == false) + { + $dateline = TIME_NOW; + } + } + + /** + * Verify thread prefix. + * + * @return boolean True when valid, false when not valid. + */ + function verify_prefix() + { + $prefix = &$this->data['prefix']; + + $prefix_cache = build_prefixes(); + + // If a valid prefix isn't supplied, don't assign one. + if(empty($prefix)) + { + $prefix = 0; + } + else + { + $prefix_cache = build_prefixes($prefix); + + if(empty($prefix_cache)) + { + $this->set_error('invalid_prefix'); + return false; + } + if($prefix_cache['groups'] != "-1") + { + if(!empty($this->data['edit_uid'])) + { + // Post is being edited + $user = get_user($this->data['edit_uid']); + } + else + { + $user = get_user($this->data['uid']); + } + + if(!is_member($prefix_cache['groups'], array('usergroup' => $user['usergroup'], 'additionalgroups' => $user['additionalgroups']))) + { + $this->set_error('invalid_prefix'); + return false; + } + } + if($prefix_cache['forums'] != "-1") + { + // Decide whether this prefix can be used in our forum + $forums = explode(",", $prefix_cache['forums']); + + if(!in_array($this->data['fid'], $forums)) + { + $this->set_error('invalid_prefix'); + return false; + } + } + } + + // Does this forum require a prefix? + $forum = get_forum($this->data['fid']); + + if($forum['requireprefix'] == 1) + { + $num_prefixes = false; + + // Go through each of our prefixes and decide if there are any possible prefixes to use. + if(!empty($this->data['edit_uid'])) + { + // Post is being edited + $user = get_user($this->data['edit_uid']); + } + else + { + $user = get_user($this->data['uid']); + } + + $prefix_cache = build_prefixes(); + + if(!empty($prefix_cache)) + { + foreach($prefix_cache as $required) + { + if($required['forums'] != "-1") + { + // Decide whether this prefix can be used in our forum + $forums = explode(",", $required['forums']); + + if(!in_array($forum['fid'], $forums)) + { + continue; + } + } + + if($required['groups'] != "-1") + { + if(!is_member($required['groups'], array('usergroup' => $user['usergroup'], 'additionalgroups' => $user['additionalgroups']))) + { + $num_prefixes = true; + } + } + else + { + $num_prefixes = true; + } + } + } + + if($prefix == 0 && $num_prefixes) + { + $this->set_error('require_prefix'); + return false; + } + } + + return true; + } + + /** + * Validate a post. + * + * @return boolean True when valid, false when invalid. + */ + function validate_post() + { + global $mybb, $db, $plugins; + + $post = &$this->data; + $time = TIME_NOW; + + $this->action = "post"; + + if($this->method != "update" && !$post['savedraft']) + { + $this->verify_post_flooding(); + } + + // Verify all post assets. + + if($this->method == "insert" || array_key_exists('uid', $post)) + { + $this->verify_author(); + } + + if($this->method == "insert" || array_key_exists('subject', $post)) + { + $this->verify_subject(); + } + + if($this->method == "insert" || array_key_exists('message', $post)) + { + $this->verify_message(); + $this->verify_image_count(); + $this->verify_video_count(); + } + + if($this->method == "insert" || array_key_exists('dateline', $post)) + { + $this->verify_dateline(); + } + + if($this->method == "insert" || array_key_exists('replyto', $post)) + { + $this->verify_reply_to(); + } + + if($this->method == "insert" || array_key_exists('icon', $post)) + { + $this->verify_post_icon(); + } + + if($this->method == "insert" || array_key_exists('options', $post)) + { + $this->verify_options(); + } + + $plugins->run_hooks("datahandler_post_validate_post", $this); + + // We are done validating, return. + $this->set_validated(true); + if(count($this->get_errors()) > 0) + { + return false; + } + else + { + return true; + } + } + + /** + * Insert a post into the database. + * + * @return array Array of new post details, pid and visibility. + */ + function insert_post() + { + global $db, $mybb, $plugins, $cache, $lang; + + $post = &$this->data; + + // Yes, validating is required. + if(!$this->get_validated()) + { + die("The post needs to be validated before inserting it into the DB."); + } + if(count($this->get_errors()) > 0) + { + die("The post is not valid."); + } + + // Fetch the thread + $thread = get_thread($post['tid']); + + $closed = $thread['closed']; + + // This post is being saved as a draft. + if($post['savedraft']) + { + $visible = -2; + } + + // Otherwise this post is being made now and we have a bit to do. + else + { + // Automatic subscription to the thread + if($post['options']['subscriptionmethod'] != "" && $post['uid'] > 0) + { + switch($post['options']['subscriptionmethod']) + { + case "pm": + $notification = 2; + break; + case "email": + $notification = 1; + break; + default: + $notification = 0; + } + + require_once MYBB_ROOT."inc/functions_user.php"; + add_subscribed_thread($post['tid'], $notification, $post['uid']); + } + + // Perform any selected moderation tools. + $ismod = is_moderator($post['fid'], "", $post['uid']); + if($ismod) + { + $lang->load($this->language_file, true); + + $modoptions = $post['modoptions']; + $modlogdata['fid'] = $thread['fid']; + $modlogdata['tid'] = $thread['tid']; + + $newstick = $newclosed = ''; + + if(!isset($modoptions['closethread'])) + { + $modoptions['closethread'] = 0; + } + + // Close the thread. + if($modoptions['closethread'] == 1 && $thread['closed'] != 1) + { + $newclosed = "closed=1"; + log_moderator_action($modlogdata, $lang->thread_closed); + $closed = 1; + } + + // Open the thread. + if($modoptions['closethread'] != 1 && $thread['closed'] == 1) + { + $newclosed = "closed=0"; + log_moderator_action($modlogdata, $lang->thread_opened); + $closed = 0; + } + + if(!isset($modoptions['stickthread'])) + { + $modoptions['stickthread'] = 0; + } + + // Stick the thread. + if($modoptions['stickthread'] == 1 && $thread['sticky'] != 1) + { + $newstick = "sticky='1'"; + log_moderator_action($modlogdata, $lang->thread_stuck); + } + + // Unstick the thread. + if($modoptions['stickthread'] != 1 && $thread['sticky']) + { + $newstick = "sticky='0'"; + log_moderator_action($modlogdata, $lang->thread_unstuck); + } + + // Execute moderation options. + if($newstick && $newclosed) + { + $sep = ","; + } + else + { + $sep = ''; + } + if($newstick || $newclosed) + { + $db->write_query(" + UPDATE ".TABLE_PREFIX."threads + SET {$newclosed}{$sep}{$newstick} + WHERE tid='{$thread['tid']}' + "); + } + } + + // Fetch the forum this post is being made in + $forum = get_forum($post['fid']); + + // Decide on the visibility of this post. + $forumpermissions = forum_permissions($post['fid'], $post['uid']); + if($forumpermissions['modposts'] == 1 && !$ismod) + { + $visible = 0; + } + else + { + $visible = 1; + } + + // Are posts from this user being moderated? Change visibility + if($mybb->user['uid'] == $post['uid'] && $mybb->user['moderateposts'] == 1) + { + $visible = 0; + } + } + + if(!isset($post['pid'])) + { + $post['pid'] = 0; + } + + $post['pid'] = (int)$post['pid']; + $post['uid'] = (int)$post['uid']; + + if($post['pid'] > 0) + { + $query = $db->simple_select("posts", "tid", "pid='{$post['pid']}' AND uid='{$post['uid']}' AND visible='-2'"); + $draft_check = $db->fetch_field($query, "tid"); + } + else + { + $draft_check = false; + } + + if($this->method != "update" && $visible == 1) + { + $double_post = $this->verify_post_merge(); + + // Only combine if they are both invisible (mod queue'd forum) or both visible + if($double_post !== true && $double_post['visible'] == $visible) + { + $this->pid = $double_post['pid']; + + $post['message'] = $double_post['message'] .= "\n".$mybb->settings['postmergesep']."\n".$post['message']; + $update_query = array( + "message" => $db->escape_string($double_post['message']) + ); + $update_query['edituid'] = (int)$post['uid']; + $update_query['edittime'] = TIME_NOW; + $query = $db->update_query("posts", $update_query, "pid='".$double_post['pid']."'"); + + if($draft_check) + { + $db->delete_query("posts", "pid='".$post['pid']."'"); + } + + if($post['posthash']) + { + // Assign any uploaded attachments with the specific posthash to the merged post. + $post['posthash'] = $db->escape_string($post['posthash']); + + $query = $db->simple_select("attachments", "COUNT(aid) AS attachmentcount", "pid='0' AND visible='1' AND posthash='{$post['posthash']}'"); + $attachmentcount = $db->fetch_field($query, "attachmentcount"); + + if($attachmentcount > 0) + { + // Update forum count + update_thread_counters($post['tid'], array('attachmentcount' => "+{$attachmentcount}")); + } + + $attachmentassign = array( + "pid" => $double_post['pid'], + "posthash" => '' + ); + $db->update_query("attachments", $attachmentassign, "posthash='{$post['posthash']}' AND pid='0'"); + } + + // Return the post's pid and whether or not it is visible. + $this->return_values = array( + "pid" => $double_post['pid'], + "visible" => $visible, + "merge" => true + ); + + $plugins->run_hooks("datahandler_post_insert_merge", $this); + + return $this->return_values; + } + } + + if($visible == 1 && $thread['visible'] == 1) + { + $now = TIME_NOW; + + // Yes, the value to the lastpost key in this array has single quotes within double quotes. It's not a bug. + $update_array = array( + 'lastpost' => "'{$now}'" + ); + if($forum['usepostcounts'] != 0) + { + $update_array['postnum'] = 'postnum+1'; + } + + $db->update_query("users", $update_array, "uid='{$post['uid']}'", 1, true); + } + + // Are we updating a post which is already a draft? Perhaps changing it into a visible post? + if($draft_check) + { + // Update a post that is a draft + $this->post_update_data = array( + "subject" => $db->escape_string($post['subject']), + "icon" => (int)$post['icon'], + "uid" => $post['uid'], + "username" => $db->escape_string($post['username']), + "dateline" => (int)$post['dateline'], + "message" => $db->escape_string($post['message']), + "ipaddress" => $db->escape_binary($post['ipaddress']), + "includesig" => $post['options']['signature'], + "smilieoff" => $post['options']['disablesmilies'], + "visible" => $visible + ); + + $plugins->run_hooks("datahandler_post_insert_post", $this); + + $db->update_query("posts", $this->post_update_data, "pid='{$post['pid']}'"); + $this->pid = $post['pid']; + } + else + { + // Insert the post. + $this->post_insert_data = array( + "tid" => (int)$post['tid'], + "replyto" => (int)$post['replyto'], + "fid" => (int)$post['fid'], + "subject" => $db->escape_string($post['subject']), + "icon" => (int)$post['icon'], + "uid" => $post['uid'], + "username" => $db->escape_string($post['username']), + "dateline" => $post['dateline'], + "message" => $db->escape_string($post['message']), + "ipaddress" => $db->escape_binary($post['ipaddress']), + "includesig" => $post['options']['signature'], + "smilieoff" => $post['options']['disablesmilies'], + "visible" => $visible + ); + + $plugins->run_hooks("datahandler_post_insert_post", $this); + + $this->pid = $db->insert_query("posts", $this->post_insert_data); + } + + // Assign any uploaded attachments with the specific posthash to the newly created post. + if($post['posthash']) + { + $post['posthash'] = $db->escape_string($post['posthash']); + $attachmentassign = array( + "pid" => $this->pid, + "posthash" => '' + ); + $db->update_query("attachments", $attachmentassign, "posthash='{$post['posthash']}' AND pid='0'"); + } + + $thread_update = array(); + if($visible == 1 && $thread['visible'] == 1) + { + $thread = get_thread($post['tid']); + require_once MYBB_ROOT.'inc/class_parser.php'; + $parser = new Postparser; + + $done_users = array(); + + $subject = $parser->parse_badwords($thread['subject']); + $excerpt = $parser->text_parse_message($post['message'], array('me_username' => $post['username'], 'filter_badwords' => 1, 'safe_html' => 1)); + $excerpt = my_substr($excerpt, 0, $mybb->settings['subscribeexcerpt']).$lang->emailbit_viewthread; + + // Fetch any users subscribed to this thread receiving instant notification and queue up their subscription notices + $query = $db->query(" + SELECT u.username, u.email, u.uid, u.language, u.loginkey, u.salt, u.regdate, s.subscriptionkey, s.notification + FROM ".TABLE_PREFIX."threadsubscriptions s + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=s.uid) + WHERE (s.notification='1' OR s.notification='2') AND s.tid='{$post['tid']}' + AND s.uid != '{$post['uid']}' + AND u.lastactive>'{$thread['lastpost']}' + "); + while($subscribedmember = $db->fetch_array($query)) + { + if($done_users[$subscribedmember['uid']]) + { + continue; + } + $done_users[$subscribedmember['uid']] = 1; + + $forumpermissions = forum_permissions($thread['fid'], $subscribedmember['uid']); + if($forumpermissions['canview'] == 0 || $forumpermissions['canviewthreads'] == 0) + { + continue; + } + + if($thread['uid'] != $subscribedmember['uid'] && $forumpermissions['canonlyviewownthread'] == 1 && !is_moderator($thread['fid'], "", $subscribedmember['uid'])) + { + // User isn't a moderator or the author of the thread... + continue; + } + + if($subscribedmember['language'] != '' && $lang->language_exists($subscribedmember['language'])) + { + $uselang = $subscribedmember['language']; + } + elseif($mybb->settings['orig_bblanguage']) + { + $uselang = $mybb->settings['orig_bblanguage']; + } + else + { + $uselang = "english"; + } + + if($uselang == $mybb->settings['bblanguage']) + { + if($subscribedmember['notification'] == 1) + { + $emailsubject = $lang->emailsubject_subscription; + $emailmessage = $lang->email_subscription; + } + } + else + { + if($subscribedmember['notification'] == 1) + { + if(!isset($langcache[$uselang]['emailsubject_subscription'])) + { + $userlang = new MyLanguage; + $userlang->set_path(MYBB_ROOT."inc/languages"); + $userlang->set_language($uselang); + $userlang->load("messages"); + $langcache[$uselang]['emailsubject_subscription'] = $userlang->emailsubject_subscription; + $langcache[$uselang]['email_subscription'] = $userlang->email_subscription; + unset($userlang); + } + $emailsubject = $langcache[$uselang]['emailsubject_subscription']; + $emailmessage = $langcache[$uselang]['email_subscription']; + } + } + + if($subscribedmember['notification'] == 1) + { + $emailsubject = $lang->sprintf($emailsubject, $subject); + + $post_code = md5($subscribedmember['loginkey'].$subscribedmember['salt'].$subscribedmember['regdate']); + $emailmessage = $lang->sprintf($emailmessage, $subscribedmember['username'], $post['username'], $mybb->settings['bbname'], $subject, $excerpt, $mybb->settings['bburl'], str_replace("&", "&", get_thread_link($thread['tid'], 0, "newpost")), $thread['tid'], $subscribedmember['subscriptionkey'], $post_code); + $new_email = array( + "mailto" => $db->escape_string($subscribedmember['email']), + "mailfrom" => '', + "subject" => $db->escape_string($emailsubject), + "message" => $db->escape_string($emailmessage), + "headers" => '' + ); + $db->insert_query("mailqueue", $new_email); + unset($userlang); + $queued_email = 1; + } + elseif($subscribedmember['notification'] == 2) + { + $post_code = md5($subscribedmember['loginkey'].$subscribedmember['salt'].$subscribedmember['regdate']); + $pm = array( + 'subject' => array('pmsubject_subscription', $subject), + 'message' => array('pm_subscription', $subscribedmember['username'], $post['username'], $subject, $excerpt, $mybb->settings['bburl'], str_replace("&", "&", get_thread_link($thread['tid'], 0, "newpost")), $thread['tid'], $subscribedmember['subscriptionkey'], $post_code), + 'touid' => $subscribedmember['uid'], + 'language' => $subscribedmember['language'], + 'language_file' => 'messages' + ); + send_pm($pm, -1, true); + } + } + // Have one or more emails been queued? Update the queue count + if(isset($queued_email) && $queued_email == 1) + { + $cache->update_mailqueue(); + } + + $thread_update = array('replies' => '+1'); + + // Update forum count + update_last_post($post['tid']); + update_forum_counters($post['fid'], array("posts" => "+1")); + update_forum_lastpost($thread['fid']); + } + // Post is stuck in moderation queue + else if($visible == 0) + { + // Update the unapproved posts count for the current thread and current forum + $thread_update = array('unapprovedposts' => '+1'); + update_thread_counters($post['tid'], array("unapprovedposts" => "+1")); + update_forum_counters($post['fid'], array("unapprovedposts" => "+1")); + } + else if($thread['visible'] == 0) + { + // Update the unapproved posts count for the current forum + $thread_update = array('replies' => '+1'); + update_forum_counters($post['fid'], array("unapprovedposts" => "+1")); + } + else if($thread['visible'] == -1) + { + // Update the unapproved posts count for the current forum + $thread_update = array('replies' => '+1'); + update_forum_counters($post['fid'], array("deletedposts" => "+1")); + } + + $query = $db->simple_select("attachments", "COUNT(aid) AS attachmentcount", "pid='{$this->pid}' AND visible='1'"); + $attachmentcount = $db->fetch_field($query, "attachmentcount"); + if($attachmentcount > 0) + { + $thread_update['attachmentcount'] = "+{$attachmentcount}"; + } + update_thread_counters($post['tid'], $thread_update); + + // Return the post's pid and whether or not it is visible. + $this->return_values = array( + "pid" => $this->pid, + "visible" => $visible, + "closed" => $closed + ); + + $plugins->run_hooks("datahandler_post_insert_post_end", $this); + + return $this->return_values; + } + + /** + * Validate a thread. + * + * @return boolean True when valid, false when invalid. + */ + function validate_thread() + { + global $mybb, $db, $plugins; + + $thread = &$this->data; + + // Validate all thread assets. + + if(!$thread['savedraft']) + { + $this->verify_post_flooding(); + } + + if($this->method == "insert" || array_key_exists('uid', $thread)) + { + $this->verify_author(); + } + + if($this->method == "insert" || array_key_exists('prefix', $thread)) + { + $this->verify_prefix(); + } + + if($this->method == "insert" || array_key_exists('subject', $thread)) + { + $this->verify_subject(); + } + + if($this->method == "insert" || array_key_exists('message', $thread)) + { + $this->verify_message(); + $this->verify_image_count(); + $this->verify_video_count(); + } + + if($this->method == "insert" || array_key_exists('dateline', $thread)) + { + $this->verify_dateline(); + } + + if($this->method == "insert" || array_key_exists('icon', $thread)) + { + $this->verify_post_icon(); + } + + if($this->method == "insert" || array_key_exists('options', $thread)) + { + $this->verify_options(); + } + + $plugins->run_hooks("datahandler_post_validate_thread", $this); + + // We are done validating, return. + $this->set_validated(true); + if(count($this->get_errors()) > 0) + { + return false; + } + else + { + return true; + } + } + + /** + * Insert a thread into the database. + * + * @return array Array of new thread details, tid and visibility. + */ + function insert_thread() + { + global $db, $mybb, $plugins, $cache, $lang; + + // Yes, validating is required. + if(!$this->get_validated()) + { + die("The thread needs to be validated before inserting it into the DB."); + } + if(count($this->get_errors()) > 0) + { + die("The thread is not valid."); + } + + $thread = &$this->data; + + // Fetch the forum this thread is being made in + $forum = get_forum($thread['fid']); + + // This thread is being saved as a draft. + if($thread['savedraft']) + { + $visible = -2; + } + + // Thread is being made now and we have a bit to do. + else + { + $forumpermissions = forum_permissions($thread['fid'], $thread['uid']); + // Decide on the visibility of this post. + if($forumpermissions['modthreads'] == 1 && !is_moderator($thread['fid'], "", $thread['uid'])) + { + $visible = 0; + } + else + { + $visible = 1; + } + + // Are posts from this user being moderated? Change visibility + if($mybb->user['uid'] == $thread['uid'] && $mybb->user['moderateposts'] == 1) + { + $visible = 0; + } + } + + // Have a post ID but not a thread ID - fetch thread ID + if(!empty($thread['pid']) && !$thread['tid']) + { + $query = $db->simple_select("posts", "tid", "pid='{$thread['pid']}"); + $thread['tid'] = $db->fetch_field($query, "tid"); + } + + if(isset($thread['pid']) && $thread['pid'] > 0) + { + $query = $db->simple_select("posts", "pid", "pid='{$thread['pid']}' AND uid='{$thread['uid']}' AND visible='-2'"); + $draft_check = $db->fetch_field($query, "pid"); + } + else + { + $draft_check = false; + } + + // Are we updating a post which is already a draft? Perhaps changing it into a visible post? + if($draft_check) + { + $this->thread_insert_data = array( + "subject" => $db->escape_string($thread['subject']), + "icon" => (int)$thread['icon'], + "username" => $db->escape_string($thread['username']), + "dateline" => (int)$thread['dateline'], + "lastpost" => (int)$thread['dateline'], + "lastposter" => $db->escape_string($thread['username']), + "visible" => $visible + ); + + $plugins->run_hooks("datahandler_post_insert_thread", $this); + + $db->update_query("threads", $this->thread_insert_data, "tid='{$thread['tid']}'"); + + $this->post_insert_data = array( + "subject" => $db->escape_string($thread['subject']), + "icon" => (int)$thread['icon'], + "username" => $db->escape_string($thread['username']), + "dateline" => (int)$thread['dateline'], + "message" => $db->escape_string($thread['message']), + "ipaddress" => $db->escape_binary(my_inet_pton(get_ip())), + "includesig" => $thread['options']['signature'], + "smilieoff" => $thread['options']['disablesmilies'], + "visible" => $visible + ); + $plugins->run_hooks("datahandler_post_insert_thread_post", $this); + + $db->update_query("posts", $this->post_insert_data, "pid='{$thread['pid']}'"); + $this->tid = $thread['tid']; + $this->pid = $thread['pid']; + } + + // Inserting a new thread into the database. + else + { + $this->thread_insert_data = array( + "fid" => $thread['fid'], + "subject" => $db->escape_string($thread['subject']), + "prefix" => (int)$thread['prefix'], + "icon" => (int)$thread['icon'], + "uid" => $thread['uid'], + "username" => $db->escape_string($thread['username']), + "dateline" => (int)$thread['dateline'], + "lastpost" => (int)$thread['dateline'], + "lastposter" => $db->escape_string($thread['username']), + "views" => 0, + "replies" => 0, + "visible" => $visible, + "notes" => '' + ); + + $plugins->run_hooks("datahandler_post_insert_thread", $this); + + $this->tid = $db->insert_query("threads", $this->thread_insert_data); + + $this->post_insert_data = array( + "tid" => $this->tid, + "fid" => $thread['fid'], + "subject" => $db->escape_string($thread['subject']), + "icon" => (int)$thread['icon'], + "uid" => $thread['uid'], + "username" => $db->escape_string($thread['username']), + "dateline" => (int)$thread['dateline'], + "message" => $db->escape_string($thread['message']), + "ipaddress" => $db->escape_binary(my_inet_pton(get_ip())), + "includesig" => $thread['options']['signature'], + "smilieoff" => $thread['options']['disablesmilies'], + "visible" => $visible + ); + $plugins->run_hooks("datahandler_post_insert_thread_post", $this); + + $this->pid = $db->insert_query("posts", $this->post_insert_data); + + // Now that we have the post id for this first post, update the threads table. + $firstpostup = array("firstpost" => $this->pid); + $db->update_query("threads", $firstpostup, "tid='{$this->tid}'"); + } + + // If we're not saving a draft there are some things we need to check now + if(!$thread['savedraft']) + { + if($thread['options']['subscriptionmethod'] != "" && $thread['uid'] > 0) + { + switch($thread['options']['subscriptionmethod']) + { + case "pm": + $notification = 2; + break; + case "email": + $notification = 1; + break; + default: + $notification = 0; + } + + require_once MYBB_ROOT."inc/functions_user.php"; + add_subscribed_thread($this->tid, $notification, $thread['uid']); + } + + // Perform any selected moderation tools. + if(is_moderator($thread['fid'], "", $thread['uid']) && is_array($thread['modoptions'])) + { + $lang->load($this->language_file, true); + + $modoptions = $thread['modoptions']; + $modlogdata['fid'] = $thread['fid']; + if(isset($thread['tid'])) + { + $modlogdata['tid'] = $thread['tid']; + } + + $newclosed = $newstick = ''; + + // Close the thread. + if(isset($modoptions['closethread']) && $modoptions['closethread'] == 1) + { + $newclosed = "closed=1"; + log_moderator_action($modlogdata, $lang->thread_closed); + } + + // Stick the thread. + if(isset($modoptions['stickthread']) && $modoptions['stickthread'] == 1) + { + $newstick = "sticky='1'"; + log_moderator_action($modlogdata, $lang->thread_stuck); + } + + // Execute moderation options. + if($newstick && $newclosed) + { + $sep = ","; + } + else + { + $sep = ''; + } + if($newstick || $newclosed) + { + $db->write_query(" + UPDATE ".TABLE_PREFIX."threads + SET $newclosed$sep$newstick + WHERE tid='{$this->tid}' + "); + } + } + if($visible == 1) + { + // If we have a registered user then update their post count and last post times. + if($thread['uid'] > 0) + { + $user = get_user($thread['uid']); + $update_query = array(); + // Only update the lastpost column of the user if the date of the thread is newer than their last post. + if($thread['dateline'] > $user['lastpost']) + { + // Yes this has a single quote within a double quote. It's not a bug. + $update_query['lastpost'] = "'{$thread['dateline']}'"; + } + // Update the post count if this forum allows post counts to be tracked + if($forum['usepostcounts'] != 0) + { + $update_query['postnum'] = "postnum+1"; + } + if($forum['usethreadcounts'] != 0) + { + $update_query['threadnum'] = 'threadnum+1'; + } + + // Only update the table if we need to. + if(!empty($update_query)) + { + $db->update_query("users", $update_query, "uid='{$thread['uid']}'", 1, true); + } + } + + if(!isset($forum['lastpost'])) + { + $forum['lastpost'] = 0; + } + + $done_users = array(); + + // Queue up any forum subscription notices to users who are subscribed to this forum. + $excerpt = my_substr($thread['message'], 0, $mybb->settings['subscribeexcerpt']).$lang->emailbit_viewthread; + + // Parse badwords + require_once MYBB_ROOT."inc/class_parser.php"; + $parser = new postParser; + $excerpt = $parser->parse_badwords($excerpt); + + $query = $db->query(" + SELECT u.username, u.email, u.uid, u.language, u.loginkey, u.salt, u.regdate + FROM ".TABLE_PREFIX."forumsubscriptions fs + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=fs.uid) + LEFT JOIN ".TABLE_PREFIX."usergroups g ON (g.gid=u.usergroup) + WHERE fs.fid='".(int)$thread['fid']."' + AND fs.uid != '".(int)$thread['uid']."' + AND u.lastactive > '{$forum['lastpost']}' + AND g.isbannedgroup != 1 + "); + while($subscribedmember = $db->fetch_array($query)) + { + if($done_users[$subscribedmember['uid']]) + { + continue; + } + $done_users[$subscribedmember['uid']] = 1; + + $forumpermissions = forum_permissions($thread['fid'], $subscribedmember['uid']); + if($forumpermissions['canview'] == 0 || $forumpermissions['canviewthreads'] == 0) + { + continue; + } + + if(!is_moderator($thread['fid'], "", $subscribedmember['uid']) && $forumpermissions['canonlyviewownthreads'] == 1) + { + // In a 'view own only' forum and not a moderator + continue; + } + + // Determine the language pack we'll be using to send this email in and load it if it isn't already. + if($subscribedmember['language'] != '' && $lang->language_exists($subscribedmember['language'])) + { + $uselang = $subscribedmember['language']; + } + else if($mybb->settings['bblanguage']) + { + $uselang = $mybb->settings['bblanguage']; + } + else + { + $uselang = "english"; + } + + if($uselang == $mybb->settings['bblanguage']) + { + $emailsubject = $lang->emailsubject_forumsubscription; + $emailmessage = $lang->email_forumsubscription; + } + else + { + if(!isset($langcache[$uselang]['emailsubject_forumsubscription'])) + { + $userlang = new MyLanguage; + $userlang->set_path(MYBB_ROOT."inc/languages"); + $userlang->set_language($uselang); + $userlang->load("messages"); + $langcache[$uselang]['emailsubject_forumsubscription'] = $userlang->emailsubject_forumsubscription; + $langcache[$uselang]['email_forumsubscription'] = $userlang->email_forumsubscription; + unset($userlang); + } + $emailsubject = $langcache[$uselang]['emailsubject_forumsubscription']; + $emailmessage = $langcache[$uselang]['email_forumsubscription']; + } + $emailsubject = $lang->sprintf($emailsubject, $forum['name']); + + $post_code = md5($subscribedmember['loginkey'].$subscribedmember['salt'].$subscribedmember['regdate']); + $emailmessage = $lang->sprintf($emailmessage, $subscribedmember['username'], $thread['username'], $forum['name'], $mybb->settings['bbname'], $thread['subject'], $excerpt, $mybb->settings['bburl'], get_thread_link($this->tid), $thread['fid'], $post_code); + $new_email = array( + "mailto" => $db->escape_string($subscribedmember['email']), + "mailfrom" => '', + "subject" => $db->escape_string($emailsubject), + "message" => $db->escape_string($emailmessage), + "headers" => '' + ); + $db->insert_query("mailqueue", $new_email); + unset($userlang); + $queued_email = 1; + } + // Have one or more emails been queued? Update the queue count + if(isset($queued_email) && $queued_email == 1) + { + $cache->update_mailqueue(); + } + } + } + + // Assign any uploaded attachments with the specific posthash to the newly created post. + if($thread['posthash']) + { + $thread['posthash'] = $db->escape_string($thread['posthash']); + $attachmentassign = array( + "pid" => $this->pid, + "posthash" => '' + ); + $db->update_query("attachments", $attachmentassign, "posthash='{$thread['posthash']}' AND pid='0'"); + } + + if($visible == 1) + { + update_last_post($this->tid); + update_forum_counters($thread['fid'], array("threads" => "+1", "posts" => "+1")); + update_forum_lastpost($thread['fid']); + } + else if($visible == 0) + { + update_forum_counters($thread['fid'], array("unapprovedthreads" => "+1", "unapprovedposts" => "+1")); + } + + $query = $db->simple_select("attachments", "COUNT(aid) AS attachmentcount", "pid='{$this->pid}' AND visible='1'"); + $attachmentcount = $db->fetch_field($query, "attachmentcount"); + if($attachmentcount > 0) + { + update_thread_counters($this->tid, array("attachmentcount" => "+{$attachmentcount}")); + } + + // Return the post's pid and whether or not it is visible. + $this->return_values = array( + "pid" => $this->pid, + "tid" => $this->tid, + "visible" => $visible + ); + + $plugins->run_hooks("datahandler_post_insert_thread_end", $this); + + return $this->return_values; + } + + /** + * Updates a post that is already in the database. + * + */ + function update_post() + { + global $db, $mybb, $plugins; + + // Yes, validating is required. + if($this->get_validated() != true) + { + die("The post needs to be validated before inserting it into the DB."); + } + if(count($this->get_errors()) > 0) + { + die("The post is not valid."); + } + + $post = &$this->data; + + $post['pid'] = (int)$post['pid']; + + $existing_post = get_post($post['pid']); + $post['tid'] = $existing_post['tid']; + $post['fid'] = $existing_post['fid']; + + $forum = get_forum($post['fid']); + $forumpermissions = forum_permissions($post['fid'], $post['uid']); + + // Check if this is the first post in a thread. + $options = array( + "order_by" => "dateline", + "order_dir" => "asc", + "limit_start" => 0, + "limit" => 1 + ); + $query = $db->simple_select("posts", "pid", "tid='".(int)$post['tid']."'", $options); + $first_post_check = $db->fetch_array($query); + if($first_post_check['pid'] == $post['pid']) + { + $first_post = true; + } + else + { + $first_post = false; + } + + // Decide on the visibility of this post. + $ismod = is_moderator($post['fid'], "", $post['uid']); + + // Keep visibility for unapproved and deleted posts + if($existing_post['visible'] == 0) + { + $visible = 0; + } + elseif($existing_post['visible'] == -1) + { + $visible = -1; + } + elseif($forumpermissions['mod_edit_posts'] == 1 && !$ismod) + { + $visible = 0; + require_once MYBB_ROOT."inc/class_moderation.php"; + $moderation = new Moderation; + $moderation->unapprove_posts(array($post['pid'])); + } + else + { + $visible = 1; + } + + // Update the thread details that might have been changed first. + if($first_post) + { + $this->tid = $post['tid']; + + if(isset($post['prefix'])) + { + $this->thread_update_data['prefix'] = (int)$post['prefix']; + } + + if(isset($post['subject'])) + { + $this->thread_update_data['subject'] = $db->escape_string($post['subject']); + } + + if(isset($post['icon'])) + { + $this->thread_update_data['icon'] = (int)$post['icon']; + } + if(count($this->thread_update_data) > 0) + { + $plugins->run_hooks("datahandler_post_update_thread", $this); + + $db->update_query("threads", $this->thread_update_data, "tid='".(int)$post['tid']."'"); + } + } + + // Prepare array for post updating. + + $this->pid = $post['pid']; + + if(isset($post['subject'])) + { + $this->post_update_data['subject'] = $db->escape_string($post['subject']); + } + + if(isset($post['message'])) + { + $this->post_update_data['message'] = $db->escape_string($post['message']); + } + + if(isset($post['editreason']) && trim($post['editreason']) != '') + { + $this->post_update_data['editreason'] = $db->escape_string(trim($post['editreason'])); + } + + if(isset($post['icon'])) + { + $this->post_update_data['icon'] = (int)$post['icon']; + } + + if(isset($post['options'])) + { + if(isset($post['options']['disablesmilies'])) + { + $this->post_update_data['smilieoff'] = $db->escape_string($post['options']['disablesmilies']); + } + if(isset($post['options']['signature'])) + { + $this->post_update_data['includesig'] = $db->escape_string($post['options']['signature']); + } + } + + // If we need to show the edited by, let's do so. + if(($mybb->settings['showeditedby'] == 1 && !is_moderator($post['fid'], "caneditposts", $post['edit_uid'])) || ($mybb->settings['showeditedbyadmin'] == 1 && is_moderator($post['fid'], "caneditposts", $post['edit_uid']))) + { + $this->post_update_data['edituid'] = (int)$post['edit_uid']; + $this->post_update_data['edittime'] = TIME_NOW; + } + + $plugins->run_hooks("datahandler_post_update", $this); + + $db->update_query("posts", $this->post_update_data, "pid='".(int)$post['pid']."'"); + + // Automatic subscription to the thread + if($post['options']['subscriptionmethod'] != "" && $post['uid'] > 0) + { + switch($post['options']['subscriptionmethod']) + { + case "pm": + $notification = 2; + break; + case "email": + $notification = 1; + break; + default: + $notification = 0; + } + require_once MYBB_ROOT."inc/functions_user.php"; + add_subscribed_thread($post['tid'], $notification, $post['uid']); + } + else + { + $db->delete_query("threadsubscriptions", "uid='".(int)$post['uid']."' AND tid='".(int)$post['tid']."'"); + } + + update_forum_lastpost($post['fid']); + update_last_post($post['tid']); + + // Return the thread's first post id and whether or not it is visible. + $this->return_values = array( + 'visible' => $visible, + 'first_post' => $first_post + ); + + $plugins->run_hooks("datahandler_post_update_end", $this); + + return $this->return_values; + } +} diff --git a/Upload/inc/datahandlers/user.php b/Upload/inc/datahandlers/user.php new file mode 100644 index 0000000..38c63b9 --- /dev/null +++ b/Upload/inc/datahandlers/user.php @@ -0,0 +1,1680 @@ +
    Please make sure IN_MYBB is defined."); +} + +/** + * User handling class, provides common structure to handle user data. + * + */ +class UserDataHandler extends DataHandler +{ + /** + * The language file used in the data handler. + * + * @var string + */ + public $language_file = 'datahandler_user'; + + /** + * The prefix for the language variables used in the data handler. + * + * @var string + */ + public $language_prefix = 'userdata'; + + /** + * Array of data inserted in to a user. + * + * @var array + */ + public $user_insert_data = array(); + + /** + * Array of data used to update a user. + * + * @var array + */ + public $user_update_data = array(); + + /** + * User ID currently being manipulated by the datahandlers. + * + * @var int + */ + public $uid = 0; + + /** + * Values to be returned after inserting/deleting an user. + * + * @var array + */ + public $return_values = array(); + + /** + * Verifies if a username is valid or invalid. + * + * @param boolean True when valid, false when invalid. + */ + function verify_username() + { + global $mybb; + + $username = &$this->data['username']; + require_once MYBB_ROOT.'inc/functions_user.php'; + + // Fix bad characters + $username = trim_blank_chrs($username); + $username = str_replace(array(unichr(160), unichr(173), unichr(0xCA), dec_to_utf8(8238), dec_to_utf8(8237), dec_to_utf8(8203)), array(" ", "-", "", "", "", ""), $username); + + // Remove multiple spaces from the username + $username = preg_replace("#\s{2,}#", " ", $username); + + // Check if the username is not empty. + if($username == '') + { + $this->set_error('missing_username'); + return false; + } + + // Check if the username belongs to the list of banned usernames. + if(is_banned_username($username, true)) + { + $this->set_error('banned_username'); + return false; + } + + // Check for certain characters in username (<, >, &, commas and slashes) + if(strpos($username, "<") !== false || strpos($username, ">") !== false || strpos($username, "&") !== false || my_strpos($username, "\\") !== false || strpos($username, ";") !== false || strpos($username, ",") !== false || !validate_utf8_string($username, false, false)) + { + $this->set_error("bad_characters_username"); + return false; + } + + // Check if the username is of the correct length. + if(($mybb->settings['maxnamelength'] != 0 && my_strlen($username) > $mybb->settings['maxnamelength']) || ($mybb->settings['minnamelength'] != 0 && my_strlen($username) < $mybb->settings['minnamelength'])) + { + $this->set_error('invalid_username_length', array($mybb->settings['minnamelength'], $mybb->settings['maxnamelength'])); + return false; + } + + return true; + } + + /** + * Verifies if a usertitle is valid or invalid. + * + * @param boolean True when valid, false when invalid. + */ + function verify_usertitle() + { + global $mybb; + + $usertitle = &$this->data['usertitle']; + + // Check if the usertitle is of the correct length. + if($mybb->settings['customtitlemaxlength'] != 0 && my_strlen($usertitle) > $mybb->settings['customtitlemaxlength']) + { + $this->set_error('invalid_usertitle_length', $mybb->settings['customtitlemaxlength']); + return false; + } + + return true; + } + + /** + * Verifies if a username is already in use or not. + * + * @return boolean False when the username is not in use, true when it is. + */ + function verify_username_exists() + { + $username = &$this->data['username']; + + $user = get_user_by_username(trim($username)); + + if(!empty($this->data['uid']) && !empty($user['uid']) && $user['uid'] == $this->data['uid']) + { + unset($user); + } + + if(!empty($user['uid'])) + { + $this->set_error("username_exists", array($username)); + return true; + } + + return false; + } + + /** + * Verifies if a new password is valid or not. + * + * @return boolean True when valid, false when invalid. + */ + function verify_password() + { + global $mybb; + + $user = &$this->data; + + // Always check for the length of the password. + if(my_strlen($user['password']) < $mybb->settings['minpasswordlength'] || my_strlen($user['password']) > $mybb->settings['maxpasswordlength']) + { + $this->set_error('invalid_password_length', array($mybb->settings['minpasswordlength'], $mybb->settings['maxpasswordlength'])); + return false; + } + + // Has the user tried to use their email address or username as a password? + if($user['email'] == $user['password'] || $user['username'] == $user['password']) + { + $this->set_error('bad_password_security'); + return false; + } + + // See if the board has "require complex passwords" enabled. + if($mybb->settings['requirecomplexpasswords'] == 1) + { + // Complex passwords required, do some extra checks. + // First, see if there is one or more complex character(s) in the password. + if(!preg_match("/^.*(?=.{".$mybb->settings['minpasswordlength'].",})(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$/", $user['password'])) + { + $this->set_error('no_complex_characters', array($mybb->settings['minpasswordlength'])); + return false; + } + } + + // If we have a "password2" check if they both match + if(isset($user['password2']) && $user['password'] != $user['password2']) + { + $this->set_error("passwords_dont_match"); + return false; + } + + // MD5 the password + $user['md5password'] = md5($user['password']); + + // Generate our salt + $user['salt'] = generate_salt(); + + // Combine the password and salt + $user['saltedpw'] = salt_password($user['md5password'], $user['salt']); + + // Generate the user login key + $user['loginkey'] = generate_loginkey(); + + return true; + } + + /** + * Verifies usergroup selections and other group details. + * + * @return boolean True when valid, false when invalid. + */ + function verify_usergroup() + { + $user = &$this->data; + return true; + } + /** + * Verifies if an email address is valid or not. + * + * @return boolean True when valid, false when invalid. + */ + function verify_email() + { + global $mybb; + + $user = &$this->data; + + // Check if an email address has actually been entered. + if(trim_blank_chrs($user['email']) == '') + { + $this->set_error('missing_email'); + return false; + } + + // Check if this is a proper email address. + if(!validate_email_format($user['email'])) + { + $this->set_error('invalid_email_format'); + return false; + } + + // Check banned emails + if(is_banned_email($user['email'], true)) + { + $this->set_error('banned_email'); + return false; + } + + // Check signed up emails + // Ignore the ACP because the Merge System sometimes produces users with duplicate email addresses (Not A Bug) + if($mybb->settings['allowmultipleemails'] == 0 && !defined("IN_ADMINCP")) + { + $uid = 0; + if(isset($user['uid'])) + { + $uid = $user['uid']; + } + if(email_already_in_use($user['email'], $uid)) + { + $this->set_error('email_already_in_use'); + return false; + } + } + + // If we have an "email2", verify it matches the existing email + if(isset($user['email2']) && $user['email'] != $user['email2']) + { + $this->set_error("emails_dont_match"); + return false; + } + + return true; + } + + /** + * Verifies if a website is valid or not. + * + * @return boolean True when valid, false when invalid. + */ + function verify_website() + { + $website = &$this->data['website']; + + if(empty($website) || my_strtolower($website) == 'http://' || my_strtolower($website) == 'https://') + { + $website = ''; + return true; + } + + // Does the website start with http(s)://? + if(my_strtolower(substr($website, 0, 4)) != "http") + { + // Website does not start with http://, let's see if the user forgot. + $website = "http://".$website; + } + + if(!filter_var($website, FILTER_VALIDATE_URL)) + { + $this->set_error('invalid_website'); + return false; + } + + return true; + } + + /** + * Verifies if an ICQ number is valid or not. + * + * @return boolean True when valid, false when invalid. + */ + function verify_icq() + { + $icq = &$this->data['icq']; + + if($icq != '' && !is_numeric($icq)) + { + $this->set_error("invalid_icq_number"); + return false; + } + $icq = (int)$icq; + return true; + } + + /** + * Verifies if a birthday is valid or not. + * + * @return boolean True when valid, false when invalid. + */ + function verify_birthday() + { + global $mybb; + + $user = &$this->data; + $birthday = &$user['birthday']; + + if(!is_array($birthday)) + { + return true; + } + + // Sanitize any input we have + $birthday['day'] = (int)$birthday['day']; + $birthday['month'] = (int)$birthday['month']; + $birthday['year'] = (int)$birthday['year']; + + // Error if a day and month exists, and the birthday day and range is not in range + if($birthday['day'] != 0 || $birthday['month'] != 0) + { + if($birthday['day'] < 1 || $birthday['day'] > 31 || $birthday['month'] < 1 || $birthday['month'] > 12 || ($birthday['month'] == 2 && $birthday['day'] > 29)) + { + $this->set_error("invalid_birthday"); + return false; + } + } + + // Check if the day actually exists. + $months = get_bdays($birthday['year']); + if($birthday['month'] != 0 && $birthday['day'] > $months[$birthday['month']-1]) + { + $this->set_error("invalid_birthday"); + return false; + } + + // Error if a year exists and the year is out of range + if($birthday['year'] != 0 && ($birthday['year'] < (date("Y")-100)) || $birthday['year'] > date("Y")) + { + $this->set_error("invalid_birthday"); + return false; + } + else if($birthday['year'] == date("Y")) + { + // Error if birth date is in future + if($birthday['month'] > date("m") || ($birthday['month'] == date("m") && $birthday['day'] > date("d"))) + { + $this->set_error("invalid_birthday"); + return false; + } + } + + // Error if COPPA is on, and the user hasn't verified their age / under 13 + if($mybb->settings['coppa'] == "enabled" && ($birthday['year'] == 0 || !$birthday['year'])) + { + $this->set_error("invalid_birthday_coppa"); + return false; + } + elseif(($mybb->settings['coppa'] == "deny" && $birthday['year'] > (date("Y")-13)) && !is_moderator()) + { + $this->set_error("invalid_birthday_coppa2"); + return false; + } + + // Make the user's birthday field + if($birthday['year'] != 0) + { + // If the year is specified, put together a d-m-y string + $user['bday'] = $birthday['day']."-".$birthday['month']."-".$birthday['year']; + } + elseif($birthday['day'] && $birthday['month']) + { + // If only a day and month are specified, put together a d-m string + $user['bday'] = $birthday['day']."-".$birthday['month']."-"; + } + else + { + // No field is specified, so return an empty string for an unknown birthday + $user['bday'] = ''; + } + return true; + } + + /** + * Verifies if the birthday privacy option is valid or not. + * + * @return boolean True when valid, false when invalid. + */ + function verify_birthday_privacy() + { + $birthdayprivacy = &$this->data['birthdayprivacy']; + $accepted = array( + 'none', + 'age', + 'all'); + + if(!in_array($birthdayprivacy, $accepted)) + { + $this->set_error("invalid_birthday_privacy"); + return false; + } + return true; + } + + /** + * Verifies if the post count field is filled in correctly. + * + * @return boolean True when valid, false when invalid. + */ + function verify_postnum() + { + $user = &$this->data; + + if(isset($user['postnum']) && $user['postnum'] < 0) + { + $this->set_error("invalid_postnum"); + return false; + } + + return true; + } + + /** + * Verifies if the thread count field is filled in correctly. + * + * @return boolean True when valid, false when invalid. + */ + function verify_threadnum() + { + $user = &$this->data; + + if(isset($user['threadnum']) && $user['threadnum'] < 0) + { + $this->set_error("invalid_threadnum"); + return false; + } + + return true; + } + + /** + * Verifies if a profile fields are filled in correctly. + * + * @return boolean True when valid, false when invalid. + */ + function verify_profile_fields() + { + global $db, $cache; + + $user = &$this->data; + $profile_fields = &$this->data['profile_fields']; + + // Loop through profile fields checking if they exist or not and are filled in. + $userfields = array(); + $comma = ''; + + // Fetch all profile fields first. + $pfcache = $cache->read('profilefields'); + + if(is_array($pfcache)) + { + // Then loop through the profile fields. + foreach($pfcache as $profilefield) + { + if(isset($this->data['profile_fields_editable']) || isset($this->data['registration']) && ($profilefield['required'] == 1 || $profilefield['registration'] == 1)) + { + $profilefield['editableby'] = -1; + } + + if(empty($profilefield['editableby']) || ($profilefield['editableby'] != -1 && !is_member($profilefield['editableby'], array('usergroup' => $user['usergroup'], 'additionalgroups' => $user['additionalgroups'])))) + { + continue; + } + + // Does this field have a minimum post count? + if(!isset($this->data['profile_fields_editable']) && !empty($profilefield['postnum']) && $profilefield['postnum'] > $user['postnum']) + { + continue; + } + + $profilefield['type'] = htmlspecialchars_uni($profilefield['type']); + $thing = explode("\n", $profilefield['type'], "2"); + $type = trim($thing[0]); + $field = "fid{$profilefield['fid']}"; + + if(!isset($profile_fields[$field])) + { + $profile_fields[$field] = ''; + } + + // If the profile field is required, but not filled in, present error. + if($type != "multiselect" && $type != "checkbox") + { + if(trim($profile_fields[$field]) == "" && $profilefield['required'] == 1 && !defined('IN_ADMINCP') && THIS_SCRIPT != "modcp.php") + { + $this->set_error('missing_required_profile_field', array($profilefield['name'])); + } + } + elseif(($type == "multiselect" || $type == "checkbox") && $profile_fields[$field] == "" && $profilefield['required'] == 1 && !defined('IN_ADMINCP') && THIS_SCRIPT != "modcp.php") + { + $this->set_error('missing_required_profile_field', array($profilefield['name'])); + } + + // Sort out multiselect/checkbox profile fields. + $options = ''; + if(($type == "multiselect" || $type == "checkbox") && is_array($profile_fields[$field])) + { + $expoptions = explode("\n", $thing[1]); + $expoptions = array_map('trim', $expoptions); + foreach($profile_fields[$field] as $value) + { + if(!in_array(htmlspecialchars_uni($value), $expoptions)) + { + $this->set_error('bad_profile_field_values', array($profilefield['name'])); + } + if($options) + { + $options .= "\n"; + } + $options .= $db->escape_string($value); + } + } + elseif($type == "select" || $type == "radio") + { + $expoptions = explode("\n", $thing[1]); + $expoptions = array_map('trim', $expoptions); + if(!in_array(htmlspecialchars_uni($profile_fields[$field]), $expoptions) && trim($profile_fields[$field]) != "") + { + $this->set_error('bad_profile_field_values', array($profilefield['name'])); + } + $options = $db->escape_string($profile_fields[$field]); + } + else + { + if($profilefield['maxlength'] > 0 && my_strlen($profile_fields[$field]) > $profilefield['maxlength']) + { + $this->set_error('max_limit_reached', array($profilefield['name'], $profilefield['maxlength'])); + } + + if(!empty($profilefield['regex']) && !preg_match("#".$profilefield['regex']."#i", $profile_fields[$field])) + { + $this->set_error('bad_profile_field_value', array($profilefield['name'])); + } + + $options = $db->escape_string($profile_fields[$field]); + } + $user['user_fields'][$field] = $options; + } + } + + return true; + } + + /** + * Verifies if an optionally entered referrer exists or not. + * + * @return boolean True when valid, false when invalid. + */ + function verify_referrer() + { + global $db, $mybb; + + $user = &$this->data; + + // Does the referrer exist or not? + if($mybb->settings['usereferrals'] == 1 && $user['referrer'] != '') + { + $referrer = get_user_by_username($user['referrer']); + + if(empty($referrer['uid'])) + { + $this->set_error('invalid_referrer', array($user['referrer'])); + return false; + } + + $user['referrer_uid'] = $referrer['uid']; + } + else + { + $user['referrer_uid'] = 0; + } + + return true; + } + + /** + * Verifies user options. + * + * @return boolean True when valid, false when invalid. + */ + function verify_options() + { + global $mybb; + + $options = &$this->data['options']; + + // Verify yes/no options. + $this->verify_yesno_option($options, 'allownotices', 1); + $this->verify_yesno_option($options, 'hideemail', 0); + $this->verify_yesno_option($options, 'receivepms', 1); + $this->verify_yesno_option($options, 'receivefrombuddy', 0); + $this->verify_yesno_option($options, 'pmnotice', 1); + $this->verify_yesno_option($options, 'pmnotify', 1); + $this->verify_yesno_option($options, 'invisible', 0); + $this->verify_yesno_option($options, 'showimages', 1); + $this->verify_yesno_option($options, 'showvideos', 1); + $this->verify_yesno_option($options, 'showsigs', 1); + $this->verify_yesno_option($options, 'showavatars', 1); + $this->verify_yesno_option($options, 'showquickreply', 1); + $this->verify_yesno_option($options, 'showredirect', 1); + $this->verify_yesno_option($options, 'showcodebuttons', 1); + $this->verify_yesno_option($options, 'sourceeditor', 1); + + if($mybb->settings['postlayout'] == 'classic') + { + $this->verify_yesno_option($options, 'classicpostbit', 1); + } + else + { + $this->verify_yesno_option($options, 'classicpostbit', 0); + } + + if(array_key_exists('subscriptionmethod', $options)) + { + // Value out of range + $options['subscriptionmethod'] = (int)$options['subscriptionmethod']; + if($options['subscriptionmethod'] < 0 || $options['subscriptionmethod'] > 3) + { + $options['subscriptionmethod'] = 0; + } + } + + if(array_key_exists('dstcorrection', $options)) + { + // Value out of range + $options['dstcorrection'] = (int)$options['dstcorrection']; + if($options['dstcorrection'] < 0 || $options['dstcorrection'] > 2) + { + $options['dstcorrection'] = 0; + } + } + + if($options['dstcorrection'] == 1) + { + $options['dst'] = 1; + } + else if($options['dstcorrection'] == 0) + { + $options['dst'] = 0; + } + + if($this->method == "insert" || (isset($options['threadmode']) && $options['threadmode'] != "linear" && $options['threadmode'] != "threaded")) + { + if($mybb->settings['threadusenetstyle']) + { + $options['threadmode'] = 'threaded'; + } + else + { + $options['threadmode'] = 'linear'; + } + } + + // Verify the "threads per page" option. + if($this->method == "insert" || (array_key_exists('tpp', $options) && $mybb->settings['usertppoptions'])) + { + if(!isset($options['tpp'])) + { + $options['tpp'] = 0; + } + $explodedtpp = explode(",", $mybb->settings['usertppoptions']); + if(is_array($explodedtpp)) + { + @asort($explodedtpp); + $biggest = $explodedtpp[count($explodedtpp)-1]; + // Is the selected option greater than the allowed options? + if($options['tpp'] > $biggest) + { + $options['tpp'] = $biggest; + } + } + $options['tpp'] = (int)$options['tpp']; + } + // Verify the "posts per page" option. + if($this->method == "insert" || (array_key_exists('ppp', $options) && $mybb->settings['userpppoptions'])) + { + if(!isset($options['ppp'])) + { + $options['ppp'] = 0; + } + $explodedppp = explode(",", $mybb->settings['userpppoptions']); + if(is_array($explodedppp)) + { + @asort($explodedppp); + $biggest = $explodedppp[count($explodedppp)-1]; + // Is the selected option greater than the allowed options? + if($options['ppp'] > $biggest) + { + $options['ppp'] = $biggest; + } + } + $options['ppp'] = (int)$options['ppp']; + } + // Is our selected "days prune" option valid or not? + if($this->method == "insert" || array_key_exists('daysprune', $options)) + { + if(!isset($options['daysprune'])) + { + $options['daysprune'] = 0; + } + $options['daysprune'] = (int)$options['daysprune']; + if($options['daysprune'] < 0) + { + $options['daysprune'] = 0; + } + } + $this->data['options'] = $options; + } + + /** + * Verifies if a registration date is valid or not. + * + * @return boolean True when valid, false when invalid. + */ + function verify_regdate() + { + $regdate = &$this->data['regdate']; + + $regdate = (int)$regdate; + // If the timestamp is below 0, set it to the current time. + if($regdate <= 0) + { + $regdate = TIME_NOW; + } + return true; + } + + /** + * Verifies if a last visit date is valid or not. + * + * @return boolean True when valid, false when invalid. + */ + function verify_lastvisit() + { + $lastvisit = &$this->data['lastvisit']; + + $lastvisit = (int)$lastvisit; + // If the timestamp is below 0, set it to the current time. + if($lastvisit <= 0) + { + $lastvisit = TIME_NOW; + } + return true; + + } + + /** + * Verifies if a last active date is valid or not. + * + * @return boolean True when valid, false when invalid. + */ + function verify_lastactive() + { + $lastactive = &$this->data['lastactive']; + + $lastactive = (int)$lastactive; + // If the timestamp is below 0, set it to the current time. + if($lastactive <= 0) + { + $lastactive = TIME_NOW; + } + return true; + + } + + /** + * Verifies if an away mode status is valid or not. + * + * @return boolean True when valid, false when invalid. + */ + function verify_away() + { + global $mybb; + + $user = &$this->data; + // If the board does not allow "away mode" or the user is marking as not away, set defaults. + if($mybb->settings['allowaway'] == 0 || !isset($user['away']['away']) || $user['away']['away'] != 1) + { + $user['away']['away'] = 0; + $user['away']['date'] = 0; + $user['away']['returndate'] = 0; + $user['away']['awayreason'] = ''; + return true; + } + else if($user['away']['returndate']) + { + list($returnday, $returnmonth, $returnyear) = explode('-', $user['away']['returndate']); + if(!$returnday || !$returnmonth || !$returnyear) + { + $this->set_error("missing_returndate"); + return false; + } + + // Validate the return date lengths + $user['away']['returndate'] = substr($returnday, 0, 2).'-'.substr($returnmonth, 0, 2).'-'.substr($returnyear, 0, 4); + } + return true; + } + + /** + * Verifies if a langage is valid for this user or not. + * + * @return boolean True when valid, false when invalid. + */ + function verify_language() + { + global $lang; + + $language = &$this->data['language']; + + // An invalid language has been specified? + if($language != '' && !$lang->language_exists($language)) + { + $this->set_error("invalid_language"); + return false; + } + return true; + } + + /** + * Verifies if this is coming from a spam bot or not + * + * @return boolean True when valid, false when invalid. + */ + function verify_checkfields() + { + $user = &$this->data; + + // An invalid language has been specified? + if($user['regcheck1'] !== "" || $user['regcheck2'] !== "true") + { + $this->set_error("invalid_checkfield"); + return false; + } + return true; + } + + /** + * Validate all user assets. + * + * @return boolean True when valid, false when invalid. + */ + function validate_user() + { + global $mybb, $plugins; + + $user = &$this->data; + + // First, grab the old user details if this user exists + if(!empty($user['uid'])) + { + $old_user = get_user($user['uid']); + } + + if($this->method == "insert" || array_key_exists('username', $user)) + { + // If the username is the same - no need to verify + if(!isset($old_user['username']) || $user['username'] != $old_user['username']) + { + $this->verify_username(); + $this->verify_username_exists(); + } + else + { + unset($user['username']); + } + } + if($this->method == "insert" || array_key_exists('usertitle', $user)) + { + $this->verify_usertitle(); + } + if($this->method == "insert" || array_key_exists('password', $user)) + { + $this->verify_password(); + } + if($this->method == "insert" || array_key_exists('usergroup', $user)) + { + $this->verify_usergroup(); + } + if($this->method == "insert" || array_key_exists('email', $user)) + { + $this->verify_email(); + } + if($this->method == "insert" || array_key_exists('website', $user)) + { + $this->verify_website(); + } + if($this->method == "insert" || array_key_exists('icq', $user)) + { + $this->verify_icq(); + } + if($this->method == "insert" || (isset($user['birthday']) && is_array($user['birthday']))) + { + $this->verify_birthday(); + } + if($this->method == "insert" || array_key_exists('postnum', $user)) + { + $this->verify_postnum(); + } + if($this->method == "insert" || array_key_exists('threadnum', $user)) + { + $this->verify_threadnum(); + } + if($this->method == "insert" || array_key_exists('profile_fields', $user)) + { + $this->verify_profile_fields(); + } + if($this->method == "insert" || array_key_exists('referrer', $user)) + { + $this->verify_referrer(); + } + if($this->method == "insert" || array_key_exists('options', $user)) + { + $this->verify_options(); + } + if($this->method == "insert" || array_key_exists('regdate', $user)) + { + $this->verify_regdate(); + } + if($this->method == "insert" || array_key_exists('lastvisit', $user)) + { + $this->verify_lastvisit(); + } + if($this->method == "insert" || array_key_exists('lastactive', $user)) + { + $this->verify_lastactive(); + } + if($this->method == "insert" || array_key_exists('away', $user)) + { + $this->verify_away(); + } + if($this->method == "insert" || array_key_exists('language', $user)) + { + $this->verify_language(); + } + if($this->method == "insert" && array_key_exists('regcheck1', $user) && array_key_exists('regcheck2', $user)) + { + $this->verify_checkfields(); + } + if(array_key_exists('birthdayprivacy', $user)) + { + $this->verify_birthday_privacy(); + } + + $plugins->run_hooks("datahandler_user_validate", $this); + + // We are done validating, return. + $this->set_validated(true); + if(count($this->get_errors()) > 0) + { + return false; + } + else + { + return true; + } + } + + /** + * Inserts a user into the database. + */ + function insert_user() + { + global $db, $cache, $plugins; + + // Yes, validating is required. + if(!$this->get_validated()) + { + die("The user needs to be validated before inserting it into the DB."); + } + if(count($this->get_errors()) > 0) + { + die("The user is not valid."); + } + + $user = &$this->data; + + $array = array('postnum', 'threadnum', 'avatar', 'avatartype', 'additionalgroups', 'displaygroup', 'icq', 'aim', 'yahoo', 'skype', 'google', 'bday', 'signature', 'style', 'dateformat', 'timeformat', 'notepad'); + foreach($array as $value) + { + if(!isset($user[$value])) + { + $user[$value] = ''; + } + } + + $this->user_insert_data = array( + "username" => $db->escape_string($user['username']), + "password" => $user['saltedpw'], + "salt" => $user['salt'], + "loginkey" => $user['loginkey'], + "email" => $db->escape_string($user['email']), + "postnum" => (int)$user['postnum'], + "threadnum" => (int)$user['threadnum'], + "avatar" => $db->escape_string($user['avatar']), + "avatartype" => $db->escape_string($user['avatartype']), + "usergroup" => (int)$user['usergroup'], + "additionalgroups" => $db->escape_string($user['additionalgroups']), + "displaygroup" => (int)$user['displaygroup'], + "usertitle" => $db->escape_string(htmlspecialchars_uni($user['usertitle'])), + "regdate" => (int)$user['regdate'], + "lastactive" => (int)$user['lastactive'], + "lastvisit" => (int)$user['lastvisit'], + "website" => $db->escape_string($user['website']), + "icq" => (int)$user['icq'], + "aim" => $db->escape_string($user['aim']), + "yahoo" => $db->escape_string($user['yahoo']), + "skype" => $db->escape_string($user['skype']), + "google" => $db->escape_string($user['google']), + "birthday" => $user['bday'], + "signature" => $db->escape_string($user['signature']), + "allownotices" => $user['options']['allownotices'], + "hideemail" => $user['options']['hideemail'], + "subscriptionmethod" => (int)$user['options']['subscriptionmethod'], + "receivepms" => $user['options']['receivepms'], + "receivefrombuddy" => $user['options']['receivefrombuddy'], + "pmnotice" => $user['options']['pmnotice'], + "pmnotify" => $user['options']['pmnotify'], + "showimages" => $user['options']['showimages'], + "showvideos" => $user['options']['showvideos'], + "showsigs" => $user['options']['showsigs'], + "showavatars" => $user['options']['showavatars'], + "showquickreply" => $user['options']['showquickreply'], + "showredirect" => $user['options']['showredirect'], + "tpp" => (int)$user['options']['tpp'], + "ppp" => (int)$user['options']['ppp'], + "invisible" => $user['options']['invisible'], + "style" => (int)$user['style'], + "timezone" => $db->escape_string($user['timezone']), + "dstcorrection" => (int)$user['options']['dstcorrection'], + "threadmode" => $user['options']['threadmode'], + "daysprune" => (int)$user['options']['daysprune'], + "dateformat" => $db->escape_string($user['dateformat']), + "timeformat" => $db->escape_string($user['timeformat']), + "regip" => $db->escape_binary($user['regip']), + "language" => $db->escape_string($user['language']), + "showcodebuttons" => $user['options']['showcodebuttons'], + "sourceeditor" => $user['options']['sourceeditor'], + "away" => $user['away']['away'], + "awaydate" => $user['away']['date'], + "returndate" => $user['away']['returndate'], + "awayreason" => $db->escape_string($user['away']['awayreason']), + "notepad" => $db->escape_string($user['notepad']), + "referrer" => (int)$user['referrer_uid'], + "referrals" => 0, + "buddylist" => '', + "ignorelist" => '', + "pmfolders" => '', + "notepad" => '', + "warningpoints" => 0, + "moderateposts" => 0, + "moderationtime" => 0, + "suspendposting" => 0, + "suspensiontime" => 0, + "coppauser" => (int)$user['coppa_user'], + "classicpostbit" => $user['options']['classicpostbit'], + "usernotes" => '' + ); + + if($user['options']['dstcorrection'] == 1) + { + $this->user_insert_data['dst'] = 1; + } + else if($user['options']['dstcorrection'] == 0) + { + $this->user_insert_data['dst'] = 0; + } + + $plugins->run_hooks("datahandler_user_insert", $this); + + $this->uid = $db->insert_query("users", $this->user_insert_data); + + $user['user_fields']['ufid'] = $this->uid; + + $pfcache = $cache->read('profilefields'); + + if(is_array($pfcache)) + { + foreach($pfcache as $profile_field) + { + if(array_key_exists("fid{$profile_field['fid']}", $user['user_fields'])) + { + continue; + } + $user['user_fields']["fid{$profile_field['fid']}"] = ''; + } + } + + $db->insert_query("userfields", $user['user_fields'], false); + + if($this->user_insert_data['referrer'] != 0) + { + $db->write_query(" + UPDATE ".TABLE_PREFIX."users + SET referrals=referrals+1 + WHERE uid='{$this->user_insert_data['referrer']}' + "); + } + + // Update forum stats + update_stats(array('numusers' => '+1')); + + if((int)$user['usergroup'] == 5) + { + $cache->update_awaitingactivation(); + } + + $this->return_values = array( + "uid" => $this->uid, + "username" => $user['username'], + "loginkey" => $user['loginkey'], + "email" => $user['email'], + "password" => $user['password'], + "usergroup" => $user['usergroup'] + ); + + $plugins->run_hooks("datahandler_user_insert_end", $this); + + return $this->return_values; + } + + /** + * Updates a user in the database. + */ + function update_user() + { + global $db, $plugins, $cache; + + // Yes, validating is required. + if(!$this->get_validated()) + { + die("The user needs to be validated before inserting it into the DB."); + } + if(count($this->get_errors()) > 0) + { + die("The user is not valid."); + } + + $user = &$this->data; + $user['uid'] = (int)$user['uid']; + $this->uid = $user['uid']; + + // Set up the update data. + if(isset($user['username'])) + { + $this->user_update_data['username'] = $db->escape_string($user['username']); + } + if(isset($user['saltedpw'])) + { + $this->user_update_data['password'] = $user['saltedpw']; + $this->user_update_data['salt'] = $user['salt']; + $this->user_update_data['loginkey'] = $user['loginkey']; + } + if(isset($user['email'])) + { + $this->user_update_data['email'] = $user['email']; + } + if(isset($user['postnum'])) + { + $this->user_update_data['postnum'] = (int)$user['postnum']; + } + if(isset($user['threadnum'])) + { + $this->user_update_data['threadnum'] = (int)$user['threadnum']; + } + if(isset($user['avatar'])) + { + $this->user_update_data['avatar'] = $db->escape_string($user['avatar']); + $this->user_update_data['avatartype'] = $db->escape_string($user['avatartype']); + } + if(isset($user['usergroup'])) + { + $this->user_update_data['usergroup'] = (int)$user['usergroup']; + } + if(isset($user['additionalgroups'])) + { + $this->user_update_data['additionalgroups'] = $db->escape_string($user['additionalgroups']); + } + if(isset($user['displaygroup'])) + { + $this->user_update_data['displaygroup'] = (int)$user['displaygroup']; + } + if(isset($user['usertitle'])) + { + $this->user_update_data['usertitle'] = $db->escape_string($user['usertitle']); + } + if(isset($user['regdate'])) + { + $this->user_update_data['regdate'] = (int)$user['regdate']; + } + if(isset($user['lastactive'])) + { + $this->user_update_data['lastactive'] = (int)$user['lastactive']; + } + if(isset($user['lastvisit'])) + { + $this->user_update_data['lastvisit'] = (int)$user['lastvisit']; + } + if(isset($user['signature'])) + { + $this->user_update_data['signature'] = $db->escape_string($user['signature']); + } + if(isset($user['website'])) + { + $this->user_update_data['website'] = $db->escape_string($user['website']); + } + if(isset($user['icq'])) + { + $this->user_update_data['icq'] = (int)$user['icq']; + } + if(isset($user['aim'])) + { + $this->user_update_data['aim'] = $db->escape_string($user['aim']); + } + if(isset($user['yahoo'])) + { + $this->user_update_data['yahoo'] = $db->escape_string($user['yahoo']); + } + if(isset($user['skype'])) + { + $this->user_update_data['skype'] = $db->escape_string($user['skype']); + } + if(isset($user['google'])) + { + $this->user_update_data['google'] = $db->escape_string($user['google']); + } + if(isset($user['bday'])) + { + $this->user_update_data['birthday'] = $user['bday']; + } + if(isset($user['birthdayprivacy'])) + { + $this->user_update_data['birthdayprivacy'] = $db->escape_string($user['birthdayprivacy']); + } + if(isset($user['style'])) + { + $this->user_update_data['style'] = (int)$user['style']; + } + if(isset($user['timezone'])) + { + $this->user_update_data['timezone'] = $db->escape_string($user['timezone']); + } + if(isset($user['dateformat'])) + { + $this->user_update_data['dateformat'] = $db->escape_string($user['dateformat']); + } + if(isset($user['timeformat'])) + { + $this->user_update_data['timeformat'] = $db->escape_string($user['timeformat']); + } + if(isset($user['regip'])) + { + $this->user_update_data['regip'] = $db->escape_string($user['regip']); + } + if(isset($user['language'])) + { + $this->user_update_data['language'] = $db->escape_string($user['language']); + } + if(isset($user['away'])) + { + $this->user_update_data['away'] = $user['away']['away']; + $this->user_update_data['awaydate'] = $db->escape_string($user['away']['date']); + $this->user_update_data['returndate'] = $db->escape_string($user['away']['returndate']); + $this->user_update_data['awayreason'] = $db->escape_string($user['away']['awayreason']); + } + if(isset($user['notepad'])) + { + $this->user_update_data['notepad'] = $db->escape_string($user['notepad']); + } + if(isset($user['usernotes'])) + { + $this->user_update_data['usernotes'] = $db->escape_string($user['usernotes']); + } + if(isset($user['options']) && is_array($user['options'])) + { + foreach($user['options'] as $option => $value) + { + $this->user_update_data[$option] = $value; + } + } + if(array_key_exists('coppa_user', $user)) + { + $this->user_update_data['coppauser'] = (int)$user['coppa_user']; + } + // First, grab the old user details for later use. + $old_user = get_user($user['uid']); + + // If old user has new pmnotice and new user has = yes, keep old value + if($old_user['pmnotice'] == "2" && $this->user_update_data['pmnotice'] == 1) + { + unset($this->user_update_data['pmnotice']); + } + + $plugins->run_hooks("datahandler_user_update", $this); + + if(count($this->user_update_data) < 1 && empty($user['user_fields'])) + { + return false; + } + + if(count($this->user_update_data) > 0) + { + // Actual updating happens here. + $db->update_query("users", $this->user_update_data, "uid='{$user['uid']}'"); + } + + $cache->update_moderators(); + if(isset($user['bday']) || isset($user['username'])) + { + $cache->update_birthdays(); + } + + if(isset($user['usergroup']) && (int)$user['usergroup'] == 5) + { + $cache->update_awaitingactivation(); + } + + // Maybe some userfields need to be updated? + if(isset($user['user_fields']) && is_array($user['user_fields'])) + { + $query = $db->simple_select("userfields", "*", "ufid='{$user['uid']}'"); + $fields = $db->fetch_array($query); + if(!$fields['ufid']) + { + $user_fields = array( + 'ufid' => $user['uid'] + ); + + $fields_array = $db->show_fields_from("userfields"); + foreach($fields_array as $field) + { + if($field['Field'] == 'ufid') + { + continue; + } + $user_fields[$field['Field']] = ''; + } + $db->insert_query("userfields", $user_fields); + } + $db->update_query("userfields", $user['user_fields'], "ufid='{$user['uid']}'", false); + } + + // Let's make sure the user's name gets changed everywhere in the db if it changed. + if(!empty($this->user_update_data['username']) && $this->user_update_data['username'] != $old_user['username']) + { + $username_update = array( + "username" => $this->user_update_data['username'] + ); + $lastposter_update = array( + "lastposter" => $this->user_update_data['username'] + ); + + $db->update_query("posts", $username_update, "uid='{$user['uid']}'"); + $db->update_query("threads", $username_update, "uid='{$user['uid']}'"); + $db->update_query("threads", $lastposter_update, "lastposteruid='{$user['uid']}'"); + $db->update_query("forums", $lastposter_update, "lastposteruid='{$user['uid']}'"); + + $stats = $cache->read("stats"); + if($stats['lastuid'] == $user['uid']) + { + // User was latest to register, update stats + update_stats(array("numusers" => "+0")); + } + } + + return true; + } + + /** + * Provides a method to completely delete a user. + * + * @param array Array of user information + * @param integer Whether if delete threads/posts or not + * @return boolean True when successful, false if fails + */ + function delete_user($delete_uids, $prunecontent=0) + { + global $db, $plugins, $mybb, $cache; + + // Yes, validating is required. + if(count($this->get_errors()) > 0) + { + die('The user is not valid.'); + } + + $this->delete_uids = array_map('intval', (array)$delete_uids); + + foreach($this->delete_uids as $key => $uid) + { + if(!$uid || is_super_admin($uid) || $uid == $mybb->user['uid']) + { + // Remove super admins + unset($this->delete_uids[$key]); + } + } + + $plugins->run_hooks('datahandler_user_delete_start', $this); + + $this->delete_uids = '\''.implode('\',\'', $this->delete_uids).'\''; + + $this->delete_content(); + + // Delete the user + $query = $db->delete_query('users', 'uid IN('.$this->delete_uids.')'); + $this->deleted_users = (int)$db->affected_rows($query); + + // Are we removing the posts/threads of a user? + if((int)$prunecontent == 1) + { + $this->delete_posts(); + } + else + { + // We're just updating the UID + $db->update_query('posts', array('uid' => 0), 'uid IN('.$this->delete_uids.')'); + $db->update_query('threads', array('uid' => 0), 'uid IN('.$this->delete_uids.')'); + } + + // Update thread ratings + $query = $db->query(" + SELECT r.*, t.numratings, t.totalratings + FROM ".TABLE_PREFIX."threadratings r + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=r.tid) + WHERE r.uid IN({$this->delete_uids}) + "); + while($rating = $db->fetch_array($query)) + { + $update_thread = array( + "numratings" => $rating['numratings'] - 1, + "totalratings" => $rating['totalratings'] - $rating['rating'] + ); + $db->update_query("threads", $update_thread, "tid='{$rating['tid']}'"); + } + + $db->delete_query('threadratings', 'uid IN('.$this->delete_uids.')'); + + // Update forums & threads if user is the lastposter + $db->update_query('forums', array('lastposteruid' => 0), 'lastposteruid IN('.$this->delete_uids.')'); + $db->update_query('threads', array('lastposteruid' => 0), 'lastposteruid IN('.$this->delete_uids.')'); + + $cache->update_banned(); + $cache->update_moderators(); + + // Update forum stats + update_stats(array('numusers' => '-'.(int)$this->deleted_users)); + + $this->return_values = array( + "deleted_users" => $this->deleted_users + ); + + // Update reports cache + $cache->update_reportedcontent(); + + $cache->update_awaitingactivation(); + + $plugins->run_hooks("datahandler_user_delete_end", $this); + + return $this->return_values; + } + + /** + * Provides a method to delete an users content + * + * @param array Array of user ids, false if they're already set (eg when using the delete_user function) + */ + function delete_content($delete_uids=false) + { + global $db, $plugins; + + if($delete_uids != false) + { + $this->delete_uids = array_map('intval', (array)$delete_uids); + + foreach($this->delete_uids as $key => $uid) + { + if(!$uid || is_super_admin($uid) || $uid == $mybb->user['uid']) + { + // Remove super admins + unset($this->delete_uids[$key]); + } + } + + $this->delete_uids = '\''.implode('\',\'', $this->delete_uids).'\''; + } + + $plugins->run_hooks('datahandler_user_delete_content', $this); + + $db->delete_query('userfields', 'ufid IN('.$this->delete_uids.')'); + $db->delete_query('privatemessages', 'uid IN('.$this->delete_uids.')'); + $db->delete_query('events', 'uid IN('.$this->delete_uids.')'); + $db->delete_query('moderators', 'id IN('.$this->delete_uids.') AND isgroup=\'0\''); + $db->delete_query('forumsubscriptions', 'uid IN('.$this->delete_uids.')'); + $db->delete_query('threadsubscriptions', 'uid IN('.$this->delete_uids.')'); + $db->delete_query('sessions', 'uid IN('.$this->delete_uids.')'); + $db->delete_query('banned', 'uid IN('.$this->delete_uids.')'); + $db->delete_query('joinrequests', 'uid IN('.$this->delete_uids.')'); + $db->delete_query('awaitingactivation', 'uid IN('.$this->delete_uids.')'); + $db->delete_query('warnings', 'uid IN('.$this->delete_uids.')'); + $db->delete_query('reputation', 'uid IN('.$this->delete_uids.') OR adduid IN('.$this->delete_uids.')'); + $db->delete_query('posts', 'uid IN('.$this->delete_uids.') AND visible=\'-2\''); + $db->delete_query('threads', 'uid IN('.$this->delete_uids.') AND visible=\'-2\''); + $db->delete_query('moderators', 'id IN('.$this->delete_uids.') AND isgroup=\'0\''); + + // Delete reports made to the profile or reputation of the deleted users (i.e. made by them) + $db->delete_query('reportedcontent', 'type=\'reputation\' AND id3 IN('.$this->delete_uids.') OR type=\'reputation\' AND id2 IN('.$this->delete_uids.')'); + $db->delete_query('reportedcontent', 'type=\'profile\' AND id IN('.$this->delete_uids.')'); + + // Update the reports made by the deleted users by setting the uid to 0 + $db->update_query('reportedcontent', array('uid' => 0), 'uid IN('.$this->delete_uids.')'); + + // Remove any of the user(s) uploaded avatars + $query = $db->simple_select('users', 'avatar', 'uid IN ('.$this->delete_uids.') AND avatartype=\'upload\''); + while($avatar = $db->fetch_field($query, 'avatar')) + { + $avatar = substr($avatar, 2, -20); + @unlink(MYBB_ROOT.$avatar); + } + + } + + /** + * Provides a method to delete an users posts and threads + * + * @param array Array of user ids, false if they're already set (eg when using the delete_user function) + */ + function delete_posts($delete_uids=false) + { + global $db, $plugins; + + if($delete_uids != false) + { + $this->delete_uids = array_map('intval', (array)$delete_uids); + + foreach($this->delete_uids as $key => $uid) + { + if(!$uid || is_super_admin($uid) || $uid == $mybb->user['uid']) + { + // Remove super admins + unset($this->delete_uids[$key]); + } + } + + $this->delete_uids = '\''.implode('\',\'', $this->delete_uids).'\''; + } + + require_once MYBB_ROOT.'inc/class_moderation.php'; + $moderation = new Moderation(); + + $plugins->run_hooks('datahandler_user_delete_posts', $this); + + // Threads + $query = $db->simple_select('threads', 'tid', 'uid IN('.$this->delete_uids.')'); + while($tid = $db->fetch_field($query, 'tid')) + { + $moderation->delete_thread($tid); + } + + // Posts + $pids = array(); + $query = $db->simple_select('posts', 'pid', 'uid IN('.$this->delete_uids.')'); + while($pid = $db->fetch_field($query, 'pid')) + { + $moderation->delete_post($pid); + $pids[] = (int)$pid; + } + + // Delete Reports made to users's posts/threads + if(!empty($pids)) + { + $db->delete_query('reportedcontent', 'type=\'posts\' AND id IN('.implode(',', $pids).')'); + } + } + + /** + * Provides a method to clear an users profile (note that this doesn't delete the custom profilefields) + * + * @param array Array of user ids, false if they're already set (eg when using the delete_user function) + * @param int The new usergroup if the users should be moved (additional usergroups are always removed) + */ + function clear_profile($delete_uids=false, $gid=0) + { + global $db, $plugins; + + // delete_uids isn't a nice name, but it's used as the functions above use the same + if($delete_uids != false) + { + $this->delete_uids = array_map('intval', (array)$delete_uids); + + foreach($this->delete_uids as $key => $uid) + { + if(!$uid || is_super_admin($uid) || $uid == $mybb->user['uid']) + { + // Remove super admins + unset($this->delete_uids[$key]); + } + } + + $this->delete_uids = '\''.implode('\',\'', $this->delete_uids).'\''; + } + + $update = array( + "website" => "", + "birthday" => "", + "icq" => "", + "aim" => "", + "yahoo" => "", + "skype" => "", + "google" => "", + "usertitle" => "", + "away" => 0, + "awaydate" => 0, + "returndate" => "", + "awayreason" => "", + "additionalgroups" => "", + "displaygroup" => 0, + "signature" => "", + "avatar" => "" + ); + + if($gid > 0) + { + $update["usergroup"] = (int)$gid; + + } + + $plugins->run_hooks('datahandler_user_clear_profile', $this); + + $db->update_query("users", $update, 'uid IN('.$this->delete_uids.')'); + } +} diff --git a/Upload/inc/datahandlers/warnings.php b/Upload/inc/datahandlers/warnings.php new file mode 100644 index 0000000..70f0689 --- /dev/null +++ b/Upload/inc/datahandlers/warnings.php @@ -0,0 +1,754 @@ +
    Please make sure IN_MYBB is defined."); +} + +/** + * Login handling class, provides common structure to handle login events. + * + */ +class WarningsHandler extends DataHandler +{ + /** + * The language file used in the data handler. + * + * @var string + */ + public $language_file = 'datahandler_warnings'; + + /** + * The prefix for the language variables used in the data handler. + * + * @var string + */ + public $language_prefix = 'warnings'; + + /** + * The stored data for the warning being written. + * + * @var array + */ + public $write_warning_data = array(); + + /** + * The stored data for the warning being retrieved. + * + * @var array + */ + private $read_warning_data = array(); + + /** + * Friendly redirect action after inserting a new warning. + * + * @var string + */ + public $friendly_action = ''; + + /** + * Validate a warning user assets. + * + * @return boolean True when valid, false when invalid. + */ + function validate_user() + { + global $mybb; + + $warning = &$this->data; + + $user = get_user($warning['uid']); + + if(!$user['uid']) + { + $this->set_error('error_invalid_user'); + return false; + } + + if($user['uid'] == $mybb->user['uid']) + { + $this->set_error('error_cannot_warn_self'); + return false; + } + + if($user['warningpoints'] >= $mybb->settings['maxwarningpoints']) + { + $this->set_error('error_user_reached_max_warning'); + return false; + } + + return true; + } + + /** + * Validate a warning thread. + * + * @return boolean True when valid, false when invalid. + */ + function validate_thread() + { + $warning = &$this->data; + + $thread = get_thread($warning['tid']); + + if(!$thread['tid']) + { + $this->set_error('error_invalid_post'); + return false; + } + + return true; + } + + /** + * Validate a warning post. + * + * @return boolean True when valid, false when invalid. + */ + function validate_post() + { + $warning = &$this->data; + + $post = get_post($warning['pid']); + + if(!$post['pid']) + { + $this->set_error('error_invalid_post'); + return false; + } + + if(!isset($warning['tid'])) + { + $warning['tid'] = $post['tid']; + } + + return true; + } + + /** + * Validate a warning notes. + * + * @return boolean True when valid, false when invalid. + */ + function validate_notes() + { + $warning = &$this->data; + + if(!trim($warning['notes'])) + { + $this->set_error('error_no_note'); + return false; + } + + return true; + } + + /** + * Validate maximum warnings per day for current user. + * + * @return boolean True when valid, false when invalid. + */ + function validate_maximum() + { + global $mybb, $db, $lang; + + if($mybb->usergroup['maxwarningsday'] != 0) + { + $timecut = TIME_NOW-60*60*24; + $query = $db->simple_select("warnings", "COUNT(wid) AS given_today", "issuedby='{$mybb->user['uid']}' AND dateline>'$timecut'"); + $given_today = $db->fetch_field($query, "given_today"); + if($given_today >= $mybb->usergroup['maxwarningsday']) + { + $this->set_error('reached_max_warnings_day', array(my_number_format($mybb->usergroup['maxwarningsday']))); + return false; + } + } + + return true; + } + + /** + * Validate warnings type. + * + * @return boolean True when valid, false when invalid. + */ + function validate_type() + { + global $mybb, $db; + + $warning = &$this->data; + + // Issuing a custom warning + if($warning['type'] == 'custom') + { + if($mybb->settings['allowcustomwarnings'] == 0) + { + $this->set_error('error_cant_custom_warn'); + return false; + } + + if(!$warning['custom_reason']) + { + $this->set_error('error_no_custom_reason'); + return false; + } + + $warning['title'] = $warning['custom_reason']; + + if(!$warning['custom_points'] || $warning['custom_points'] > $mybb->settings['maxwarningpoints'] || $warning['custom_points'] < 0) + { + $this->set_error('error_invalid_custom_points', array(my_number_format($mybb->settings['maxwarningpoints']))); + return false; + } + + $warning['points'] = round($warning['custom_points']); + + // Build expiry date + if($warning['expires_period'] == "hours") + { + $warning['expires'] = $warning['expires']*3600 + TIME_NOW; + } + else if($warning['expires_period'] == "days") + { + $warning['expires'] = $warning['expires']*86400 + TIME_NOW; + } + else if($warning['expires_period'] == "weeks") + { + $warning['expires'] = $warning['expires']*604800 + TIME_NOW; + } + else if($warning['expires_period'] == "months") + { + $warning['expires'] = $warning['expires']*2592000 + TIME_NOW; + } + else if($warning['expires_period'] == "never") + { + $warning['expires'] = 0; + } + else + { + // unkown expires_period + $this->set_error('error_invalid_expires_period'); + return false; + } + } + // Using a predefined warning type + else + { + $query = $db->simple_select("warningtypes", "*", "tid='".(int)$warning['type']."'"); + $this->warning_type = $db->fetch_array($query); + + if(!$this->warning_type) + { + $this->set_error('error_invalid_type'); + return false; + } + + $warning['points'] = $this->warning_type['points']; + + $warning['title'] = $warning['expires'] = ''; + if($this->warning_type['expirationtime']) + { + $warning['expires'] = TIME_NOW+$this->warning_type['expirationtime']; + } + } + + return true; + } + + /** + * Validate a warning. + * + * @return boolean True when valid, false when invalid. + */ + function validate_warning() + { + global $plugins; + + $warning = &$this->data; + + // Verify all warning assets. + $this->validate_user(); + $this->validate_maximum(); + $this->validate_notes(); + + if(array_key_exists('pid', $warning)) + { + $this->validate_post(); + $this->validate_thread(); + } + if(array_key_exists('type', $warning)) + { + $this->validate_type(); + } + + $plugins->run_hooks("datahandler_warnings_validate_warning", $this); + + // We are done validating, return. + $this->set_validated(true); + + if(count($this->get_errors()) > 0) + { + return false; + } + + return true; + } + + /** + * Gets a valid warning from the DB engine. + * + * @return mixed array when valid, boolean false when invalid. + */ + function get($wid) + { + global $db; + + $wid = (int)$wid; + if($wid <= 0) + { + return false; + } + + $query = $db->simple_select("warnings", "*", "wid='".$wid."'"); + $this->read_warning_data = $db->fetch_array($query); + + if(!$this->read_warning_data['wid']) + { + return false; + } + + return $this->read_warning_data; + } + + /** + * Expire old warnings in the database. + * + * @return boolean True when finished. + */ + function expire_warnings() + { + global $db; + + $users = array(); + + $query = $db->query(" + SELECT w.wid, w.uid, w.points, u.warningpoints + FROM ".TABLE_PREFIX."warnings w + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=w.uid) + WHERE expires<".TIME_NOW." AND expires!=0 AND expired!=1 + "); + while($warning = $db->fetch_array($query)) + { + $updated_warning = array( + "expired" => 1 + ); + $db->update_query("warnings", $updated_warning, "wid='{$warning['wid']}'"); + + if(array_key_exists($warning['uid'], $users)) + { + $users[$warning['uid']] -= $warning['points']; + } + else + { + $users[$warning['uid']] = $warning['warningpoints']-$warning['points']; + } + } + + foreach($users as $uid => $warningpoints) + { + if($warningpoints < 0) + { + $warningpoints = 0; + } + + $updated_user = array( + "warningpoints" => (int)$warningpoints + ); + $db->update_query("users", $updated_user, "uid='".(int)$uid."'"); + } + + return true; + } + + /** + * Updates an user warning details. + * + * @return array Updated user details. + */ + function update_user($method='insert') + { + global $db, $mybb, $lang; + + $warning = &$this->data; + + $user = get_user($warning['uid']); + + if($method == 'insert') + { + // Build warning level & ensure it doesn't go over 100. + $current_level = round($user['warningpoints']/$mybb->settings['maxwarningpoints']*100); + $this->new_warning_level = round(($user['warningpoints']+$warning['points'])/$mybb->settings['maxwarningpoints']*100); + if($this->new_warning_level > 100) + { + $this->new_warning_level = 100; + } + + // Update user + $this->updated_user = array( + "warningpoints" => $user['warningpoints']+$warning['points'] + ); + + // Fetch warning level + $query = $db->simple_select("warninglevels", "*", "percentage<={$this->new_warning_level}", array("order_by" => "percentage", "order_dir" => "desc")); + $new_level = $db->fetch_array($query); + + if($new_level['lid']) + { + $expiration = 0; + $action = my_unserialize($new_level['action']); + + if($action['length'] > 0) + { + $expiration = TIME_NOW+$action['length']; + } + + switch($action['type']) + { + // Ban the user for a specified time + case 1: + // Fetch any previous bans for this user + $query = $db->simple_select("banned", "*", "uid='{$user['uid']}' AND gid='{$action['usergroup']}' AND lifted>".TIME_NOW); + $existing_ban = $db->fetch_array($query); + + // Only perform if no previous ban or new ban expires later than existing ban + if(($expiration > $existing_ban['lifted'] && $existing_ban['lifted'] != 0) || $expiration == 0 || !$existing_ban['uid']) + { + if(!$warning['title']) + { + $warning['title'] = $this->warning_type['title']; + } + + // Never lift the ban? + if($action['length'] <= 0) + { + $bantime = '---'; + } + else + { + $bantimes = fetch_ban_times(); + foreach($bantimes as $date => $string) + { + if($date == '---') + { + continue; + } + + $time = 0; + list($day, $month, $year) = explode('-', $date); + if($day > 0) + { + $time += 60*60*24*$day; + } + + if($month > 0) + { + $time += 60*60*24*30*$month; + } + + if($year > 0) + { + $time += 60*60*24*365*$year; + } + + if($time == $action['length']) + { + $bantime = $date; + break; + } + } + } + + $new_ban = array( + "uid" => (int)$user['uid'], + "gid" => $db->escape_string($action['usergroup']), + "oldgroup" => $db->escape_string($user['usergroup']), + "oldadditionalgroups" => $db->escape_string($user['additionalgroups']), + "olddisplaygroup" => $db->escape_string($user['displaygroup']), + "admin" => $mybb->user['uid'], + "dateline" => TIME_NOW, + "bantime" => $db->escape_string($bantime), + "lifted" => $expiration, + "reason" => $db->escape_string($warning['title']) + ); + // Delete old ban for this user, taking details + if($existing_ban['uid']) + { + $db->delete_query("banned", "uid='{$user['uid']}' AND gid='{$action['usergroup']}'"); + // Override new ban details with old group info + $new_ban['oldgroup'] = $db->escape_string($existing_ban['oldgroup']); + $new_ban['oldadditionalgroups'] = $db->escape_string($existing_ban['oldadditionalgroups']); + $new_ban['olddisplaygroup'] = $db->escape_string($existing_ban['olddisplaygroup']); + } + + $period = $lang->expiration_never; + $ban_length = fetch_friendly_expiration($action['length']); + + if($ban_length['time']) + { + $lang_str = "expiration_".$ban_length['period']; + $period = $lang->sprintf($lang->result_period, $ban_length['time'], $lang->$lang_str); + } + + $group_name = $groupscache[$action['usergroup']]['title']; + $this->friendly_action = $lang->sprintf($lang->redirect_warned_banned, $group_name, $period); + + $db->insert_query("banned", $new_ban); + $this->updated_user['usergroup'] = $action['usergroup']; + $this->updated_user['additionalgroups'] = $this->updated_user['displaygroup'] = ""; + } + break; + // Suspend posting privileges + case 2: + // Only perform if the expiration time is greater than the users current suspension period + if($expiration == 0 || $expiration > $user['suspensiontime']) + { + if(($user['suspensiontime'] != 0 && $user['suspendposting']) || !$user['suspendposting']) + { + $period = $lang->expiration_never; + $ban_length = fetch_friendly_expiration($action['length']); + + if($ban_length['time']) + { + $lang_str = "expiration_".$ban_length['period']; + $period = $lang->sprintf($lang->result_period, $ban_length['time'], $lang->$lang_str); + } + + $this->friendly_action = $lang->sprintf($lang->redirect_warned_suspended, $period); + + $this->updated_user['suspensiontime'] = $expiration; + $this->updated_user['suspendposting'] = 1; + } + } + break; + // Moderate new posts + case 3: + // Only perform if the expiration time is greater than the users current suspension period + if($expiration == 0 || $expiration > $user['moderationtime']) + { + if(($user['moderationtime'] != 0 && $user['moderateposts']) || !$user['suspendposting']) + { + $period = $lang->expiration_never; + $ban_length = fetch_friendly_expiration($action['length']); + + if($ban_length['time']) + { + $lang_str = "expiration_".$ban_length['period']; + $period = $lang->sprintf($lang->result_period, $ban_length['time'], $lang->$lang_str); + } + + $this->friendly_action = $lang->sprintf($lang->redirect_warned_moderate, $period); + + $this->updated_user['moderationtime'] = $expiration; + $this->updated_user['moderateposts'] = 1; + } + } + break; + } + } + } + else + { + // Warning is still active, lower users point count + if($warning['expired'] != 1) + { + $new_warning_points = $user['warningpoints']-$warning['points']; + if($new_warning_points < 0) + { + $new_warning_points = 0; + } + + $this->updated_user = array( + "warningpoints" => $new_warning_points + ); + + + // check if we need to revoke any consequences with this warning + $current_level = round($user['warningpoints']/$mybb->settings['maxwarningpoints']*100); + $this->new_warning_level = round($new_warning_points/$mybb->settings['maxwarningpoints']*100); + $query = $db->simple_select("warninglevels", "action", "percentage>{$this->new_warning_level} AND percentage<=$current_level"); + if($db->num_rows($query)) + { + // we have some warning levels we need to revoke + $max_expiration_times = $check_levels = array(); + find_warnlevels_to_check($query, $max_expiration_times, $check_levels); + + // now check warning levels already applied to this user to see if we need to lower any expiration times + $query = $db->simple_select("warninglevels", "action", "percentage<={$this->new_warning_level}"); + $lower_expiration_times = $lower_levels = array(); + find_warnlevels_to_check($query, $lower_expiration_times, $lower_levels); + + // now that we've got all the info, do necessary stuff + for($i = 1; $i <= 3; ++$i) + { + if($check_levels[$i]) + { + switch($i) + { + case 1: // Ban + // we'll have to resort to letting the admin/mod remove the ban manually, since there's an issue if stacked bans are in force... + continue; + case 2: // Revoke posting + $current_expiry_field = 'suspensiontime'; + $current_inforce_field = 'suspendposting'; + break; + case 3: + $current_expiry_field = 'moderationtime'; + $current_inforce_field = 'moderateposts'; + break; + } + + // if the thing isn't in force, don't bother with trying to update anything + if(!$user[$current_inforce_field]) + { + continue; + } + + if($lower_levels[$i]) + { + // lessen the expiration time if necessary + + if(!$lower_expiration_times[$i]) + { + // doesn't expire - enforce this + $this->updated_user[$current_expiry_field] = 0; + continue; + } + + if($max_expiration_times[$i]) + { + // if the old level did have an expiry time... + if($max_expiration_times[$i] <= $lower_expiration_times[$i]) + { + // if the lower expiration time is actually higher than the upper expiration time -> skip + continue; + } + // both new and old max expiry times aren't infinite, so we can take a difference + $expire_offset = ($lower_expiration_times[$i] - $max_expiration_times[$i]); + } + else + { + // the old level never expired, not much we can do but try to estimate a new expiry time... which will just happen to be starting from today... + $expire_offset = TIME_NOW + $lower_expiration_times[$i]; + // if the user's expiry time is already less than what we're going to set it to, skip + if($user[$current_expiry_field] <= $expire_offset) + { + continue; + } + } + + $this->updated_user[$current_expiry_field] = $user[$current_expiry_field] + $expire_offset; + // double-check if it's expired already + if($this->updated_user[$current_expiry_field] < TIME_NOW) + { + $this->updated_user[$current_expiry_field] = 0; + $this->updated_user[$current_inforce_field] = 0; + } + } + else + { + // there's no lower level for this type - remove the consequence entirely + $this->updated_user[$current_expiry_field] = 0; + $this->updated_user[$current_inforce_field] = 0; + } + } + } + } + } + } + + // Save updated details + $db->update_query("users", $this->updated_user, "uid='{$user['uid']}'"); + + $mybb->cache->update_moderators(); + + return $this->updated_user; + } + + /** + * Inserts a warning into the database + * + * @return array Warning database details. + */ + function insert_warning() + { + global $db, $mybb, $plugins; + + $warning = &$this->data; + + $this->write_warning_data = array( + "uid" => (int)$warning['uid'], + "tid" => (int)$warning['tid'], + "pid" => (int)$warning['pid'], + "title" => $db->escape_string($warning['title']), + "points" => (int)$warning['points'], + "dateline" => TIME_NOW, + "issuedby" => (int)$mybb->user['uid'], + "expires" => $db->escape_string($warning['expires']), + "expired" => 0, + "revokereason" => '', + "notes" => $db->escape_string($warning['notes']) + ); + + $this->write_warning_data['wid'] = $db->insert_query("warnings", $this->write_warning_data); + + $this->update_user(); + + $plugins->run_hooks("datahandler_warnings_insert_warning", $this); + + return $this->write_warning_data; + } + + /** + * Updates a warning in the database + * + * @return array Warning database details. + */ + function update_warning() + { + global $db, $mybb, $plugins; + + $warning = &$this->data; + + $warning['wid'] = (int)$warning['wid']; + if($warning['wid'] <= 0) + { + return false; + } + + $this->write_warning_data = array( + "expired" => 1, + "daterevoked" => TIME_NOW, + "revokedby" => $mybb->user['uid'], + "revokereason" => $db->escape_string($warning['reason']) + ); + + $plugins->run_hooks("datahandler_warnings_update_warning", $this); + + $db->update_query("warnings", $this->write_warning_data, "wid='{$warning['wid']}'"); + + $this->update_user('update'); + + return $this->write_warning_data; + } + +} + diff --git a/Upload/inc/db_mysql.php b/Upload/inc/db_mysql.php new file mode 100644 index 0000000..73d1d62 --- /dev/null +++ b/Upload/inc/db_mysql.php @@ -0,0 +1,1538 @@ + write; 0 => read + * + * @var int + */ + + protected $last_query_type = 0; + + /** + * Connect to the database server. + * + * @param array Array of DBMS connection details. + * @return resource The DB connection resource. Returns false on fail or -1 on a db connect failure. + */ + function connect($config) + { + // Simple connection to one server + if(array_key_exists('hostname', $config)) + { + $connections['read'][] = $config; + } + // Connecting to more than one server + else + { + // Specified multiple servers, but no specific read/write servers + if(!array_key_exists('read', $config)) + { + foreach($config as $key => $settings) + { + if(is_int($key)) + { + $connections['read'][] = $settings; + } + } + } + // Specified both read & write servers + else + { + $connections = $config; + } + } + + $this->db_encoding = $config['encoding']; + + // Actually connect to the specified servers + foreach(array('read', 'write') as $type) + { + if(!isset($connections[$type]) || !is_array($connections[$type])) + { + break; + } + + if(array_key_exists('hostname', $connections[$type])) + { + $details = $connections[$type]; + unset($connections); + $connections[$type][] = $details; + } + + // Shuffle the connections + shuffle($connections[$type]); + + // Loop-de-loop + foreach($connections[$type] as $single_connection) + { + $connect_function = "mysql_connect"; + if(isset($single_connection['pconnect'])) + { + $connect_function = "mysql_pconnect"; + } + + $link = "{$type}_link"; + + get_execution_time(); + + $this->$link = @$connect_function($single_connection['hostname'], $single_connection['username'], $single_connection['password'], 1); + + $time_spent = get_execution_time(); + $this->query_time += $time_spent; + + // Successful connection? break down brother! + if($this->$link) + { + $this->connections[] = "[".strtoupper($type)."] {$single_connection['username']}@{$single_connection['hostname']} (Connected in ".format_time_duration($time_spent).")"; + break; + } + else + { + $this->connections[] = "[FAILED] [".strtoupper($type)."] {$single_connection['username']}@{$single_connection['hostname']}"; + } + } + } + + // No write server was specified (simple connection or just multiple servers) - mirror write link + if(!array_key_exists('write', $connections)) + { + $this->write_link = &$this->read_link; + } + + // Have no read connection? + if(!$this->read_link) + { + $this->error("[READ] Unable to connect to MySQL server"); + return false; + } + // No write? + else if(!$this->write_link) + { + $this->error("[WRITE] Unable to connect to MySQL server"); + return false; + } + + // Select databases + if(!$this->select_db($config['database'])) + { + return -1; + } + + $this->current_link = &$this->read_link; + return $this->read_link; + } + + /** + * Selects the database to use. + * + * @param string The database name. + * @return boolean True when successfully connected, false if not. + */ + function select_db($database) + { + global $mybb; + + $this->current_link = &$this->read_link; + $read_success = @mysql_select_db($database, $this->read_link) or $this->error("[READ] Unable to select database", $this->read_link); + if($this->write_link) + { + $this->current_link = &$this->write_link; + $write_success = @mysql_select_db($database, $this->write_link) or $this->error("[WRITE] Unable to select database", $this->write_link); + $success = ($read_success && $write_success ? true : false); + } + else + { + $success = $read_success; + } + + if($success && $this->db_encoding) + { + // A little magic to support PHP 5.2.0, 5.2.1 and 5.2.2 + if(version_compare(PHP_VERSION, '5.2.3', '>=')) { + @mysql_set_charset($this->db_encoding, $this->read_link); + } + else + { + $this->query("SET NAMES '{$this->db_encoding}'"); + } + + if($write_success && count($this->connections) > 1) + { + if(version_compare(PHP_VERSION, '5.2.3', '>=')) { + @mysql_set_charset($this->db_encoding, $this->write_link); + } + else + { + $this->write_query("SET NAMES '{$this->db_encoding}'"); + } + } + } + return $success; + } + + /** + * Query the database. + * + * @param string The query SQL. + * @param integer 1 if hide errors, 0 if not. + * @param integer 1 if executes on master database, 0 if not. + * @return resource The query data. + */ + function query($string, $hide_errors=0, $write_query=0) + { + global $pagestarttime, $db, $mybb; + + get_execution_time(); + + // Only execute write queries on master database + if(($write_query || $this->last_query_type) && $this->write_link) + { + $this->current_link = &$this->write_link; + $query = @mysql_query($string, $this->write_link); + } + else + { + $this->current_link = &$this->read_link; + $query = @mysql_query($string, $this->read_link); + } + + if($this->error_number() && !$hide_errors) + { + $this->error($string); + exit; + } + + if($write_query) + { + $this->last_query_type = 1; + } + else + { + $this->last_query_type = 0; + } + + $query_time = get_execution_time(); + $this->query_time += $query_time; + $this->query_count++; + + if($mybb->debug_mode) + { + $this->explain_query($string, $query_time); + } + + return $query; + } + + /** + * Execute a write query on the master database + * + * @param string The query SQL. + * @param boolean 1 if hide errors, 0 if not. + * @return resource The query data. + */ + function write_query($query, $hide_errors=0) + { + return $this->query($query, $hide_errors, 1); + } + + /** + * Explain a query on the database. + * + * @param string The query SQL. + * @param string The time it took to perform the query. + */ + function explain_query($string, $qtime) + { + global $plugins; + + $debug_extra = ''; + if($plugins->current_hook) + { + $debug_extra = "
    (Plugin Hook: {$plugins->current_hook})
    "; + } + if(preg_match("#^\s*select#i", $string)) + { + $query = mysql_query("EXPLAIN $string", $this->current_link); + $this->explain .= "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n"; + + while($table = mysql_fetch_array($query)) + { + $this->explain .= + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n"; + } + $this->explain .= + "\n". + "\n". + "\n". + "
    {$debug_extra}
    #".$this->query_count." - Select Query
    ".htmlspecialchars_uni($string)."
    TableTypePossible KeysKeyKey LengthRefRowsExtra
    ".$table['table']."".$table['type']."".$table['possible_keys']."".$table['key']."".$table['key_len']."".$table['ref']."".$table['rows']."".$table['Extra']."
    Query Time: ".format_time_duration($qtime)."
    \n". + "
    \n"; + } + else + { + $this->explain .= "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "
    {$debug_extra}
    #".$this->query_count." - Write Query
    ".htmlspecialchars_uni($string)."
    Query Time: ".format_time_duration($qtime)."
    \n". + "
    \n"; + } + + $this->querylist[$this->query_count]['query'] = $string; + $this->querylist[$this->query_count]['time'] = $qtime; + } + + /** + * Return a result array for a query. + * + * @param resource The query ID. + * @param constant The type of array to return. + * @return array The array of results. + */ + function fetch_array($query, $resulttype=MYSQL_ASSOC) + { + switch($resulttype) + { + case MYSQL_NUM: + case MYSQL_BOTH: + break; + default: + $resulttype = MYSQL_ASSOC; + break; + } + + $array = mysql_fetch_array($query, $resulttype); + + return $array; + } + + /** + * Return a specific field from a query. + * + * @param resource The query ID. + * @param string The name of the field to return. + * @param int The number of the row to fetch it from. + */ + function fetch_field($query, $field, $row=false) + { + if($row === false) + { + $array = $this->fetch_array($query); + return $array[$field]; + } + else + { + return mysql_result($query, $row, $field); + } + } + + /** + * Moves internal row pointer to the next row + * + * @param resource The query ID. + * @param int The pointer to move the row to. + */ + function data_seek($query, $row) + { + return mysql_data_seek($query, $row); + } + + /** + * Return the number of rows resulting from a query. + * + * @param resource The query ID. + * @return int The number of rows in the result. + */ + function num_rows($query) + { + return mysql_num_rows($query); + } + + /** + * Return the last id number of inserted data. + * + * @return int The id number. + */ + function insert_id() + { + return mysql_insert_id($this->current_link); + } + + /** + * Close the connection with the DBMS. + * + */ + function close() + { + @mysql_close($this->read_link); + if($this->write_link) + { + @mysql_close($this->write_link); + } + } + + /** + * Return an error number. + * + * @return int The error number of the current error. + */ + function error_number() + { + if($this->current_link) + { + return @mysql_errno($this->current_link); + } + else + { + return @mysql_errno(); + } + } + + /** + * Return an error string. + * + * @return string The explanation for the current error. + */ + function error_string() + { + if($this->current_link) + { + return @mysql_error($this->current_link); + } + else + { + return @mysql_error(); + } + } + + /** + * Output a database error. + * + * @param string The string to present as an error. + */ + function error($string="") + { + if($this->error_reporting) + { + if(class_exists("errorHandler")) + { + global $error_handler; + + if(!is_object($error_handler)) + { + require_once MYBB_ROOT."inc/class_error.php"; + $error_handler = new errorHandler(); + } + + $error = array( + "error_no" => $this->error_number(), + "error" => $this->error_string(), + "query" => $string + ); + $error_handler->error(MYBB_SQL, $error); + } + else + { + trigger_error("[SQL] [".$this->error_number()."] ".$this->error_string()."
    {$string}", E_USER_ERROR); + } + } + else + { + return false; + } + } + + /** + * Returns the number of affected rows in a query. + * + * @return int The number of affected rows. + */ + function affected_rows() + { + return mysql_affected_rows($this->current_link); + } + + /** + * Return the number of fields. + * + * @param resource The query ID. + * @return int The number of fields. + */ + function num_fields($query) + { + return mysql_num_fields($query); + } + + /** + * Lists all functions in the database. + * + * @param string The database name. + * @param string Prefix of the table (optional) + * @return array The table list. + */ + function list_tables($database, $prefix='') + { + if($prefix) + { + $query = $this->query("SHOW TABLES FROM `$database` LIKE '".$this->escape_string($prefix)."%'"); + } + else + { + $query = $this->query("SHOW TABLES FROM `$database`"); + } + + $tables = array(); + while(list($table) = mysql_fetch_array($query)) + { + $tables[] = $table; + } + + return $tables; + } + + /** + * Check if a table exists in a database. + * + * @param string The table name. + * @return boolean True when exists, false if not. + */ + function table_exists($table) + { + // Execute on master server to ensure if we've just created a table that we get the correct result + $query = $this->write_query(" + SHOW TABLES + LIKE '{$this->table_prefix}$table' + "); + $exists = $this->num_rows($query); + if($exists > 0) + { + return true; + } + else + { + return false; + } + } + + /** + * Check if a field exists in a database. + * + * @param string The field name. + * @param string The table name. + * @return boolean True when exists, false if not. + */ + function field_exists($field, $table) + { + $query = $this->write_query(" + SHOW COLUMNS + FROM {$this->table_prefix}$table + LIKE '$field' + "); + $exists = $this->num_rows($query); + if($exists > 0) + { + return true; + } + else + { + return false; + } + } + + /** + * Add a shutdown query. + * + * @param resource The query data. + * @param string An optional name for the query. + */ + function shutdown_query($query, $name=0) + { + global $shutdown_queries; + if($name) + { + $shutdown_queries[$name] = $query; + } + else + { + $shutdown_queries[] = $query; + } + } + /** + * Performs a simple select query. + * + * @param string The table name to be queried. + * @param string Comma delimetered list of fields to be selected. + * @param string SQL formatted list of conditions to be matched. + * @param array List of options: group by, order by, order direction, limit, limit start. + * @return resource The query data. + */ + function simple_select($table, $fields="*", $conditions="", $options=array()) + { + $query = "SELECT ".$fields." FROM {$this->table_prefix}{$table}"; + if($conditions != "") + { + $query .= " WHERE ".$conditions; + } + + if(isset($options['group_by'])) + { + $query .= " GROUP BY ".$options['group_by']; + } + + if(isset($options['order_by'])) + { + $query .= " ORDER BY ".$options['order_by']; + if(isset($options['order_dir'])) + { + $query .= " ".my_strtoupper($options['order_dir']); + } + } + + if(isset($options['limit_start']) && isset($options['limit'])) + { + $query .= " LIMIT ".$options['limit_start'].", ".$options['limit']; + } + elseif(isset($options['limit'])) + { + $query .= " LIMIT ".$options['limit']; + } + + return $this->query($query); + } + + /** + * Build an insert query from an array. + * + * @param string The table name to perform the query on. + * @param array An array of fields and their values. + * @return int The insert ID if available + */ + function insert_query($table, $array) + { + global $mybb; + + if(!is_array($array)) + { + return false; + } + + foreach($array as $field => $value) + { + if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) + { + if($value[0] != 'X') // Not escaped? + { + $value = $this->escape_binary($value); + } + + $array[$field] = $value; + } + else + { + $array[$field] = "'{$value}'"; + } + } + + $fields = "`".implode("`,`", array_keys($array))."`"; + $values = implode(",", $array); + $this->write_query(" + INSERT + INTO {$this->table_prefix}{$table} (".$fields.") + VALUES (".$values.") + "); + return $this->insert_id(); + } + + /** + * Build one query for multiple inserts from a multidimensional array. + * + * @param string The table name to perform the query on. + * @param array An array of inserts. + * @return int The insert ID if available + */ + function insert_query_multiple($table, $array) + { + global $mybb; + + if(!is_array($array)) + { + return false; + } + // Field names + $fields = array_keys($array[0]); + $fields = "`".implode("`,`", $fields)."`"; + + $insert_rows = array(); + foreach($array as $values) + { + foreach($values as $field => $value) + { + if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) + { + if($value[0] != 'X') // Not escaped? + { + $value = $this->escape_binary($value); + } + + $values[$field] = $value; + } + else + { + $values[$field] = "'{$value}'"; + } + } + $insert_rows[] = "(".implode(",", $values).")"; + } + $insert_rows = implode(", ", $insert_rows); + + $this->write_query(" + INSERT + INTO {$this->table_prefix}{$table} ({$fields}) + VALUES {$insert_rows} + "); + } + + /** + * Build an update query from an array. + * + * @param string The table name to perform the query on. + * @param array An array of fields and their values. + * @param string An optional where clause for the query. + * @param string An optional limit clause for the query. + * @param boolean An option to quote incoming values of the array. + * @return resource The query data. + */ + function update_query($table, $array, $where="", $limit="", $no_quote=false) + { + global $mybb; + + if(!is_array($array)) + { + return false; + } + + $comma = ""; + $query = ""; + $quote = "'"; + + if($no_quote == true) + { + $quote = ""; + } + + foreach($array as $field => $value) + { + if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) + { + if($value[0] != 'X') // Not escaped? + { + $value = $this->escape_binary($value); + } + + $query .= $comma."`".$field."`={$value}"; + } + else + { + if(is_numeric($value)) + { + $query .= $comma."`".$field."`={$value}"; + } + else + { + $query .= $comma."`".$field."`={$quote}{$value}{$quote}"; + } + } + $comma = ', '; + } + + if(!empty($where)) + { + $query .= " WHERE $where"; + } + + if(!empty($limit)) + { + $query .= " LIMIT $limit"; + } + + return $this->write_query(" + UPDATE {$this->table_prefix}$table + SET $query + "); + } + + /** + * Build a delete query. + * + * @param string The table name to perform the query on. + * @param string An optional where clause for the query. + * @param string An optional limit clause for the query. + * @return resource The query data. + */ + function delete_query($table, $where="", $limit="") + { + $query = ""; + if(!empty($where)) + { + $query .= " WHERE $where"; + } + + if(!empty($limit)) + { + $query .= " LIMIT $limit"; + } + + return $this->write_query(" + DELETE + FROM {$this->table_prefix}$table + $query + "); + } + + /** + * Escape a string according to the MySQL escape format. + * + * @param string The string to be escaped. + * @return string The escaped string. + */ + function escape_string($string) + { + if($this->db_encoding == 'utf8') + { + $string = validate_utf8_string($string, false); + } + elseif($this->db_encoding == 'utf8mb4') + { + $string = validate_utf8_string($string); + } + + if(function_exists("mysql_real_escape_string") && $this->read_link) + { + $string = mysql_real_escape_string($string, $this->read_link); + } + else + { + $string = addslashes($string); + } + return $string; + } + + /** + * Frees the resources of a MySQLi query. + * + * @param object The query to destroy. + * @return boolean Returns true on success, false on faliure + */ + function free_result($query) + { + return mysql_free_result($query); + } + + /** + * Escape a string used within a like command. + * + * @param string The string to be escaped. + * @return string The escaped string. + */ + function escape_string_like($string) + { + return $this->escape_string(str_replace(array('%', '_') , array('\\%' , '\\_') , $string)); + } + + /** + * Gets the current version of MySQL. + * + * @return string Version of MySQL. + */ + function get_version() + { + if($this->version) + { + return $this->version; + } + + $version = @mysql_get_server_info(); + if(!$version) + { + $query = $this->query("SELECT VERSION() as version"); + $ver = $this->fetch_array($query); + $version = $ver['version']; + } + + if($version) + { + $version = explode(".", $version, 3); + $this->version = (int)$version[0].".".(int)$version[1].".".(int)$version[2]; + } + return $this->version; + } + + /** + * Optimizes a specific table. + * + * @param string The name of the table to be optimized. + */ + function optimize_table($table) + { + $this->write_query("OPTIMIZE TABLE {$this->table_prefix}{$table}"); + } + + /** + * Analyzes a specific table. + * + * @param string The name of the table to be analyzed. + */ + function analyze_table($table) + { + $this->write_query("ANALYZE TABLE {$this->table_prefix}{$table}"); + } + + /** + * Show the "create table" command for a specific table. + * + * @param string The name of the table. + * @return string The MySQL command to create the specified table. + */ + function show_create_table($table) + { + $query = $this->write_query("SHOW CREATE TABLE {$this->table_prefix}{$table}"); + $structure = $this->fetch_array($query); + return $structure['Create Table']; + } + + /** + * Show the "show fields from" command for a specific table. + * + * @param string The name of the table. + * @return string Field info for that table + */ + function show_fields_from($table) + { + $query = $this->write_query("SHOW FIELDS FROM {$this->table_prefix}{$table}"); + while($field = $this->fetch_array($query)) + { + $field_info[] = $field; + } + return $field_info; + } + + /** + * Returns whether or not the table contains a fulltext index. + * + * @param string The name of the table. + * @param string Optionally specify the name of the index. + * @return boolean True or false if the table has a fulltext index or not. + */ + function is_fulltext($table, $index="") + { + $structure = $this->show_create_table($table); + if($index != "") + { + if(preg_match("#FULLTEXT KEY (`?)$index(`?)#i", $structure)) + { + return true; + } + else + { + return false; + } + } + if(preg_match('#FULLTEXT KEY#i', $structure)) + { + return true; + } + return false; + } + + /** + * Returns whether or not this database engine supports fulltext indexing. + * + * @param string The table to be checked. + * @return boolean True or false if supported or not. + */ + + function supports_fulltext($table) + { + $version = $this->get_version(); + $query = $this->write_query("SHOW TABLE STATUS LIKE '{$this->table_prefix}$table'"); + $status = $this->fetch_array($query); + if($status['Engine']) + { + $table_type = my_strtoupper($status['Engine']); + } + else + { + $table_type = my_strtoupper($status['Type']); + } + if(version_compare($version, '3.23.23', '>=') && ($table_type == 'MYISAM' || $table_type == 'ARIA')) + { + return true; + } + elseif(version_compare($version, '5.6', '>=') && $table_type == 'INNODB') + { + return true; + } + return false; + } + + /** + * Checks to see if an index exists on a specified table + * + * @param string The name of the table. + * @param string The name of the index. + */ + function index_exists($table, $index) + { + $index_exists = false; + $query = $this->write_query("SHOW INDEX FROM {$this->table_prefix}{$table}"); + while($ukey = $this->fetch_array($query)) + { + if($ukey['Key_name'] == $index) + { + $index_exists = true; + break; + } + } + + if($index_exists) + { + return true; + } + + return false; + } + + /** + * Returns whether or not this database engine supports boolean fulltext matching. + * + * @param string The table to be checked. + * @return boolean True or false if supported or not. + */ + function supports_fulltext_boolean($table) + { + $version = $this->get_version(); + $supports_fulltext = $this->supports_fulltext($table); + if(version_compare($version, '4.0.1', '>=') && $supports_fulltext == true) + { + return true; + } + return false; + } + + /** + * Creates a fulltext index on the specified column in the specified table with optional index name. + * + * @param string The name of the table. + * @param string Name of the column to be indexed. + * @param string The index name, optional. + */ + function create_fulltext_index($table, $column, $name="") + { + $this->write_query(" + ALTER TABLE {$this->table_prefix}$table + ADD FULLTEXT $name ($column) + "); + } + + /** + * Drop an index with the specified name from the specified table + * + * @param string The name of the table. + * @param string The name of the index. + */ + function drop_index($table, $name) + { + $this->write_query(" + ALTER TABLE {$this->table_prefix}$table + DROP INDEX $name + "); + } + + /** + * Drop an table with the specified table + * + * @param boolean hard drop - no checking + * @param boolean use table prefix + */ + function drop_table($table, $hard=false, $table_prefix=true) + { + if($table_prefix == false) + { + $table_prefix = ""; + } + else + { + $table_prefix = $this->table_prefix; + } + + if($hard == false) + { + $this->write_query('DROP TABLE IF EXISTS '.$table_prefix.$table); + } + else + { + $this->write_query('DROP TABLE '.$table_prefix.$table); + } + } + + /** + * Renames a table + * + * @param string The old table name + * @param string the new table name + * @param boolean use table prefix + */ + function rename_table($old_table, $new_table, $table_prefix=true) + { + if($table_prefix == false) + { + $table_prefix = ""; + } + else + { + $table_prefix = $this->table_prefix; + } + + return $this->write_query("RENAME TABLE {$table_prefix}{$old_table} TO {$table_prefix}{$new_table}"); + } + + /** + * Replace contents of table with values + * + * @param string The table + * @param array The replacements + */ + function replace_query($table, $replacements=array()) + { + global $mybb; + + $values = ''; + $comma = ''; + foreach($replacements as $column => $value) + { + if(isset($mybb->binary_fields[$table][$column]) && $mybb->binary_fields[$table][$column]) + { + if($value[0] != 'X') // Not escaped? + { + $value = $this->escape_binary($value); + } + + $values .= $comma."`".$column."`=".$value; + } + else + { + $values .= $comma."`".$column."`='".$value."'"; + } + + $comma = ','; + } + + if(empty($replacements)) + { + return false; + } + + return $this->write_query("REPLACE INTO {$this->table_prefix}{$table} SET {$values}"); + } + + /** + * Drops a column + * + * @param string The table + * @param string The column name + */ + function drop_column($table, $column) + { + return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} DROP {$column}"); + } + + /** + * Adds a column + * + * @param string The table + * @param string The column name + * @param string the new column definition + */ + function add_column($table, $column, $definition) + { + return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ADD {$column} {$definition}"); + } + + /** + * Modifies a column + * + * @param string The table + * @param string The column name + * @param string the new column definition + */ + function modify_column($table, $column, $new_definition) + { + return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} MODIFY {$column} {$new_definition}"); + } + + /** + * Renames a column + * + * @param string The table + * @param string The old column name + * @param string the new column name + * @param string the new column definition + */ + function rename_column($table, $old_column, $new_column, $new_definition) + { + return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} CHANGE {$old_column} {$new_column} {$new_definition}"); + } + + /** + * Sets the table prefix used by the simple select, insert, update and delete functions + * + * @param string The new table prefix + */ + function set_table_prefix($prefix) + { + $this->table_prefix = $prefix; + } + + /** + * Fetched the total size of all mysql tables or a specific table + * + * @param string The table (optional) + * @return integer the total size of all mysql tables or a specific table + */ + function fetch_size($table='') + { + if($table != '') + { + $query = $this->query("SHOW TABLE STATUS LIKE '".$this->table_prefix.$table."'"); + } + else + { + $query = $this->query("SHOW TABLE STATUS"); + } + $total = 0; + while($table = $this->fetch_array($query)) + { + $total += $table['Data_length']+$table['Index_length']; + } + return $total; + } + + /** + * Fetch a list of database character sets this DBMS supports + * + * @return array Array of supported character sets with array key being the name, array value being display name. False if unsupported + */ + function fetch_db_charsets() + { + if($this->write_link && version_compare($this->get_version(), "4.1", "<")) + { + return false; + } + return array( + 'big5' => 'Big5 Traditional Chinese', + 'dec8' => 'DEC West European', + 'cp850' => 'DOS West European', + 'hp8' => 'HP West European', + 'koi8r' => 'KOI8-R Relcom Russian', + 'latin1' => 'cp1252 West European', + 'latin2' => 'ISO 8859-2 Central European', + 'swe7' => '7bit Swedish', + 'ascii' => 'US ASCII', + 'ujis' => 'EUC-JP Japanese', + 'sjis' => 'Shift-JIS Japanese', + 'hebrew' => 'ISO 8859-8 Hebrew', + 'tis620' => 'TIS620 Thai', + 'euckr' => 'EUC-KR Korean', + 'koi8u' => 'KOI8-U Ukrainian', + 'gb2312' => 'GB2312 Simplified Chinese', + 'greek' => 'ISO 8859-7 Greek', + 'cp1250' => 'Windows Central European', + 'gbk' => 'GBK Simplified Chinese', + 'latin5' => 'ISO 8859-9 Turkish', + 'armscii8' => 'ARMSCII-8 Armenian', + 'utf8' => 'UTF-8 Unicode', + 'utf8mb4' => '4-Byte UTF-8 Unicode (requires MySQL 5.5.3 or above)', + 'ucs2' => 'UCS-2 Unicode', + 'cp866' => 'DOS Russian', + 'keybcs2' => 'DOS Kamenicky Czech-Slovak', + 'macce' => 'Mac Central European', + 'macroman' => 'Mac West European', + 'cp852' => 'DOS Central European', + 'latin7' => 'ISO 8859-13 Baltic', + 'cp1251' => 'Windows Cyrillic', + 'cp1256' => 'Windows Arabic', + 'cp1257' => 'Windows Baltic', + 'binary' => 'Binary pseudo charset', + 'geostd8' => 'GEOSTD8 Georgian', + 'cp932' => 'SJIS for Windows Japanese', + 'eucjpms' => 'UJIS for Windows Japanese', + ); + } + + /** + * Fetch a database collation for a particular database character set + * + * @param string The database character set + * @return string The matching database collation, false if unsupported + */ + function fetch_charset_collation($charset) + { + $collations = array( + 'big5' => 'big5_chinese_ci', + 'dec8' => 'dec8_swedish_ci', + 'cp850' => 'cp850_general_ci', + 'hp8' => 'hp8_english_ci', + 'koi8r' => 'koi8r_general_ci', + 'latin1' => 'latin1_swedish_ci', + 'latin2' => 'latin2_general_ci', + 'swe7' => 'swe7_swedish_ci', + 'ascii' => 'ascii_general_ci', + 'ujis' => 'ujis_japanese_ci', + 'sjis' => 'sjis_japanese_ci', + 'hebrew' => 'hebrew_general_ci', + 'tis620' => 'tis620_thai_ci', + 'euckr' => 'euckr_korean_ci', + 'koi8u' => 'koi8u_general_ci', + 'gb2312' => 'gb2312_chinese_ci', + 'greek' => 'greek_general_ci', + 'cp1250' => 'cp1250_general_ci', + 'gbk' => 'gbk_chinese_ci', + 'latin5' => 'latin5_turkish_ci', + 'armscii8' => 'armscii8_general_ci', + 'utf8' => 'utf8_general_ci', + 'utf8mb4' => 'utf8mb4_general_ci', + 'ucs2' => 'ucs2_general_ci', + 'cp866' => 'cp866_general_ci', + 'keybcs2' => 'keybcs2_general_ci', + 'macce' => 'macce_general_ci', + 'macroman' => 'macroman_general_ci', + 'cp852' => 'cp852_general_ci', + 'latin7' => 'latin7_general_ci', + 'cp1251' => 'cp1251_general_ci', + 'cp1256' => 'cp1256_general_ci', + 'cp1257' => 'cp1257_general_ci', + 'binary' => 'binary', + 'geostd8' => 'geostd8_general_ci', + 'cp932' => 'cp932_japanese_ci', + 'eucjpms' => 'eucjpms_japanese_ci', + ); + if($collations[$charset]) + { + return $collations[$charset]; + } + return false; + } + + /** + * Fetch a character set/collation string for use with CREATE TABLE statements. Uses current DB encoding + * + * @return string The built string, empty if unsupported + */ + function build_create_table_collation() + { + if(!$this->db_encoding) + { + return ''; + } + + $collation = $this->fetch_charset_collation($this->db_encoding); + if(!$collation) + { + return ''; + } + return " CHARACTER SET {$this->db_encoding} COLLATE {$collation}"; + } + + /** + * Time how long it takes for a particular piece of code to run. Place calls above & below the block of code. + * + * @deprecated + */ + function get_execution_time() + { + return get_execution_time(); + } + + /** + * Binary database fields require special attention. + * + * @param string Binary value + * @return string Encoded binary value + */ + function escape_binary($string) + { + return "X'".$this->escape_string(bin2hex($string))."'"; + } + + /** + * Unescape binary data. + * + * @param string Binary value + * @return string Encoded binary value + */ + function unescape_binary($string) + { + // Nothing to do + return $string; + } +} + diff --git a/Upload/inc/db_mysqli.php b/Upload/inc/db_mysqli.php new file mode 100644 index 0000000..6258e09 --- /dev/null +++ b/Upload/inc/db_mysqli.php @@ -0,0 +1,1520 @@ + write; 0 => read + * + * @var int + */ + protected $last_query_type = 0; + + /** + * Connect to the database server. + * + * @param array Array of DBMS connection details. + * @return resource The DB connection resource. Returns false on fail or -1 on a db connect failure. + */ + function connect($config) + { + // Simple connection to one server + if(array_key_exists('hostname', $config)) + { + $connections['read'][] = $config; + } + else + // Connecting to more than one server + { + // Specified multiple servers, but no specific read/write servers + if(!array_key_exists('read', $config)) + { + foreach($config as $key => $settings) + { + if(is_int($key)) + { + $connections['read'][] = $settings; + } + } + } + // Specified both read & write servers + else + { + $connections = $config; + } + } + + $this->db_encoding = $config['encoding']; + + // Actually connect to the specified servers + foreach(array('read', 'write') as $type) + { + if(!isset($connections[$type]) || !is_array($connections[$type])) + { + break; + } + + if(array_key_exists('hostname', $connections[$type])) + { + $details = $connections[$type]; + unset($connections); + $connections[$type][] = $details; + } + + // Shuffle the connections + shuffle($connections[$type]); + + // Loop-de-loop + foreach($connections[$type] as $single_connection) + { + $connect_function = "mysqli_connect"; + $persist = ""; + if(!empty($single_connection['pconnect']) && version_compare(PHP_VERSION, '5.3.0', '>=')) + { + $persist = 'p:'; + } + + $link = "{$type}_link"; + + get_execution_time(); + + // Specified a custom port for this connection? + $port = 0; + if(strstr($single_connection['hostname'],':')) + { + list($hostname, $port) = explode(":", $single_connection['hostname'], 2); + } + + if($port) + { + $this->$link = @$connect_function($persist.$hostname, $single_connection['username'], $single_connection['password'], "", $port); + } + else + { + $this->$link = @$connect_function($persist.$single_connection['hostname'], $single_connection['username'], $single_connection['password']); + } + + $time_spent = get_execution_time(); + $this->query_time += $time_spent; + + // Successful connection? break down brother! + if($this->$link) + { + $this->connections[] = "[".strtoupper($type)."] {$single_connection['username']}@{$single_connection['hostname']} (Connected in ".format_time_duration($time_spent).")"; + break; + } + else + { + $this->connections[] = "[FAILED] [".strtoupper($type)."] {$single_connection['username']}@{$single_connection['hostname']}"; + } + } + } + + // No write server was specified (simple connection or just multiple servers) - mirror write link + if(!array_key_exists('write', $connections)) + { + $this->write_link = &$this->read_link; + } + + // Have no read connection? + if(!$this->read_link) + { + $this->error("[READ] Unable to connect to MySQL server"); + return false; + } + // No write? + else if(!$this->write_link) + { + $this->error("[WRITE] Unable to connect to MySQL server"); + return false; + } + + // Select databases + if(!$this->select_db($config['database'])) + { + return -1; + } + + $this->current_link = &$this->read_link; + return $this->read_link; + } + + /** + * Selects the database to use. + * + * @param string The database name. + * @return boolean True when successfully connected, false if not. + */ + function select_db($database) + { + global $mybb; + + $master_success = @mysqli_select_db($this->read_link, $database) or $this->error("[READ] Unable to select database", $this->read_link); + if($this->write_link) + { + $slave_success = @mysqli_select_db($this->write_link, $database) or $this->error("[WRITE] Unable to select slave database", $this->write_link); + + $success = ($master_success && $slave_success ? true : false); + } + else + { + $success = $master_success; + } + + if($success && $this->db_encoding) + { + @mysqli_set_charset($this->read_link, $this->db_encoding); + + if($slave_success && count($this->connections) > 1) + { + @mysqli_set_charset($this->write_link, $this->db_encoding); + } + } + return $success; + } + + /** + * Query the database. + * + * @param string The query SQL. + * @param boolean 1 if hide errors, 0 if not. + * @param integer 1 if executes on master database, 0 if not. + * @return resource The query data. + */ + function query($string, $hide_errors=0, $write_query=0) + { + global $pagestarttime, $db, $mybb; + + get_execution_time(); + + // Only execute write queries on master server + if(($write_query || $this->last_query_type) && $this->write_link) + { + $this->current_link = &$this->write_link; + $query = @mysqli_query($this->write_link, $string); + } + else + { + $this->current_link = &$this->read_link; + $query = @mysqli_query($this->read_link, $string); + } + + if($this->error_number() && !$hide_errors) + { + $this->error($string); + exit; + } + + if($write_query) + { + $this->last_query_type = 1; + } + else + { + $this->last_query_type = 0; + } + + $query_time = get_execution_time(); + $this->query_time += $query_time; + $this->query_count++; + + if($mybb->debug_mode) + { + $this->explain_query($string, $query_time); + } + return $query; + } + + /** + * Execute a write query on the master database + * + * @param string The query SQL. + * @param boolean 1 if hide errors, 0 if not. + * @return resource The query data. + */ + function write_query($query, $hide_errors=0) + { + return $this->query($query, $hide_errors, 1); + } + + /** + * Explain a query on the database. + * + * @param string The query SQL. + * @param string The time it took to perform the query. + */ + function explain_query($string, $qtime) + { + global $plugins; + + $debug_extra = ''; + if($plugins->current_hook) + { + $debug_extra = "
    (Plugin Hook: {$plugins->current_hook})
    "; + } + if(preg_match("#^\s*select#i", $string)) + { + $query = mysqli_query($this->current_link, "EXPLAIN $string"); + $this->explain .= "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n"; + + while($table = mysqli_fetch_assoc($query)) + { + $this->explain .= + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n"; + } + $this->explain .= + "\n". + "\n". + "\n". + "
    {$debug_extra}
    #".$this->query_count." - Select Query
    ".htmlspecialchars_uni($string)."
    TableTypePossible KeysKeyKey LengthRefRowsExtra
    ".$table['table']."".$table['type']."".$table['possible_keys']."".$table['key']."".$table['key_len']."".$table['ref']."".$table['rows']."".$table['Extra']."
    Query Time: ".format_time_duration($qtime)."
    \n". + "
    \n"; + } + else + { + $this->explain .= "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "
    {$debug_extra}
    #".$this->query_count." - Write Query
    ".htmlspecialchars_uni($string)."
    Query Time: ".format_time_duration($qtime)."
    \n". + "
    \n"; + } + + $this->querylist[$this->query_count]['query'] = $string; + $this->querylist[$this->query_count]['time'] = $qtime; + } + + /** + * Return a result array for a query. + * + * @param resource The query data. + * @param constant The type of array to return. + * @return array The array of results. + */ + function fetch_array($query, $resulttype=MYSQLI_ASSOC) + { + switch($resulttype) + { + case MYSQLI_NUM: + case MYSQLI_BOTH: + break; + default: + $resulttype = MYSQLI_ASSOC; + break; + } + + $array = mysqli_fetch_array($query, $resulttype); + + return $array; + } + + /** + * Return a specific field from a query. + * + * @param resource The query ID. + * @param string The name of the field to return. + * @param int The number of the row to fetch it from. + */ + function fetch_field($query, $field, $row=false) + { + if($row !== false) + { + $this->data_seek($query, $row); + } + $array = $this->fetch_array($query); + return $array[$field]; + } + + /** + * Moves internal row pointer to the next row + * + * @param resource The query ID. + * @param int The pointer to move the row to. + */ + function data_seek($query, $row) + { + return mysqli_data_seek($query, $row); + } + + /** + * Return the number of rows resulting from a query. + * + * @param resource The query data. + * @return int The number of rows in the result. + */ + function num_rows($query) + { + return mysqli_num_rows($query); + } + + /** + * Return the last id number of inserted data. + * + * @return int The id number. + */ + function insert_id() + { + $id = mysqli_insert_id($this->current_link); + return $id; + } + + /** + * Close the connection with the DBMS. + * + */ + function close() + { + @mysqli_close($this->read_link); + if($this->write_link) + { + @mysqli_close($this->write_link); + } + } + + /** + * Return an error number. + * + * @return int The error number of the current error. + */ + function error_number() + { + if($this->current_link) + { + return mysqli_errno($this->current_link); + } + else + { + return mysqli_connect_errno(); + } + } + + /** + * Return an error string. + * + * @return string The explanation for the current error. + */ + function error_string() + { + if($this->current_link) + { + return mysqli_error($this->current_link); + } + else + { + return mysqli_connect_error(); + } + } + + /** + * Output a database error. + * + * @param string The string to present as an error. + */ + function error($string="") + { + if($this->error_reporting) + { + if(class_exists("errorHandler")) + { + global $error_handler; + + if(!is_object($error_handler)) + { + require_once MYBB_ROOT."inc/class_error.php"; + $error_handler = new errorHandler(); + } + + $error = array( + "error_no" => $this->error_number(), + "error" => $this->error_string(), + "query" => $string + ); + $error_handler->error(MYBB_SQL, $error); + } + else + { + trigger_error("[SQL] [".$this->error_number()."] ".$this->error_string()."
    {$string}", E_USER_ERROR); + } + } + else + { + return false; + } + } + + /** + * Returns the number of affected rows in a query. + * + * @return int The number of affected rows. + */ + function affected_rows() + { + return mysqli_affected_rows($this->current_link); + } + + /** + * Return the number of fields. + * + * @param resource The query data. + * @return int The number of fields. + */ + function num_fields($query) + { + return mysqli_num_fields($query); + } + + /** + * Lists all functions in the database. + * + * @param string The database name. + * @param string Prefix of the table (optional) + * @return array The table list. + */ + function list_tables($database, $prefix='') + { + if($prefix) + { + $query = $this->query("SHOW TABLES FROM `$database` LIKE '".$this->escape_string($prefix)."%'"); + } + else + { + $query = $this->query("SHOW TABLES FROM `$database`"); + } + + $tables = array(); + while(list($table) = mysqli_fetch_array($query)) + { + $tables[] = $table; + } + return $tables; + } + + /** + * Check if a table exists in a database. + * + * @param string The table name. + * @return boolean True when exists, false if not. + */ + function table_exists($table) + { + // Execute on master server to ensure if we've just created a table that we get the correct result + $query = $this->write_query(" + SHOW TABLES + LIKE '{$this->table_prefix}$table' + "); + $exists = $this->num_rows($query); + + if($exists > 0) + { + return true; + } + else + { + return false; + } + } + + /** + * Check if a field exists in a database. + * + * @param string The field name. + * @param string The table name. + * @return boolean True when exists, false if not. + */ + function field_exists($field, $table) + { + $query = $this->write_query(" + SHOW COLUMNS + FROM {$this->table_prefix}$table + LIKE '$field' + "); + $exists = $this->num_rows($query); + + if($exists > 0) + { + return true; + } + else + { + return false; + } + } + + /** + * Add a shutdown query. + * + * @param resource The query data. + * @param string An optional name for the query. + */ + function shutdown_query($query, $name=0) + { + global $shutdown_queries; + if($name) + { + $shutdown_queries[$name] = $query; + } + else + { + $shutdown_queries[] = $query; + } + } + + /** + * Performs a simple select query. + * + * @param string The table name to be queried. + * @param string Comma delimetered list of fields to be selected. + * @param string SQL formatted list of conditions to be matched. + * @param array List of options: group by, order by, order direction, limit, limit start. + * @return resource The query data. + */ + function simple_select($table, $fields="*", $conditions="", $options=array()) + { + $query = "SELECT ".$fields." FROM ".$this->table_prefix.$table; + + if($conditions != "") + { + $query .= " WHERE ".$conditions; + } + + if(isset($options['group_by'])) + { + $query .= " GROUP BY ".$options['group_by']; + } + + if(isset($options['order_by'])) + { + $query .= " ORDER BY ".$options['order_by']; + if(isset($options['order_dir'])) + { + $query .= " ".my_strtoupper($options['order_dir']); + } + } + + if(isset($options['limit_start']) && isset($options['limit'])) + { + $query .= " LIMIT ".$options['limit_start'].", ".$options['limit']; + } + else if(isset($options['limit'])) + { + $query .= " LIMIT ".$options['limit']; + } + + return $this->query($query); + } + + /** + * Build an insert query from an array. + * + * @param string The table name to perform the query on. + * @param array An array of fields and their values. + * @return int The insert ID if available + */ + function insert_query($table, $array) + { + global $mybb; + + if(!is_array($array)) + { + return false; + } + + foreach($array as $field => $value) + { + if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) + { + if($value[0] != 'X') // Not escaped? + { + $value = $this->escape_binary($value); + } + + $array[$field] = $value; + } + else + { + $array[$field] = "'{$value}'"; + } + } + + $fields = "`".implode("`,`", array_keys($array))."`"; + $values = implode(",", $array); + $this->write_query(" + INSERT + INTO {$this->table_prefix}{$table} (".$fields.") + VALUES (".$values.") + "); + return $this->insert_id(); + } + + /** + * Build one query for multiple inserts from a multidimensional array. + * + * @param string The table name to perform the query on. + * @param array An array of inserts. + * @return int The insert ID if available + */ + function insert_query_multiple($table, $array) + { + global $mybb; + + if(!is_array($array)) + { + return false; + } + // Field names + $fields = array_keys($array[0]); + $fields = "`".implode("`,`", $fields)."`"; + + $insert_rows = array(); + foreach($array as $values) + { + foreach($values as $field => $value) + { + if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) + { + if($value[0] != 'X') // Not escaped? + { + $value = $this->escape_binary($value); + } + + $values[$field] = $value; + } + else + { + $values[$field] = "'{$value}'"; + } + } + $insert_rows[] = "(".implode(",", $values).")"; + } + $insert_rows = implode(", ", $insert_rows); + + $this->write_query(" + INSERT + INTO {$this->table_prefix}{$table} ({$fields}) + VALUES {$insert_rows} + "); + } + + /** + * Build an update query from an array. + * + * @param string The table name to perform the query on. + * @param array An array of fields and their values. + * @param string An optional where clause for the query. + * @param string An optional limit clause for the query. + * @param boolean An option to quote incoming values of the array. + * @return resource The query data. + */ + function update_query($table, $array, $where="", $limit="", $no_quote=false) + { + global $mybb; + + if(!is_array($array)) + { + return false; + } + + $comma = ""; + $query = ""; + $quote = "'"; + + if($no_quote == true) + { + $quote = ""; + } + + foreach($array as $field => $value) + { + if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) + { + if($value[0] != 'X') // Not escaped? + { + $value = $this->escape_binary($value); + } + + $query .= $comma."`".$field."`={$value}"; + } + else + { + if(is_numeric($value)) + { + $query .= $comma."`".$field."`={$value}"; + } + else + { + $query .= $comma."`".$field."`={$quote}{$value}{$quote}"; + } + } + $comma = ', '; + } + + if(!empty($where)) + { + $query .= " WHERE $where"; + } + + if(!empty($limit)) + { + $query .= " LIMIT $limit"; + } + + return $this->write_query(" + UPDATE {$this->table_prefix}$table + SET $query + "); + } + + /** + * Build a delete query. + * + * @param string The table name to perform the query on. + * @param string An optional where clause for the query. + * @param string An optional limit clause for the query. + * @return resource The query data. + */ + function delete_query($table, $where="", $limit="") + { + $query = ""; + if(!empty($where)) + { + $query .= " WHERE $where"; + } + if(!empty($limit)) + { + $query .= " LIMIT $limit"; + } + return $this->write_query("DELETE FROM {$this->table_prefix}$table $query"); + } + + /** + * Escape a string according to the MySQL escape format. + * + * @param string The string to be escaped. + * @return string The escaped string. + */ + function escape_string($string) + { + if($this->db_encoding == 'utf8') + { + $string = validate_utf8_string($string, false); + } + elseif($this->db_encoding == 'utf8mb4') + { + $string = validate_utf8_string($string); + } + + if(function_exists("mysqli_real_escape_string") && $this->read_link) + { + $string = mysqli_real_escape_string($this->read_link, $string); + } + else + { + $string = addslashes($string); + } + return $string; + } + + /** + * Frees the resources of a MySQLi query. + * + * @param object The query to destroy. + * @return boolean Returns true on success, false on faliure + */ + function free_result($query) + { + return mysqli_free_result($query); + } + + /** + * Escape a string used within a like command. + * + * @param string The string to be escaped. + * @return string The escaped string. + */ + function escape_string_like($string) + { + return $this->escape_string(str_replace(array('%', '_') , array('\\%' , '\\_') , $string)); + } + + /** + * Gets the current version of MySQL. + * + * @return string Version of MySQL. + */ + function get_version() + { + if($this->version) + { + return $this->version; + } + + $version = @mysqli_get_server_info($this->read_link); + if(!$version) + { + $query = $this->query("SELECT VERSION() as version"); + $ver = $this->fetch_array($query); + $version = $ver['version']; + } + + if($version) + { + $version = explode(".", $version, 3); + $this->version = (int)$version[0].".".(int)$version[1].".".(int)$version[2]; + } + return $this->version; + } + + /** + * Optimizes a specific table. + * + * @param string The name of the table to be optimized. + */ + function optimize_table($table) + { + $this->write_query("OPTIMIZE TABLE ".$this->table_prefix.$table.""); + } + + /** + * Analyzes a specific table. + * + * @param string The name of the table to be analyzed. + */ + function analyze_table($table) + { + $this->write_query("ANALYZE TABLE ".$this->table_prefix.$table.""); + } + + /** + * Show the "create table" command for a specific table. + * + * @param string The name of the table. + * @return string The MySQL command to create the specified table. + */ + function show_create_table($table) + { + $query = $this->write_query("SHOW CREATE TABLE ".$this->table_prefix.$table.""); + $structure = $this->fetch_array($query); + + return $structure['Create Table']; + } + + /** + * Show the "show fields from" command for a specific table. + * + * @param string The name of the table. + * @return string Field info for that table + */ + function show_fields_from($table) + { + $query = $this->write_query("SHOW FIELDS FROM ".$this->table_prefix.$table.""); + while($field = $this->fetch_array($query)) + { + $field_info[] = $field; + } + return $field_info; + } + + /** + * Returns whether or not the table contains a fulltext index. + * + * @param string The name of the table. + * @param string Optionally specify the name of the index. + * @return boolean True or false if the table has a fulltext index or not. + */ + function is_fulltext($table, $index="") + { + $structure = $this->show_create_table($table); + if($index != "") + { + if(preg_match("#FULLTEXT KEY (`?)$index(`?)#i", $structure)) + { + return true; + } + else + { + return false; + } + } + if(preg_match('#FULLTEXT KEY#i', $structure)) + { + return true; + } + return false; + } + + /** + * Returns whether or not this database engine supports fulltext indexing. + * + * @param string The table to be checked. + * @return boolean True or false if supported or not. + */ + + function supports_fulltext($table) + { + $version = $this->get_version(); + $query = $this->write_query("SHOW TABLE STATUS LIKE '{$this->table_prefix}$table'"); + $status = $this->fetch_array($query); + $table_type = my_strtoupper($status['Engine']); + if(version_compare($version, '3.23.23', '>=') && ($table_type == 'MYISAM' || $table_type == 'ARIA')) + { + return true; + } + elseif(version_compare($version, '5.6', '>=') && $table_type == 'INNODB') + { + return true; + } + return false; + } + + /** + * Returns whether or not this database engine supports boolean fulltext matching. + * + * @param string The table to be checked. + * @return boolean True or false if supported or not. + */ + function supports_fulltext_boolean($table) + { + $version = $this->get_version(); + $supports_fulltext = $this->supports_fulltext($table); + if(version_compare($version, '4.0.1', '>=') && $supports_fulltext == true) + { + return true; + } + return false; + } + + /** + * Checks to see if an index exists on a specified table + * + * @param string The name of the table. + * @param string The name of the index. + */ + function index_exists($table, $index) + { + $index_exists = false; + $query = $this->write_query("SHOW INDEX FROM {$this->table_prefix}{$table}"); + while($ukey = $this->fetch_array($query)) + { + if($ukey['Key_name'] == $index) + { + $index_exists = true; + break; + } + } + + if($index_exists) + { + return true; + } + + return false; + } + + /** + * Creates a fulltext index on the specified column in the specified table with optional index name. + * + * @param string The name of the table. + * @param string Name of the column to be indexed. + * @param string The index name, optional. + */ + function create_fulltext_index($table, $column, $name="") + { + $this->write_query("ALTER TABLE {$this->table_prefix}$table ADD FULLTEXT $name ($column)"); + } + + /** + * Drop an index with the specified name from the specified table + * + * @param string The name of the table. + * @param string The name of the index. + */ + function drop_index($table, $name) + { + $this->write_query("ALTER TABLE {$this->table_prefix}$table DROP INDEX $name"); + } + + /** + * Drop an table with the specified table + * + * @param boolean hard drop - no checking + * @param boolean use table prefix + */ + function drop_table($table, $hard=false, $table_prefix=true) + { + if($table_prefix == false) + { + $table_prefix = ""; + } + else + { + $table_prefix = $this->table_prefix; + } + + if($hard == false) + { + $this->write_query('DROP TABLE IF EXISTS '.$table_prefix.$table); + } + else + { + $this->write_query('DROP TABLE '.$table_prefix.$table); + } + } + + /** + * Renames a table + * + * @param string The old table name + * @param string the new table name + * @param boolean use table prefix + */ + function rename_table($old_table, $new_table, $table_prefix=true) + { + if($table_prefix == false) + { + $table_prefix = ""; + } + else + { + $table_prefix = $this->table_prefix; + } + + return $this->write_query("RENAME TABLE {$table_prefix}{$old_table} TO {$table_prefix}{$new_table}"); + } + + /** + * Replace contents of table with values + * + * @param string The table + * @param array The replacements + */ + function replace_query($table, $replacements=array()) + { + global $mybb; + + $values = ''; + $comma = ''; + foreach($replacements as $column => $value) + { + if(isset($mybb->binary_fields[$table][$column]) && $mybb->binary_fields[$table][$column]) + { + if($value[0] != 'X') // Not escaped? + { + $value = $this->escape_binary($value); + } + + $values .= $comma."`".$column."`=".$value; + } + else + { + $values .= $comma."`".$column."`='".$value."'"; + } + + $comma = ','; + } + + if(empty($replacements)) + { + return false; + } + + return $this->write_query("REPLACE INTO {$this->table_prefix}{$table} SET {$values}"); + } + + /** + * Drops a column + * + * @param string The table + * @param string The column name + */ + function drop_column($table, $column) + { + return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} DROP {$column}"); + } + + /** + * Adds a column + * + * @param string The table + * @param string The column name + * @param string the new column definition + */ + function add_column($table, $column, $definition) + { + return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ADD {$column} {$definition}"); + } + + /** + * Modifies a column + * + * @param string The table + * @param string The column name + * @param string the new column definition + */ + function modify_column($table, $column, $new_definition) + { + return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} MODIFY {$column} {$new_definition}"); + } + + /** + * Renames a column + * + * @param string The table + * @param string The old column name + * @param string the new column name + * @param string the new column definition + */ + function rename_column($table, $old_column, $new_column, $new_definition) + { + return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} CHANGE {$old_column} {$new_column} {$new_definition}"); + } + + /** + * Sets the table prefix used by the simple select, insert, update and delete functions + * + * @param string The new table prefix + */ + function set_table_prefix($prefix) + { + $this->table_prefix = $prefix; + } + + /** + * Fetched the total size of all mysql tables or a specific table + * + * @param string The table (optional) + * @return integer the total size of all mysql tables or a specific table + */ + function fetch_size($table='') + { + if($table != '') + { + $query = $this->query("SHOW TABLE STATUS LIKE '".$this->table_prefix.$table."'"); + } + else + { + $query = $this->query("SHOW TABLE STATUS"); + } + $total = 0; + while($table = $this->fetch_array($query)) + { + $total += $table['Data_length']+$table['Index_length']; + } + return $total; + } + + /** + * Fetch a list of database character sets this DBMS supports + * + * @return array Array of supported character sets with array key being the name, array value being display name. False if unsupported + */ + function fetch_db_charsets() + { + if($this->write_link && version_compare($this->get_version(), "4.1", "<")) + { + return false; + } + return array( + 'big5' => 'Big5 Traditional Chinese', + 'dec8' => 'DEC West European', + 'cp850' => 'DOS West European', + 'hp8' => 'HP West European', + 'koi8r' => 'KOI8-R Relcom Russian', + 'latin1' => 'cp1252 West European', + 'latin2' => 'ISO 8859-2 Central European', + 'swe7' => '7bit Swedish', + 'ascii' => 'US ASCII', + 'ujis' => 'EUC-JP Japanese', + 'sjis' => 'Shift-JIS Japanese', + 'hebrew' => 'ISO 8859-8 Hebrew', + 'tis620' => 'TIS620 Thai', + 'euckr' => 'EUC-KR Korean', + 'koi8u' => 'KOI8-U Ukrainian', + 'gb2312' => 'GB2312 Simplified Chinese', + 'greek' => 'ISO 8859-7 Greek', + 'cp1250' => 'Windows Central European', + 'gbk' => 'GBK Simplified Chinese', + 'latin5' => 'ISO 8859-9 Turkish', + 'armscii8' => 'ARMSCII-8 Armenian', + 'utf8' => 'UTF-8 Unicode', + 'utf8mb4' => '4-Byte UTF-8 Unicode (requires MySQL 5.5.3 or above)', + 'ucs2' => 'UCS-2 Unicode', + 'cp866' => 'DOS Russian', + 'keybcs2' => 'DOS Kamenicky Czech-Slovak', + 'macce' => 'Mac Central European', + 'macroman' => 'Mac West European', + 'cp852' => 'DOS Central European', + 'latin7' => 'ISO 8859-13 Baltic', + 'cp1251' => 'Windows Cyrillic', + 'cp1256' => 'Windows Arabic', + 'cp1257' => 'Windows Baltic', + 'binary' => 'Binary pseudo charset', + 'geostd8' => 'GEOSTD8 Georgian', + 'cp932' => 'SJIS for Windows Japanese', + 'eucjpms' => 'UJIS for Windows Japanese', + ); + } + + /** + * Fetch a database collation for a particular database character set + * + * @param string The database character set + * @return string The matching database collation, false if unsupported + */ + function fetch_charset_collation($charset) + { + $collations = array( + 'big5' => 'big5_chinese_ci', + 'dec8' => 'dec8_swedish_ci', + 'cp850' => 'cp850_general_ci', + 'hp8' => 'hp8_english_ci', + 'koi8r' => 'koi8r_general_ci', + 'latin1' => 'latin1_swedish_ci', + 'latin2' => 'latin2_general_ci', + 'swe7' => 'swe7_swedish_ci', + 'ascii' => 'ascii_general_ci', + 'ujis' => 'ujis_japanese_ci', + 'sjis' => 'sjis_japanese_ci', + 'hebrew' => 'hebrew_general_ci', + 'tis620' => 'tis620_thai_ci', + 'euckr' => 'euckr_korean_ci', + 'koi8u' => 'koi8u_general_ci', + 'gb2312' => 'gb2312_chinese_ci', + 'greek' => 'greek_general_ci', + 'cp1250' => 'cp1250_general_ci', + 'gbk' => 'gbk_chinese_ci', + 'latin5' => 'latin5_turkish_ci', + 'armscii8' => 'armscii8_general_ci', + 'utf8' => 'utf8_general_ci', + 'utf8mb4' => 'utf8mb4_general_ci', + 'ucs2' => 'ucs2_general_ci', + 'cp866' => 'cp866_general_ci', + 'keybcs2' => 'keybcs2_general_ci', + 'macce' => 'macce_general_ci', + 'macroman' => 'macroman_general_ci', + 'cp852' => 'cp852_general_ci', + 'latin7' => 'latin7_general_ci', + 'cp1251' => 'cp1251_general_ci', + 'cp1256' => 'cp1256_general_ci', + 'cp1257' => 'cp1257_general_ci', + 'binary' => 'binary', + 'geostd8' => 'geostd8_general_ci', + 'cp932' => 'cp932_japanese_ci', + 'eucjpms' => 'eucjpms_japanese_ci', + ); + if($collations[$charset]) + { + return $collations[$charset]; + } + return false; + } + + /** + * Fetch a character set/collation string for use with CREATE TABLE statements. Uses current DB encoding + * + * @return string The built string, empty if unsupported + */ + function build_create_table_collation() + { + if(!$this->db_encoding) + { + return ''; + } + + $collation = $this->fetch_charset_collation($this->db_encoding); + if(!$collation) + { + return ''; + } + return " CHARACTER SET {$this->db_encoding} COLLATE {$collation}"; + } + + /** + * Time how long it takes for a particular piece of code to run. Place calls above & below the block of code. + * + * @deprecated + */ + function get_execution_time() + { + return get_execution_time(); + } + + /** + * Binary database fields require special attention. + * + * @param string Binary value + * @return string Encoded binary value + */ + function escape_binary($string) + { + return "X'".$this->escape_string(bin2hex($string))."'"; + } + + /** + * Unescape binary data. + * + * @param string Binary value + * @return string Encoded binary value + */ + function unescape_binary($string) + { + // Nothing to do + return $string; + } +} + diff --git a/Upload/inc/db_pdo.php b/Upload/inc/db_pdo.php new file mode 100644 index 0000000..7f6b8ca --- /dev/null +++ b/Upload/inc/db_pdo.php @@ -0,0 +1,239 @@ +db = new PDO($dsn, $user, $password, $driver_options); + } + catch(PDOException $exception) + { + die('Connection failed: '.$exception->getMessage()); + } + + $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + return true; + } + + /** + * Query the database. + * + * @param string The query SQL. + * @return resource The query data. + */ + function query($string) + { + ++$this->queries; + + $query = $this->db->query($string, PDO::FETCH_BOTH); + $this->last_query = $query; + + $query->guid = $this->queries; + + return $query; + } + + /** + * Return a result array for a query. + * + * @param resource The query resource. + * @return array The array of results. + */ + function fetch_array($query) + { + if(!is_object($query)) + { + return; + } + + if($this->seek_array[$query->guid]) + { + $array = $query->fetch(PDO::FETCH_BOTH, $this->seek[$query->guid]['offset'], $this->seek[$query->guid]['row']); + } + else + { + $array = $query->fetch(PDO::FETCH_BOTH); + } + + return $array; + } + + /** + * Moves internal row pointer to the next row + * + * @param resource The query resource. + * @param int The pointer to move the row to. + */ + function seek($query, $row) + { + if(!is_object($query)) + { + return; + } + + $this->seek_array[$query->guid] = array('offset' => PDO::FETCH_ORI_ABS, 'row' => $row); + } + + /** + * Return the number of rows resulting from a query. + * + * @param resource The query resource. + * @return int The number of rows in the result. + */ + function num_rows($query) + { + if(!is_object($query)) + { + return; + } + + if(is_numeric(stripos($query->queryString, 'SELECT'))) + { + $query = $this->db->query($query->queryString); + $result = $query->fetchAll(); + return count($result); + } + else + { + return $query->rowCount(); + } + } + + /** + * Return the last id number of inserted data. + * + * @param string The name of the insert id to check. (Optional) + * @return int The id number. + */ + function insert_id($name="") + { + return $this->db->lastInsertId($name); + } + + /** + * Return an error number. + * + * @param resource The query resource. + * @return int The error number of the current error. + */ + function error_number($query) + { + if(!is_object($query) || !method_exists($query, "errorCode")) + { + return; + } + + $errorcode = $query->errorCode(); + + return $errorcode; + } + + /** + * Return an error string. + * + * @param resource The query resource. + * @return int The error string of the current error. + */ + function error_string($query) + { + if(!is_object($query) || !method_exists($query, "errorInfo")) + { + return $this->db->errorInfo(); + } + return $query->errorInfo(); + } + + /** + * Roll back the last query. + * + * @return boolean true on success, false otherwise. + */ + function roll_back() + { + //return $this->db->rollBack(); + } + + /** + * Returns the number of affected rows in a query. + * + * @return int The number of affected rows. + */ + function affected_rows($query) + { + return $query->rowCount(); + } + + /** + * Return the number of fields. + * + * @param resource The query resource. + * @return int The number of fields. + */ + function num_fields($query) + { + return $query->columnCount(); + } + + function escape_string($string) + { + $string = $this->db->quote($string); + + // Remove ' from the begginging of the string and at the end of the string, because we already use it in insert_query + $string = substr($string, 1); + $string = substr($string, 0, -1); + + return $string; + } + + /** + * Return a selected attribute + * + * @param constant The attribute to check. + * @return string The value of the attribute. + */ + function get_attribute($attribute) + { + $attribute = $this->db->getAttribute(constant("PDO::".$attribute."")); + + return $attribute; + } +} + diff --git a/Upload/inc/db_pgsql.php b/Upload/inc/db_pgsql.php new file mode 100644 index 0000000..46cb726 --- /dev/null +++ b/Upload/inc/db_pgsql.php @@ -0,0 +1,1546 @@ + $settings) + { + if(is_int($key)) $connections['read'][] = $settings; + } + } + // Specified both read & write servers + else + { + $connections = $config; + } + } + + $this->db_encoding = $config['encoding']; + + // Actually connect to the specified servers + foreach(array('read', 'write') as $type) + { + if(!isset($connections[$type]) || !is_array($connections[$type])) + { + break; + } + + if(array_key_exists('hostname', $connections[$type])) + { + $details = $connections[$type]; + unset($connections); + $connections[$type][] = $details; + } + + // Shuffle the connections + shuffle($connections[$type]); + + // Loop-de-loop + foreach($connections[$type] as $single_connection) + { + $connect_function = "pg_connect"; + if(isset($single_connection['pconnect'])) + { + $connect_function = "pg_pconnect"; + } + + $link = $type."_link"; + + get_execution_time(); + + $this->connect_string = "dbname={$single_connection['database']} user={$single_connection['username']}"; + + if(strpos($single_connection['hostname'], ':') !== false) + { + list($single_connection['hostname'], $single_connection['port']) = explode(':', $single_connection['hostname']); + } + + if($single_connection['port']) + { + $this->connect_string .= " port={$single_connection['port']}"; + } + + if($single_connection['hostname'] != "") + { + $this->connect_string .= " host={$single_connection['hostname']}"; + } + + if($single_connection['password']) + { + $this->connect_string .= " password={$single_connection['password']}"; + } + $this->$link = @$connect_function($this->connect_string); + + $time_spent = get_execution_time(); + $this->query_time += $time_spent; + + // Successful connection? break down brother! + if($this->$link) + { + $this->connections[] = "[".strtoupper($type)."] {$single_connection['username']}@{$single_connection['hostname']} (Connected in ".format_time_duration($time_spent).")"; + break; + } + else + { + $this->connections[] = "[FAILED] [".strtoupper($type)."] {$single_connection['username']}@{$single_connection['hostname']}"; + } + } + } + + // No write server was specified (simple connection or just multiple servers) - mirror write link + if(!array_key_exists('write', $connections)) + { + $this->write_link = &$this->read_link; + } + + // Have no read connection? + if(!$this->read_link) + { + $this->error("[READ] Unable to connect to PgSQL server"); + return false; + } + // No write? + else if(!$this->write_link) + { + $this->error("[WRITE] Unable to connect to PgSQL server"); + return false; + } + + $this->current_link = &$this->read_link; + return $this->read_link; + } + + /** + * Query the database. + * + * @param string The query SQL. + * @param boolean 1 if hide errors, 0 if not. + * @param integer 1 if executes on slave database, 0 if not. + * @return resource The query data. + */ + function query($string, $hide_errors=0, $write_query=0) + { + global $pagestarttime, $db, $mybb; + + $string = preg_replace("#LIMIT (\s*)([0-9]+),(\s*)([0-9]+)$#im", "LIMIT $4 OFFSET $2", trim($string)); + + $this->last_query = $string; + + get_execution_time(); + + if(strtolower(substr(ltrim($string), 0, 5)) == 'alter') + { + $string = preg_replace("#\sAFTER\s([a-z_]+?)(;*?)$#i", "", $string); + if(strstr($string, 'CHANGE') !== false) + { + $string = str_replace(' CHANGE ', ' ALTER ', $string); + } + } + + if($write_query && $this->write_link) + { + while(pg_connection_busy($this->write_link)); + $this->current_link = &$this->write_link; + pg_send_query($this->current_link, $string); + $query = pg_get_result($this->current_link); + } + else + { + while(pg_connection_busy($this->read_link)); + $this->current_link = &$this->read_link; + pg_send_query($this->current_link, $string); + $query = pg_get_result($this->current_link); + } + + if((pg_result_error($query) && !$hide_errors)) + { + $this->error($string, $query); + exit; + } + + $query_time = get_execution_time(); + $this->query_time += $query_time; + $this->query_count++; + $this->last_result = $query; + + if($mybb->debug_mode) + { + $this->explain_query($string, $query_time); + } + return $query; + } + + /** + * Execute a write query on the slave database + * + * @param string The query SQL. + * @param boolean 1 if hide errors, 0 if not. + * @return resource The query data. + */ + function write_query($query, $hide_errors=0) + { + return $this->query($query, $hide_errors, 1); + } + + /** + * Explain a query on the database. + * + * @param string The query SQL. + * @param string The time it took to perform the query. + */ + function explain_query($string, $qtime) + { + if(preg_match("#^\s*select#i", $string)) + { + $query = pg_query($this->current_link, "EXPLAIN $string"); + $this->explain .= "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n"; + + while($table = pg_fetch_assoc($query)) + { + $this->explain .= + "\n". + "\n". + "\n"; + } + $this->explain .= + "\n". + "\n". + "\n". + "
    #".$this->query_count." - Select Query
    ".htmlspecialchars_uni($string)."
    Info
    ".$table['QUERY PLAN']."
    Query Time: ".format_time_duration($qtime)."
    \n". + "
    \n"; + } + else + { + $this->explain .= "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "
    #".$this->query_count." - Write Query
    ".htmlspecialchars_uni($string)."
    Query Time: ".format_time_duration($qtime)."
    \n". + "
    \n"; + } + + $this->querylist[$this->query_count]['query'] = $string; + $this->querylist[$this->query_count]['time'] = $qtime; + } + + /** + * Return a result array for a query. + * + * @param resource The query ID. + * @param constant The type of array to return. + * @return array The array of results. + */ + function fetch_array($query, $resulttype=PGSQL_ASSOC) + { + switch($resulttype) + { + case PGSQL_NUM: + case PGSQL_BOTH: + break; + default: + $resulttype = PGSQL_ASSOC; + break; + } + + $array = pg_fetch_array($query, NULL, $resulttype); + + return $array; + } + + /** + * Return a specific field from a query. + * + * @param resource The query ID. + * @param string The name of the field to return. + * @param int The number of the row to fetch it from. + */ + function fetch_field($query, $field, $row=false) + { + if($row === false) + { + $array = $this->fetch_array($query); + return $array[$field]; + } + else + { + return pg_fetch_result($query, $row, $field); + } + } + + /** + * Moves internal row pointer to the next row + * + * @param resource The query ID. + * @param int The pointer to move the row to. + */ + function data_seek($query, $row) + { + return pg_result_seek($query, $row); + } + + /** + * Return the number of rows resulting from a query. + * + * @param resource The query ID. + * @return int The number of rows in the result. + */ + function num_rows($query) + { + return pg_num_rows($query); + } + + /** + * Return the last id number of inserted data. + * + * @return int The id number. + */ + function insert_id() + { + $this->last_query = str_replace(array("\r", "\t"), '', $this->last_query); + $this->last_query = str_replace("\n", ' ', $this->last_query); + preg_match('#INSERT INTO ([a-zA-Z0-9_\-]+)#i', $this->last_query, $matches); + + $table = $matches[1]; + + $query = $this->query("SELECT column_name FROM information_schema.constraint_column_usage WHERE table_name = '{$table}' and constraint_name = '{$table}_pkey' LIMIT 1"); + $field = $this->fetch_field($query, 'column_name'); + + // Do we not have a primary field? + if(!$field) + { + return; + } + + $id = $this->write_query("SELECT currval(pg_get_serial_sequence('{$table}', '{$field}')) AS last_value"); + return $this->fetch_field($id, 'last_value'); + } + + /** + * Close the connection with the DBMS. + * + */ + function close() + { + @pg_close($this->read_link); + if($this->write_link) + { + @pg_close($this->write_link); + } + } + + /** + * Return an error number. + * + * @return int The error number of the current error. + */ + function error_number($query="") + { + if(!$query || !function_exists("pg_result_error_field")) + { + return 0; + } + + return pg_result_error_field($query, PGSQL_DIAG_SQLSTATE); + } + + /** + * Return an error string. + * + * @return string The explanation for the current error. + */ + function error_string($query="") + { + if($query) + { + return pg_result_error($query); + } + + if($this->current_link) + { + return pg_last_error($this->current_link); + } + else + { + return pg_last_error(); + } + } + + /** + * Output a database error. + * + * @param string The string to present as an error. + */ + function error($string="", $query="") + { + if($this->error_reporting) + { + if(class_exists("errorHandler")) + { + global $error_handler; + + if(!is_object($error_handler)) + { + require_once MYBB_ROOT."inc/class_error.php"; + $error_handler = new errorHandler(); + } + + $error = array( + "error_no" => $this->error_number($query), + "error" => $this->error_string($query), + "query" => $string + ); + $error_handler->error(MYBB_SQL, $error); + } + else + { + trigger_error("[SQL] [".$this->error_number()."] ".$this->error_string()."
    {$string}", E_USER_ERROR); + } + } + } + + /** + * Returns the number of affected rows in a query. + * + * @return int The number of affected rows. + */ + function affected_rows() + { + return pg_affected_rows($this->last_result); + } + + /** + * Return the number of fields. + * + * @param resource The query ID. + * @return int The number of fields. + */ + function num_fields($query) + { + return pg_num_fields($query); + } + + /** + * Lists all functions in the database. + * + * @param string The database name. + * @param string Prefix of the table (optional) + * @return array The table list. + */ + function list_tables($database, $prefix='') + { + if($prefix) + { + $query = $this->query("SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_name LIKE '".$this->escape_string($prefix)."%'"); + } + else + { + $query = $this->query("SELECT table_name FROM information_schema.tables WHERE table_schema='public'"); + } + + $tables = array(); + while($table = $this->fetch_array($query)) + { + $tables[] = $table['table_name']; + } + + return $tables; + } + + /** + * Check if a table exists in a database. + * + * @param string The table name. + * @return boolean True when exists, false if not. + */ + function table_exists($table) + { + // Execute on master server to ensure if we've just created a table that we get the correct result + $query = $this->write_query("SELECT COUNT(table_name) as table_names FROM information_schema.tables WHERE table_schema = 'public' AND table_name='{$this->table_prefix}{$table}'"); + + $exists = $this->fetch_field($query, 'table_names'); + + if($exists > 0) + { + return true; + } + else + { + return false; + } + } + + /** + * Check if a field exists in a database. + * + * @param string The field name. + * @param string The table name. + * @return boolean True when exists, false if not. + */ + function field_exists($field, $table) + { + $query = $this->write_query("SELECT COUNT(column_name) as column_names FROM information_schema.columns WHERE table_name='{$this->table_prefix}{$table}' AND column_name='{$field}'"); + + $exists = $this->fetch_field($query, "column_names"); + + if($exists > 0) + { + return true; + } + else + { + return false; + } + } + + /** + * Add a shutdown query. + * + * @param resource The query data. + * @param string An optional name for the query. + */ + function shutdown_query($query, $name=0) + { + global $shutdown_queries; + if($name) + { + $shutdown_queries[$name] = $query; + } + else + { + $shutdown_queries[] = $query; + } + } + + /** + * Performs a simple select query. + * + * @param string The table name to be queried. + * @param string Comma delimetered list of fields to be selected. + * @param string SQL formatted list of conditions to be matched. + * @param array List of options: group by, order by, order direction, limit, limit start. + * @return resource The query data. + */ + function simple_select($table, $fields="*", $conditions="", $options=array()) + { + $query = "SELECT ".$fields." FROM ".$this->table_prefix.$table; + if($conditions != "") + { + $query .= " WHERE ".$conditions; + } + + if(isset($options['group_by'])) + { + $query .= " GROUP BY ".$options['group_by']; + } + + if(isset($options['order_by'])) + { + $query .= " ORDER BY ".$options['order_by']; + if(isset($options['order_dir'])) + { + $query .= " ".my_strtoupper($options['order_dir']); + } + } + + if(isset($options['limit_start']) && isset($options['limit'])) + { + $query .= " LIMIT ".$options['limit_start'].", ".$options['limit']; + } + else if(isset($options['limit'])) + { + $query .= " LIMIT ".$options['limit']; + } + + return $this->query($query); + } + + /** + * Build an insert query from an array. + * + * @param string The table name to perform the query on. + * @param array An array of fields and their values. + * @param boolean Whether or not to return an insert id. True by default + * @return int The insert ID if available + */ + function insert_query($table, $array, $insert_id=true) + { + global $mybb; + + if(!is_array($array)) + { + return false; + } + + foreach($array as $field => $value) + { + if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) + { + $array[$field] = $value; + } + else + { + $array[$field] = "'{$value}'"; + } + } + + $fields = implode(",", array_keys($array)); + $values = implode(",", $array); + $this->write_query(" + INSERT + INTO {$this->table_prefix}{$table} (".$fields.") + VALUES (".$values.") + "); + + if($insert_id != false) + { + return $this->insert_id(); + } + else + { + return true; + } + } + + /** + * Build one query for multiple inserts from a multidimensional array. + * + * @param string The table name to perform the query on. + * @param array An array of inserts. + * @return int The insert ID if available + */ + function insert_query_multiple($table, $array) + { + global $mybb; + + if(!is_array($array)) + { + return false; + } + // Field names + $fields = array_keys($array[0]); + $fields = implode(",", $fields); + + $insert_rows = array(); + foreach($array as $values) + { + foreach($values as $field => $value) + { + if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) + { + $values[$field] = $value; + } + else + { + $values[$field] = "'{$value}'"; + } + } + $insert_rows[] = "(".implode(",", $values).")"; + } + $insert_rows = implode(", ", $insert_rows); + + $this->write_query(" + INSERT + INTO {$this->table_prefix}{$table} ({$fields}) + VALUES {$insert_rows} + "); + } + + /** + * Build an update query from an array. + * + * @param string The table name to perform the query on. + * @param array An array of fields and their values. + * @param string An optional where clause for the query. + * @param string An optional limit clause for the query. + * @param boolean An option to quote incoming values of the array. + * @return resource The query data. + */ + function update_query($table, $array, $where="", $limit="", $no_quote=false) + { + global $mybb; + + if(!is_array($array)) + { + return false; + } + + $comma = ""; + $query = ""; + $quote = "'"; + + if($no_quote == true) + { + $quote = ""; + } + + foreach($array as $field => $value) + { + if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) + { + $query .= $comma.$field."={$value}"; + } + else + { + $query .= $comma.$field."={$quote}{$value}{$quote}"; + } + $comma = ', '; + } + if(!empty($where)) + { + $query .= " WHERE $where"; + } + return $this->write_query(" + UPDATE {$this->table_prefix}$table + SET $query + "); + } + + /** + * Build a delete query. + * + * @param string The table name to perform the query on. + * @param string An optional where clause for the query. + * @param string An optional limit clause for the query. + * @return resource The query data. + */ + function delete_query($table, $where="", $limit="") + { + $query = ""; + if(!empty($where)) + { + $query .= " WHERE $where"; + } + + return $this->write_query(" + DELETE + FROM {$this->table_prefix}$table + $query + "); + } + + /** + * Escape a string according to the pg escape format. + * + * @param string The string to be escaped. + * @return string The escaped string. + */ + function escape_string($string) + { + if(function_exists("pg_escape_string")) + { + $string = pg_escape_string($string); + } + else + { + $string = addslashes($string); + } + return $string; + } + + /** + * Frees the resources of a MySQLi query. + * + * @param object The query to destroy. + * @return boolean Returns true on success, false on faliure + */ + function free_result($query) + { + return pg_free_result($query); + } + + /** + * Escape a string used within a like command. + * + * @param string The string to be escaped. + * @return string The escaped string. + */ + function escape_string_like($string) + { + return $this->escape_string(str_replace(array('%', '_') , array('\\%' , '\\_') , $string)); + } + + /** + * Gets the current version of PgSQL. + * + * @return string Version of PgSQL. + */ + function get_version() + { + if($this->version) + { + return $this->version; + } + + $version = pg_version($this->current_link); + + $this->version = $version['server']; + + return $this->version; + } + + /** + * Optimizes a specific table. + * + * @param string The name of the table to be optimized. + */ + function optimize_table($table) + { + $this->write_query("VACUUM ".$this->table_prefix.$table.""); + } + + /** + * Analyzes a specific table. + * + * @param string The name of the table to be analyzed. + */ + function analyze_table($table) + { + $this->write_query("ANALYZE ".$this->table_prefix.$table.""); + } + + /** + * Show the "create table" command for a specific table. + * + * @param string The name of the table. + * @return string The pg command to create the specified table. + */ + function show_create_table($table) + { + $query = $this->write_query(" + SELECT a.attnum, a.attname as field, t.typname as type, a.attlen as length, a.atttypmod as lengthvar, a.attnotnull as notnull + FROM pg_class c + LEFT JOIN pg_attribute a ON (a.attrelid = c.oid) + LEFT JOIN pg_type t ON (a.atttypid = t.oid) + WHERE c.relname = '{$this->table_prefix}{$table}' AND a.attnum > 0 + ORDER BY a.attnum + "); + + $lines = array(); + $table_lines = "CREATE TABLE {$this->table_prefix}{$table} (\n"; + + while($row = $this->fetch_array($query)) + { + // Get the data from the table + $query2 = $this->write_query(" + SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault + FROM pg_attrdef d + LEFT JOIN pg_class c ON (c.oid = d.adrelid) + WHERE c.relname = '{$this->table_prefix}{$table}' AND d.adnum = '{$row['attnum']}' + "); + + if(!$query2) + { + unset($row['rowdefault']); + } + else + { + $row['rowdefault'] = $this->fetch_field($query2, 'rowdefault'); + } + + if($row['type'] == 'bpchar') + { + // Stored in the engine as bpchar, but in the CREATE TABLE statement it's char + $row['type'] = 'char'; + } + + $line = " {$row['field']} {$row['type']}"; + + if(strpos($row['type'], 'char') !== false) + { + if($row['lengthvar'] > 0) + { + $line .= '('.($row['lengthvar'] - 4).')'; + } + } + + if(strpos($row['type'], 'numeric') !== false) + { + $line .= '('.sprintf("%s,%s", (($row['lengthvar'] >> 16) & 0xffff), (($row['lengthvar'] - 4) & 0xffff)).')'; + } + + if(!empty($row['rowdefault'])) + { + $line .= " DEFAULT {$row['rowdefault']}"; + } + + if($row['notnull'] == 't') + { + $line .= ' NOT NULL'; + } + + $lines[] = $line; + } + + // Get the listing of primary keys. + $query = $this->write_query(" + SELECT ic.relname as index_name, bc.relname as tab_name, ta.attname as column_name, i.indisunique as unique_key, i.indisprimary as primary_key + FROM pg_class bc + LEFT JOIN pg_index i ON (bc.oid = i.indrelid) + LEFT JOIN pg_class ic ON (ic.oid = i.indexrelid) + LEFT JOIN pg_attribute ia ON (ia.attrelid = i.indexrelid) + LEFT JOIN pg_attribute ta ON (ta.attrelid = bc.oid AND ta.attrelid = i.indrelid AND ta.attnum = i.indkey[ia.attnum-1]) + WHERE bc.relname = '{$this->table_prefix}{$table}' + ORDER BY index_name, tab_name, column_name + "); + + $primary_key = array(); + + // We do this in two steps. It makes placing the comma easier + while($row = $this->fetch_array($query)) + { + if($row['primary_key'] == 't') + { + $primary_key[] = $row['column_name']; + $primary_key_name = $row['index_name']; + } + } + + if(!empty($primary_key)) + { + $lines[] = " CONSTRAINT $primary_key_name PRIMARY KEY (".implode(', ', $primary_key).")"; + } + + $table_lines .= implode(", \n", $lines); + $table_lines .= "\n)\n"; + + return $table_lines; + } + + /** + * Show the "show fields from" command for a specific table. + * + * @param string The name of the table. + * @return string Field info for that table + */ + function show_fields_from($table) + { + $query = $this->write_query("SELECT column_name FROM information_schema.constraint_column_usage WHERE table_name = '{$this->table_prefix}{$table}' and constraint_name = '{$this->table_prefix}{$table}_pkey' LIMIT 1"); + $primary_key = $this->fetch_field($query, 'column_name'); + + $query = $this->write_query(" + SELECT column_name as Field, data_type as Extra + FROM information_schema.columns + WHERE table_name = '{$this->table_prefix}{$table}' + "); + while($field = $this->fetch_array($query)) + { + if($field['field'] == $primary_key) + { + $field['extra'] = 'auto_increment'; + } + + $field_info[] = array('Extra' => $field['extra'], 'Field' => $field['field']); + } + + return $field_info; + } + + /** + * Returns whether or not the table contains a fulltext index. + * + * @param string The name of the table. + * @param string Optionally specify the name of the index. + * @return boolean True or false if the table has a fulltext index or not. + */ + function is_fulltext($table, $index="") + { + return false; + } + + /** + * Returns whether or not this database engine supports fulltext indexing. + * + * @param string The table to be checked. + * @return boolean True or false if supported or not. + */ + + function supports_fulltext($table) + { + return false; + } + + /** + * Returns whether or not this database engine supports boolean fulltext matching. + * + * @param string The table to be checked. + * @return boolean True or false if supported or not. + */ + function supports_fulltext_boolean($table) + { + return false; + } + + /** + * Creates a fulltext index on the specified column in the specified table with optional index name. + * + * @param string The name of the table. + * @param string Name of the column to be indexed. + * @param string The index name, optional. + */ + function create_fulltext_index($table, $column, $name="") + { + return false; + } + + /** + * Drop an index with the specified name from the specified table + * + * @param string The name of the table. + * @param string The name of the index. + */ + function drop_index($table, $name) + { + $this->write_query(" + ALTER TABLE {$this->table_prefix}$table + DROP INDEX $name + "); + } + + /** + * Checks to see if an index exists on a specified table + * + * @param string The name of the table. + * @param string The name of the index. + */ + function index_exists($table, $index) + { + $err = $this->error_reporting; + $this->error_reporting = 0; + + $query = $this->write_query("SELECT * FROM pg_indexes WHERE tablename='".$this->escape_string($this->table_prefix.$table)."'"); + + $exists = $this->fetch_field($query, $index); + $this->error_reporting = $err; + + if($exists) + { + return true; + } + else + { + return false; + } + } + + /** + * Drop an table with the specified table + * + * @param string The name of the table. + * @param boolean hard drop - no checking + * @param boolean use table prefix + */ + function drop_table($table, $hard=false, $table_prefix=true) + { + if($table_prefix == false) + { + $table_prefix = ""; + } + else + { + $table_prefix = $this->table_prefix; + } + + if($hard == false) + { + if($this->table_exists($table)) + { + $this->write_query('DROP TABLE '.$table_prefix.$table); + } + } + else + { + $this->write_query('DROP TABLE '.$table_prefix.$table); + } + + $query = $this->query("SELECT column_name FROM information_schema.constraint_column_usage WHERE table_name = '{$table}' and constraint_name = '{$table}_pkey' LIMIT 1"); + $field = $this->fetch_field($query, 'column_name'); + + // Do we not have a primary field? + if($field) + { + $this->write_query('DROP SEQUENCE {$table}_{$field}_id_seq'); + } + } + + /** + * Renames a table + * + * @param string The old table name + * @param string the new table name + * @param boolean use table prefix + */ + function rename_table($old_table, $new_table, $table_prefix=true) + { + if($table_prefix == false) + { + $table_prefix = ""; + } + else + { + $table_prefix = $this->table_prefix; + } + + return $this->write_query("ALTER TABLE {$table_prefix}{$old_table} RENAME TO {$table_prefix}{$new_table}"); + } + + /** + * Replace contents of table with values + * + * @param string The table + * @param array The replacements + * @param mixed The default field(s) + * @param boolean Whether or not to return an insert id. True by default + */ + function replace_query($table, $replacements=array(), $default_field="", $insert_id=true) + { + global $mybb; + + if($default_field == "") + { + $query = $this->write_query("SELECT column_name FROM information_schema.constraint_column_usage WHERE table_name = '{$this->table_prefix}{$table}' and constraint_name = '{$this->table_prefix}{$table}_pkey' LIMIT 1"); + $main_field = $this->fetch_field($query, 'column_name'); + } + else + { + $main_field = $default_field; + } + + $update = false; + if(is_array($main_field) && !empty($main_field)) + { + $search_bit = array(); + $string = ''; + foreach($main_field as $field) + { + if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) + { + $search_bit[] = "{$field} = ".$replacements[$field]; + } + else + { + $search_bit[] = "{$field} = '".$replacements[$field]."'"; + } + } + + $search_bit = implode(" AND ", $search_bit); + $query = $this->write_query("SELECT COUNT(".$main_field[0].") as count FROM {$this->table_prefix}{$table} WHERE {$search_bit} LIMIT 1"); + if($this->fetch_field($query, "count") == 1) + { + $update = true; + } + } + else + { + $query = $this->write_query("SELECT {$main_field} FROM {$this->table_prefix}{$table}"); + + while($column = $this->fetch_array($query)) + { + if($column[$main_field] == $replacements[$main_field]) + { + $update = true; + break; + } + } + } + + if($update === true) + { + if(is_array($main_field)) + { + return $this->update_query($table, $replacements, $search_bit); + } + else + { + return $this->update_query($table, $replacements, "{$main_field}='".$replacements[$main_field]."'"); + } + } + else + { + return $this->insert_query($table, $replacements, $insert_id); + } + } + + function build_fields_string($table, $append="") + { + $fields = $this->show_fields_from($table); + $comma = ''; + + foreach($fields as $key => $field) + { + $fieldstring .= $comma.$append.$field['Field']; + $comma = ','; + } + + return $fieldstring; + } + + /** + * Drops a column + * + * @param string The table + * @param string The column name + */ + function drop_column($table, $column) + { + return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} DROP {$column}"); + } + + /** + * Adds a column + * + * @param string The table + * @param string The column name + * @param string the new column definition + */ + function add_column($table, $column, $definition) + { + return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ADD {$column} {$definition}"); + } + + /** + * Modifies a column + * + * @param string The table + * @param string The column name + * @param string the new column definition + * @param boolean Whether to drop or set a column + * @param boolean The new default value (if one is to be set) + */ + function modify_column($table, $column, $new_definition, $new_not_null=false, $new_default_value=false) + { + $result1 = $result2 = $result3 = true; + + if($new_definition !== false) + { + $result1 = $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ALTER COLUMN {$column} TYPE {$new_definition}"); + } + + if($new_not_null !== false) + { + $set_drop = "DROP"; + + if(strtolower($new_not_null) == "set") + { + $set_drop = "SET"; + } + + $result2 = $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ALTER COLUMN {$column} {$set_drop} NOT NULL"); + } + + if($new_default_value !== false) + { + $result3 = $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ALTER COLUMN {$column} SET DEFAULT {$new_default_value}"); + } + else + { + $result3 = $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ALTER COLUMN {$column} DROP DEFAULT"); + } + + return $result1 && $result2 && $result3; + } + + /** + * Renames a column + * + * @param string The table + * @param string The old column name + * @param string the new column name + * @param string the new column definition + * @param boolean Whether to drop or set a column + * @param boolean The new default value (if one is to be set) + */ + function rename_column($table, $old_column, $new_column, $new_definition, $new_not_null=false, $new_default_value=false) + { + $result1 = $this->write_query("ALTER TABLE {$this->table_prefix}{$table} RENAME COLUMN {$old_column} TO {$new_column}"); + $result2 = $this->modify_column($table, $new_column, $new_definition, $new_not_null, $new_default_value); + return ($result1 && $result2); + } + + /** + * Sets the table prefix used by the simple select, insert, update and delete functions + * + * @param string The new table prefix + */ + function set_table_prefix($prefix) + { + $this->table_prefix = $prefix; + } + + /** + * Fetched the total size of all mysql tables or a specific table + * + * @param string The table (optional) + * @return integer the total size of all mysql tables or a specific table + */ + function fetch_size($table='') + { + if($table != '') + { + $query = $this->query("SELECT reltuples, relpages FROM pg_class WHERE relname = '".$this->table_prefix.$table."'"); + } + else + { + $query = $this->query("SELECT reltuples, relpages FROM pg_class"); + } + $total = 0; + while($table = $this->fetch_array($query)) + { + $total += $table['relpages']+$table['reltuples']; + } + return $total; + } + + /** + * Fetch a list of database character sets this DBMS supports + * + * @return array Array of supported character sets with array key being the name, array value being display name. False if unsupported + */ + function fetch_db_charsets() + { + return false; + } + + /** + * Fetch a database collation for a particular database character set + * + * @param string The database character set + * @return string The matching database collation, false if unsupported + */ + function fetch_charset_collation($charset) + { + return false; + } + + /** + * Fetch a character set/collation string for use with CREATE TABLE statements. Uses current DB encoding + * + * @return string The built string, empty if unsupported + */ + function build_create_table_collation() + { + return ''; + } + + /** + * Time how long it takes for a particular piece of code to run. Place calls above & below the block of code. + * + * @deprecated + */ + function get_execution_time() + { + return get_execution_time(); + } + + /** + * Binary database fields require special attention. + * + * @param string Binary value + * @return string Encoded binary value + */ + function escape_binary($string) + { + return "'".pg_escape_bytea($string)."'"; + } + + /** + * Unescape binary data. + * + * @param string Binary value + * @return string Encoded binary value + */ + function unescape_binary($string) + { + // hex format + if(substr($string, 0, 2) == '\x') + { + return pack('H*', substr($string, 2)); + } + // escape format + else + { + return pg_unescape_bytea($string); + } + } +} + diff --git a/Upload/inc/db_sqlite.php b/Upload/inc/db_sqlite.php new file mode 100644 index 0000000..eac9135 --- /dev/null +++ b/Upload/inc/db_sqlite.php @@ -0,0 +1,1460 @@ +db = new dbpdoEngine("sqlite:{$config['database']}"); + + $query_time = get_execution_time(); + + $this->query_time += $query_time; + + $this->connections[] = "[WRITE] {$config['database']} (Connected in ".format_time_duration($query_time).")"; + + if($this->db) + { + $this->query('PRAGMA short_column_names = 1'); + return true; + } + else + { + return false; + } + } + + /** + * Query the database. + * + * @param string The query SQL. + * @param boolean 1 if hide errors, 0 if not. + * @return resource The query data. + */ + function query($string, $hide_errors=0) + { + global $pagestarttime, $db, $mybb; + + get_execution_time(); + + if(strtolower(substr(ltrim($string), 0, 5)) == 'alter') + { + $string = preg_replace("#\sAFTER\s([a-z_]+?)(;*?)$#i", "", $string); + + $queryparts = preg_split("/[\s]+/", $string, 4, PREG_SPLIT_NO_EMPTY); + $tablename = $queryparts[2]; + $alterdefs = $queryparts[3]; + if(strtolower($queryparts[1]) != 'table' || $queryparts[2] == '') + { + $this->error_msg = "near \"{$queryparts[0]}\": syntax error"; + } + else + { + // SQLITE 3 supports ADD and RENAME TO alter statements + if(strtolower(substr(ltrim($alterdefs), 0, 3)) == 'add' || strtolower(substr(ltrim($alterdefs), 0, 9)) == "rename to") + { + $query = $this->db->query($string); + $query->closeCursor(); + } + else + { + $query = $this->alter_table_parse($tablename, $alterdefs, $string); + } + } + } + else + { + try + { + $query = $this->db->query($string); + } + catch(PDOException $exception) + { + $error = array( + "message" => $exception->getMessage(), + "code" => $exception->getCode() + ); + + $this->error($error['message'], $error['code']); + } + } + + if($this->error_number($query) > 0 && !$hide_errors) + { + $this->error($string, $query); + exit; + } + + $query_time = get_execution_time(); + $this->query_time += $query_time; + $this->query_count++; + + if($mybb->debug_mode) + { + $this->explain_query($string, $query_time); + } + + if(strtolower(substr(ltrim($string), 0, 6)) == "create") + { + $query->closeCursor(); + return; + } + + return $query; + } + + /** + * Explain a query on the database. + * + * @param string The query SQL. + * @param string The time it took to perform the query. + */ + function explain_query($string, $qtime) + { + if(preg_match("#^\s*select#i", $string)) + { + $this->explain .= "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "
    #".$this->query_count." - Select Query
    ".htmlspecialchars_uni($string)."
    Query Time: ".format_time_duration($qtime)."
    \n". + "
    \n"; + } + else + { + $this->explain .= "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "\n". + "
    #".$this->query_count." - Write Query
    ".htmlspecialchars_uni($string)."
    Query Time: ".format_time_duration($qtime)."
    \n". + "
    \n"; + } + + $this->querylist[$this->query_count]['query'] = $string; + $this->querylist[$this->query_count]['time'] = $qtime; + } + + /** + * Execute a write query on the database + * + * @param string The query SQL. + * @param boolean 1 if hide errors, 0 if not. + * @return resource The query data. + */ + function write_query($query, $hide_errors=0) + { + return $this->query($query, $hide_errors); + } + + /** + * Return a result array for a query. + * + * @param resource The result data. + * @param constant The type of array to return. + * @return array The array of results. + */ + function fetch_array($query) + { + $array = $this->db->fetch_array($query); + return $array; + } + + /** + * Return a specific field from a query. + * + * @param resource The query ID. + * @param string The name of the field to return. + * @param int The number of the row to fetch it from. + */ + function fetch_field($query, $field, $row=false) + { + if($row !== false) + { + $this->data_seek($query, $row); + } + $array = $this->fetch_array($query); + return $array[$field]; + } + + /** + * Moves internal row pointer to the next row + * + * @param resource The query ID. + * @param int The pointer to move the row to. + */ + function data_seek($query, $row) + { + return $this->db->seek($query, $row); + } + + /** + * Return the number of rows resulting from a query. + * + * @param resource The query data. + * @return int The number of rows in the result. + */ + function num_rows($query) + { + return $this->db->num_rows($query); + } + + /** + * Return the last id number of inserted data. + * + * @return int The id number. + */ + function insert_id($name="") + { + return $this->db->insert_id($name); + } + + /** + * Close the connection with the DBMS. + * + */ + function close() + { + return; + } + + /** + * Return an error number. + * + * @return int The error number of the current error. + */ + function error_number($query="") + { + if(!$query) + { + $query = $this->db->last_query; + } + + $this->error_number = $this->db->error_number($query); + + return $this->error_number; + } + + /** + * Return an error string. + * + * @return string The explanation for the current error. + */ + function error_string($query="") + { + if($this->error_number != "") + { + if(!$query) + { + $query = $this->db->last_query; + } + + $error_string = $this->db->error_string($query); + $this->error_number = ""; + + return $error_string; + } + } + + /** + * Output a database error. + * + * @param string The string to present as an error. + */ + function error($string="", $query="", $error="", $error_no="") + { + $this->db->roll_back(); + + if($this->error_reporting) + { + if(!$query) + { + $query = $this->db->last_query; + } + + if($error_no == "") + { + $error_no = $this->error_number($query); + } + + if($error == "") + { + $error = $this->error_string($query); + } + + if(class_exists("errorHandler")) + { + global $error_handler; + + if(!is_object($error_handler)) + { + require_once MYBB_ROOT."inc/class_error.php"; + $error_handler = new errorHandler(); + } + + $error = array( + "error_no" => $error_no, + "error" => $error, + "query" => $string + ); + $error_handler->error(MYBB_SQL, $error); + } + else + { + trigger_error("[SQL] [{$error_no}] {$error}
    {$string}", E_USER_ERROR); + } + } + } + + /** + * Returns the number of affected rows in a query. + * + * @return int The number of affected rows. + */ + function affected_rows($query="") + { + if(!$query) + { + $query = $this->db->last_query; + } + + return $this->db->affected_rows($query); + } + + /** + * Return the number of fields. + * + * @param resource The query data. + * @return int The number of fields. + */ + function num_fields($query) + { + if(!$query) + { + $query = $this->db->last_query; + } + + return $this->db->num_fields($query); + } + + /** + * Lists all functions in the database. + * + * @param string The database name. + * @param string Prefix of the table (optional) + * @return array The table list. + */ + function list_tables($database, $prefix='') + { + if($prefix) + { + $query = $this->query("SELECT tbl_name FROM sqlite_master WHERE type = 'table' AND tbl_name LIKE '".$this->escape_string($prefix)."%'"); + } + else + { + $query = $this->query("SELECT tbl_name FROM sqlite_master WHERE type = 'table'"); + } + + $tables = array(); + while($table = $this->fetch_array($query)) + { + $tables[] = $table['tbl_name']; + } + $query->closeCursor(); + return $tables; + } + + /** + * Check if a table exists in a database. + * + * @param string The table name. + * @return boolean True when exists, false if not. + */ + function table_exists($table) + { + $query = $this->query("SELECT COUNT(name) as count FROM sqlite_master WHERE type='table' AND name='{$this->table_prefix}{$table}'"); + $exists = $this->fetch_field($query, "count"); + $query->closeCursor(); + + if($exists > 0) + { + return true; + } + else + { + return false; + } + } + + /** + * Check if a field exists in a database. + * + * @param string The field name. + * @param string The table name. + * @return boolean True when exists, false if not. + */ + function field_exists($field, $table) + { + $query = $this->query("PRAGMA table_info('{$this->table_prefix}{$table}')"); + + $exists = 0; + + while($row = $this->fetch_array($query)) + { + if($row['name'] == $field) + { + ++$exists; + } + } + + $query->closeCursor(); + + if($exists > 0) + { + return true; + } + else + { + return false; + } + } + + /** + * Add a shutdown query. + * + * @param resource The query data. + * @param string An optional name for the query. + */ + function shutdown_query($query, $name=0) + { + global $shutdown_queries; + if($name) + { + $shutdown_queries[$name] = $query; + } + else + { + $shutdown_queries[] = $query; + } + } + + /** + * Performs a simple select query. + * + * @param string The table name to be queried. + * @param string Comma delimetered list of fields to be selected. + * @param string SQL formatted list of conditions to be matched. + * @param array List of options: group by, order by, order direction, limit, limit start. + * @return resource The query data. + */ + function simple_select($table, $fields="*", $conditions="", $options=array()) + { + $query = "SELECT ".$fields." FROM ".$this->table_prefix.$table; + + if($conditions != "") + { + $query .= " WHERE ".$conditions; + } + + if(isset($options['group_by'])) + { + $query .= " GROUP BY ".$options['group_by']; + } + + if(isset($options['order_by'])) + { + $query .= " ORDER BY ".$options['order_by']; + + if(isset($options['order_dir'])) + { + $query .= " ".strtoupper($options['order_dir']); + } + } + + if(isset($options['limit_start']) && isset($options['limit'])) + { + $query .= " LIMIT ".$options['limit_start'].", ".$options['limit']; + } + else if(isset($options['limit'])) + { + $query .= " LIMIT ".$options['limit']; + } + + return $this->query($query); + } + + /** + * Build an insert query from an array. + * + * @param string The table name to perform the query on. + * @param array An array of fields and their values. + * @return int The insert ID if available + */ + function insert_query($table, $array) + { + global $mybb; + + if(!is_array($array)) + { + return false; + } + + foreach($array as $field => $value) + { + if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) + { + if($value[0] != 'X') // Not escaped? + { + $value = $this->escape_binary($value); + } + + $array[$field] = $value; + } + else + { + $array[$field] = "'{$value}'"; + } + } + + $fields = implode(",", array_keys($array)); + $values = implode(",", $array); + $query = $this->write_query(" + INSERT + INTO {$this->table_prefix}{$table} (".$fields.") + VALUES (".$values.") + "); + $query->closeCursor(); + return $this->insert_id(); + } + + /** + * Build one query for multiple inserts from a multidimensional array. + * + * @param string The table name to perform the query on. + * @param array An array of inserts. + * @return int The insert ID if available + */ + function insert_query_multiple($table, $array) + { + global $mybb; + + if(!is_array($array)) + { + return false; + } + // Field names + $fields = array_keys($array[0]); + $fields = implode(",", $fields); + + $insert_rows = array(); + foreach($array as $values) + { + foreach($values as $field => $value) + { + if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) + { + if($value[0] != 'X') // Not escaped? + { + $value = $this->escape_binary($value); + } + + $values[$field] = $value; + } + else + { + $values[$field] = "'{$value}'"; + } + } + $insert_rows[] = "(".implode(",", $values).")"; + } + $insert_rows = implode(", ", $insert_rows); + + $query = $this->write_query(" + INSERT + INTO {$this->table_prefix}{$table} ({$fields}) + VALUES {$insert_rows} + "); + $query->closeCursor(); + } + + /** + * Build an update query from an array. + * + * @param string The table name to perform the query on. + * @param array An array of fields and their values. + * @param string An optional where clause for the query. + * @param string An optional limit clause for the query. + * @param boolean An option to quote incoming values of the array. + * @return resource The query data. + */ + function update_query($table, $array, $where="", $limit="", $no_quote=false) + { + global $mybb; + + if(!is_array($array)) + { + return false; + } + + $comma = ""; + $query = ""; + $quote = "'"; + + if($no_quote == true) + { + $quote = ""; + } + + foreach($array as $field => $value) + { + if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) + { + if($value[0] != 'X') // Not escaped? + { + $value = $this->escape_binary($value); + } + + $query .= $comma.$field."=".$value; + } + else + { + $query .= $comma.$field."={$quote}".$value."{$quote}"; + } + $comma = ', '; + } + + if(!empty($where)) + { + $query .= " WHERE $where"; + } + + $query = $this->query("UPDATE {$this->table_prefix}$table SET $query"); + $query->closeCursor(); + return $query; + } + + /** + * Build a delete query. + * + * @param string The table name to perform the query on. + * @param string An optional where clause for the query. + * @param string An optional limit clause for the query. + * @return resource The query data. + */ + function delete_query($table, $where="", $limit="") + { + $query = ""; + if(!empty($where)) + { + $query .= " WHERE $where"; + } + + $query = $this->query("DELETE FROM {$this->table_prefix}$table $query"); + $query->closeCursor(); + return $query; + } + + /** + * Escape a string + * + * @param string The string to be escaped. + * @return string The escaped string. + */ + function escape_string($string) + { + $string = $this->db->escape_string($string); + return $string; + } + + /** + * Serves no purposes except compatibility + * + */ + function free_result($query) + { + return; + } + + /** + * Escape a string used within a like command. + * + * @param string The string to be escaped. + * @return string The escaped string. + */ + function escape_string_like($string) + { + return $this->escape_string(str_replace(array('%', '_') , array('\\%' , '\\_') , $string)); + } + + /** + * Gets the current version of SQLLite. + * + * @return string Version of MySQL. + */ + function get_version() + { + if($this->version) + { + return $this->version; + } + $this->version = $this->db->get_attribute("ATTR_SERVER_VERSION"); + + return $this->version; + } + + /** + * Optimizes a specific table. + * + * @param string The name of the table to be optimized. + */ + function optimize_table($table) + { + $query = $this->query("VACUUM ".$this->table_prefix.$table.""); + $query->closeCursor(); + } + + /** + * Analyzes a specific table. + * + * @param string The name of the table to be analyzed. + */ + function analyze_table($table) + { + $query = $this->query("ANALYZE ".$this->table_prefix.$table.""); + $query->closeCursor(); + } + + /** + * Show the "create table" command for a specific table. + * + * @param string The name of the table. + * @return string The MySQL command to create the specified table. + */ + function show_create_table($table) + { + $old_tbl_prefix = $this->table_prefix; + $this->set_table_prefix(""); + $query = $this->simple_select("sqlite_master", "sql", "type = 'table' AND name = '{$old_tbl_prefix}{$table}' ORDER BY type DESC, name"); + $this->set_table_prefix($old_tbl_prefix); + + $result = $this->fetch_field($query, 'sql'); + + $query->closeCursor(); + + return $result; + } + + /** + * Show the "show fields from" command for a specific table. + * + * @param string The name of the table. + * @return string Field info for that table + */ + function show_fields_from($table) + { + $old_tbl_prefix = $this->table_prefix; + $this->set_table_prefix(""); + $query = $this->simple_select("sqlite_master", "sql", "type = 'table' AND name = '{$old_tbl_prefix}{$table}'"); + $this->set_table_prefix($old_tbl_prefix); + $table = trim(preg_replace('#CREATE\s+TABLE\s+"?'.$this->table_prefix.$table.'"?#i', '', $this->fetch_field($query, "sql"))); + $query->closeCursor(); + + preg_match('#\((.*)\)#s', $table, $matches); + + $field_info = array(); + $table_cols = explode(',', trim($matches[1])); + foreach($table_cols as $declaration) + { + $entities = preg_split('#\s+#', trim($declaration)); + $column_name = preg_replace('/"?([^"]+)"?/', '\1', $entities[0]); + + $field_info[] = array('Extra' => $entities[1], 'Field' => $column_name); + } + + return $field_info; + } + + /** + * Returns whether or not the table contains a fulltext index. + * + * @param string The name of the table. + * @param string Optionally specify the name of the index. + * @return boolean True or false if the table has a fulltext index or not. + */ + function is_fulltext($table, $index="") + { + return false; + } + + /** + * Returns whether or not this database engine supports fulltext indexing. + * + * @param string The table to be checked. + * @return boolean True or false if supported or not. + */ + + function supports_fulltext($table) + { + return false; + } + + /** + * Returns whether or not this database engine supports boolean fulltext matching. + * + * @param string The table to be checked. + * @return boolean True or false if supported or not. + */ + function supports_fulltext_boolean($table) + { + return false; + } + + /** + * Creates a fulltext index on the specified column in the specified table with optional index name. + * + * @param string The name of the table. + * @param string Name of the column to be indexed. + * @param string The index name, optional. + */ + function create_fulltext_index($table, $column, $name="") + { + return false; + } + + /** + * Drop an index with the specified name from the specified table + * + * @param string The name of the table. + * @param string The name of the index. + */ + function drop_index($table, $name) + { + $query = $this->query("ALTER TABLE {$this->table_prefix}$table DROP INDEX $name"); + $query->closeCursor(); + } + + /** + * Checks to see if an index exists on a specified table + * + * @param string The name of the table. + * @param string The name of the index. + */ + function index_exists($table, $index) + { + return false; + } + + /** + * Drop an table with the specified table + * + * @param string The name of the table. + * @param boolean hard drop - no checking + * @param boolean use table prefix + */ + function drop_table($table, $hard=false, $table_prefix=true) + { + if($table_prefix == false) + { + $table_prefix = ""; + } + else + { + $table_prefix = $this->table_prefix; + } + + if($hard == false) + { + if($this->table_exists($table)) + { + $query = $this->query('DROP TABLE '.$table_prefix.$table); + } + } + else + { + $query = $this->query('DROP TABLE '.$table_prefix.$table); + } + + if(isset($query)) + { + $query->closeCursor(); + } + } + + /** + * Renames a table + * + * @param string The old table name + * @param string the new table name + * @param boolean use table prefix + */ + function rename_table($old_table, $new_table, $table_prefix=true) + { + if($table_prefix == false) + { + $table_prefix = ""; + } + else + { + $table_prefix = $this->table_prefix; + } + + $query = $this->write_query("ALTER TABLE {$table_prefix}{$old_table} RENAME TO {$table_prefix}{$new_table}"); + $query->closeCursor(); + return $query; + } + + /** + * Replace contents of table with values + * + * @param string The table + * @param array The replacements + * @param mixed The default field(s) + * @param boolean Whether or not to return an insert id. True by default + */ + function replace_query($table, $replacements=array(), $default_field="", $insert_id=true) + { + global $mybb; + + $columns = ''; + $values = ''; + $comma = ''; + foreach($replacements as $column => $value) + { + $columns .= $comma.$column; + if(isset($mybb->binary_fields[$table][$column]) && $mybb->binary_fields[$table][$column]) + { + if($value[0] != 'X') // Not escaped? + { + $value = $this->escape_binary($value); + } + + $values .= $comma.$value; + } + else + { + $values .= $comma."'".$value."'"; + } + + $comma = ','; + } + + if(empty($columns) || empty($values)) + { + return false; + } + + if($default_field == "") + { + $query = $this->query("REPLACE INTO {$this->table_prefix}{$table} ({$columns}) VALUES({$values})"); + $query->closeCursor(); + return $query; + } + else + { + $update = false; + if(is_array($default_field) && !empty($default_field)) + { + $search_bit = array(); + foreach($default_field as $field) + { + $search_bit[] = "{$field} = '".$replacements[$field]."'"; + } + + $search_bit = implode(" AND ", $search_bit); + $query = $this->write_query("SELECT COUNT(".$default_field[0].") as count FROM {$this->table_prefix}{$table} WHERE {$search_bit} LIMIT 1"); + if($this->fetch_field($query, "count") == 1) + { + $update = true; + } + } + else + { + $query = $this->write_query("SELECT {$default_field} FROM {$this->table_prefix}{$table}"); + $search_bit = "{$default_field}='".$replacements[$default_field]."'"; + + while($column = $this->fetch_array($query)) + { + if($column[$default_field] == $replacements[$default_field]) + { + $update = true; + break; + } + } + } + + if($update === true) + { + return $this->update_query($table, $replacements, $search_bit); + } + else + { + return $this->insert_query($table, $replacements, $insert_id); + } + } + } + + /** + * Sets the table prefix used by the simple select, insert, update and delete functions + * + * @param string The new table prefix + */ + function set_table_prefix($prefix) + { + $this->table_prefix = $prefix; + } + + /** + * Fetched the total size of all mysql tables or a specific table + * + * @param string The table (optional) (ignored) + * @return integer the total size of all mysql tables or a specific table + */ + function fetch_size($table='') + { + global $config, $lang; + + $total = @filesize($config['database']['database']); + if(!$total || $table != '') + { + $total = $lang->na; + } + return $total; + } + + /** + * Perform an "Alter Table" query in SQLite < 3.2.0 - Code taken from http://code.jenseng.com/db/ + * + * @param string The table (optional) + * @return integer the total size of all mysql tables or a specific table + */ + function alter_table_parse($table, $alterdefs, $fullquery="") + { + if(!$fullquery) + { + $fullquery = " ... {$alterdefs}"; + } + + if(!defined("TIME_NOW")) + { + define("TIME_NOW", time()); + } + + if($alterdefs != '') + { + $result = $this->query("SELECT sql,name,type FROM sqlite_master WHERE tbl_name = '{$table}' ORDER BY type DESC"); + if($this->num_rows($result) > 0) + { + $row = $this->fetch_array($result); // Table sql + $result->closeCursor(); + $tmpname = 't'.TIME_NOW; + $origsql = trim(preg_replace("/[\s]+/", " ", str_replace(",", ", ", preg_replace("/[\(]/","( ", $row['sql'], 1)))); + $createtemptableSQL = 'CREATE TEMPORARY '.substr(trim(preg_replace("'".$table."'", $tmpname, $origsql, 1)), 6); + $createindexsql = array(); + $i = 0; + $defs = preg_split("/[,]+/", $alterdefs, -1, PREG_SPLIT_NO_EMPTY); + $prevword = $table; + $oldcols = preg_split("/[,]+/", substr(trim($createtemptableSQL), strpos(trim($createtemptableSQL), '(')+1), -1, PREG_SPLIT_NO_EMPTY); + $newcols = array(); + + for($i = 0; $i < sizeof($oldcols); $i++) + { + $colparts = preg_split("/[\s]+/", $oldcols[$i], -1, PREG_SPLIT_NO_EMPTY); + $oldcols[$i] = $colparts[0]; + $newcols[$colparts[0]] = $colparts[0]; + } + + $newcolumns = ''; + $oldcolumns = ''; + reset($newcols); + + foreach($newcols as $key => $val) + { + $newcolumns .= ($newcolumns ? ', ' : '').$val; + $oldcolumns .= ($oldcolumns ? ', ' : '').$key; + } + + $copytotempsql = 'INSERT INTO '.$tmpname.'('.$newcolumns.') SELECT '.$oldcolumns.' FROM '.$table; + $dropoldsql = 'DROP TABLE '.$table; + $createtesttableSQL = $createtemptableSQL; + + foreach($defs as $def) + { + $defparts = preg_split("/[\s]+/", $def, -1, PREG_SPLIT_NO_EMPTY); + $action = strtolower($defparts[0]); + + switch($action) + { + case 'change': + if(sizeof($defparts) <= 3) + { + $this->error($alterdefs, 'near "'.$defparts[0].($defparts[1] ? ' '.$defparts[1] : '').($defparts[2] ? ' '.$defparts[2] : '').'": syntax error', E_USER_WARNING); + return false; + } + + if($severpos = strpos($createtesttableSQL, ' '.$defparts[1].' ')) + { + if($newcols[$defparts[1]] != $defparts[1]) + { + $this->error($alterdefs, 'unknown column "'.$defparts[1].'" in "'.$table.'"'); + return false; + } + + $newcols[$defparts[1]] = $defparts[2]; + $nextcommapos = strpos($createtesttableSQL, ',', $severpos); + $insertval = ''; + + for($i = 2; $i < sizeof($defparts); $i++) + { + $insertval .= ' '.$defparts[$i]; + } + + if($nextcommapos) + { + $createtesttableSQL = substr($createtesttableSQL, 0, $severpos).$insertval.substr($createtesttableSQL, $nextcommapos); + } + else + { + $createtesttableSQL = substr($createtesttableSQL, 0, $severpos-(strpos($createtesttableSQL, ',') ? 0 : 1)).$insertval.')'; + } + } + else + { + $this->error($fullquery, 'unknown column "'.$defparts[1].'" in "'.$table.'"', E_USER_WARNING); + return false; + } + break; + case 'drop': + if(sizeof($defparts) < 2) + { + $this->error($fullquery, 'near "'.$defparts[0].($defparts[1] ? ' '.$defparts[1] : '').'": syntax error'); + return false; + } + + if($severpos = strpos($createtesttableSQL, ' '.$defparts[1].' ')) + { + $nextcommapos = strpos($createtesttableSQL, ',', $severpos); + + if($nextcommapos) + { + $createtesttableSQL = substr($createtesttableSQL, 0, $severpos).substr($createtesttableSQL, $nextcommapos + 1); + } + else + { + $createtesttableSQL = substr($createtesttableSQL, 0, $severpos-(strpos($createtesttableSQL, ',') ? 0 : 1) - 1).')'; + } + + unset($newcols[$defparts[1]]); + } + else + { + $this->error($fullquery, 'unknown column "'.$defparts[1].'" in "'.$table.'"'); + return false; + } + break; + default: + $this->error($fullquery, 'near "'.$prevword.'": syntax error'); + return false; + } + + $prevword = $defparts[sizeof($defparts)-1]; + } + + // This block of code generates a test table simply to verify that the columns specifed are valid in an sql statement + // This ensures that no reserved words are used as columns, for example + $this->query($createtesttableSQL); + + $droptempsql = 'DROP TABLE '.$tmpname; + $query = $this->query($droptempsql, 0); + if($query === false) + { + return false; + } + $query->closeCursor(); + // End block + + + $createnewtableSQL = 'CREATE '.substr(trim(preg_replace("'{$tmpname}'", $table, $createtesttableSQL, 1)), 17); + $newcolumns = ''; + $oldcolumns = ''; + reset($newcols); + + foreach($newcols as $key => $val) + { + $newcolumns .= ($newcolumns ? ', ' : '').$val; + $oldcolumns .= ($oldcolumns ? ', ' : '').$key; + } + + $copytonewsql = 'INSERT INTO '.$table.'('.$newcolumns.') SELECT '.$oldcolumns.' FROM '.$tmpname; + + + $this->query($createtemptableSQL); // Create temp table + $query = $this->query($copytotempsql); // Copy to table + $query->closeCursor(); + $query = $this->query($dropoldsql); // Drop old table + $query->closeCursor(); + + $this->query($createnewtableSQL); // Recreate original table + $query = $this->query($copytonewsql); // Copy back to original table + $query->closeCursor(); + $query = $this->query($droptempsql); // Drop temp table + $query->closeCursor(); + } + else + { + $this->error($fullquery, 'no such table: '.$table); + return false; + } + return true; + } + } + + /** + * Drops a column + * + * @param string The table + * @param string The column name + */ + function drop_column($table, $column) + { + return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} DROP {$column}"); + } + + /** + * Adds a column + * + * @param string The table + * @param string The column name + * @param string the new column definition + */ + function add_column($table, $column, $definition) + { + $query = $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ADD {$column} {$definition}"); + $query->closeCursor(); + return $query; + } + + /** + * Modifies a column + * + * @param string The table + * @param string The column name + * @param string the new column definition + */ + function modify_column($table, $column, $new_definition) + { + // We use a rename query as both need to duplicate the table etc... + $this->rename_column($table, $column, $column, $new_definition); + } + + /** + * Renames a column + * + * @param string The table + * @param string The old column name + * @param string the new column name + * @param string the new column definition + */ + function rename_column($table, $old_column, $new_column, $new_definition) + { + // This will trigger the "alter_table_parse" function which will copy the table and rename the column + return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} CHANGE {$old_column} {$new_column} {$new_definition}"); + } + + /** + * Fetch a list of database character sets this DBMS supports + * + * @return array Array of supported character sets with array key being the name, array value being display name. False if unsupported + */ + function fetch_db_charsets() + { + return false; + } + + /** + * Fetch a database collation for a particular database character set + * + * @param string The database character set + * @return string The matching database collation, false if unsupported + */ + function fetch_charset_collation($charset) + { + return false; + } + + /** + * Fetch a character set/collation string for use with CREATE TABLE statements. Uses current DB encoding + * + * @return string The built string, empty if unsupported + */ + function build_create_table_collation() + { + return ''; + } + + /** + * Time how long it takes for a particular piece of code to run. Place calls above & below the block of code. + * + * @deprecated + */ + function get_execution_time() + { + return get_execution_time(); + } + + /** + * Binary database fields require special attention. + * + * @param string Binary value + * @return string Encoded binary value + */ + function escape_binary($string) + { + return "X'".$this->escape_string(bin2hex($string))."'"; + } + + /** + * Unescape binary data. + * + * @param string Binary value + * @return string Encoded binary value + */ + function unescape_binary($string) + { + // Nothing to do + return $string; + } +} + diff --git a/Upload/inc/functions.php b/Upload/inc/functions.php new file mode 100644 index 0000000..37d4ed4 --- /dev/null +++ b/Upload/inc/functions.php @@ -0,0 +1,7852 @@ +stop()); + $contents = $plugins->run_hooks("pre_output_page", $contents); + + if($mybb->usergroup['cancp'] == 1 || $mybb->dev_mode == 1) + { + if($mybb->settings['extraadmininfo'] != 0) + { + $phptime = $maintimer->totaltime - $db->query_time; + $query_time = $db->query_time; + + if($maintimer->totaltime > 0) + { + $percentphp = number_format((($phptime/$maintimer->totaltime) * 100), 2); + $percentsql = number_format((($query_time/$maintimer->totaltime) * 100), 2); + } + else + { + // if we've got a super fast script... all we can do is assume something + $percentphp = 0; + $percentsql = 0; + } + + $serverload = get_server_load(); + + if(my_strpos(getenv("REQUEST_URI"), "?")) + { + $debuglink = htmlspecialchars_uni(getenv("REQUEST_URI")) . "&debug=1"; + } + else + { + $debuglink = htmlspecialchars_uni(getenv("REQUEST_URI")) . "?debug=1"; + } + + $memory_usage = get_memory_usage(); + + if($memory_usage) + { + $memory_usage = $lang->sprintf($lang->debug_memory_usage, get_friendly_size($memory_usage)); + } + else + { + $memory_usage = ''; + } + // MySQLi is still MySQL, so present it that way to the user + $database_server = $db->short_title; + + if($database_server == 'MySQLi') + { + $database_server = 'MySQL'; + } + $generated_in = $lang->sprintf($lang->debug_generated_in, $totaltime); + $debug_weight = $lang->sprintf($lang->debug_weight, $percentphp, $percentsql, $database_server); + $sql_queries = $lang->sprintf($lang->debug_sql_queries, $db->query_count); + $server_load = $lang->sprintf($lang->debug_server_load, $serverload); + + eval("\$debugstuff = \"".$templates->get("debug_summary")."\";"); + $contents = str_replace("", $debugstuff, $contents); + } + + if($mybb->debug_mode == true) + { + debug_page(); + } + } + + $contents = str_replace("", "", $contents); + + if($mybb->settings['gzipoutput'] == 1) + { + $contents = gzip_encode($contents, $mybb->settings['gziplevel']); + } + + @header("Content-type: text/html; charset={$lang->settings['charset']}"); + + echo $contents; + + $plugins->run_hooks("post_output_page"); +} + +/** + * Adds a function or class to the list of code to run on shutdown. + * + * @param mixed The name of the function. + * @param mixed An array of arguments for the function + * @return boolean True if function exists, otherwise false. + */ +function add_shutdown($name, $arguments=array()) +{ + global $shutdown_functions; + + if(!is_array($shutdown_functions)) + { + $shutdown_functions = array(); + } + + if(!is_array($arguments)) + { + $arguments = array($arguments); + } + + if(is_array($name) && method_exists($name[0], $name[1])) + { + $shutdown_functions[] = array('function' => $name, 'arguments' => $arguments); + return true; + } + else if(!is_array($name) && function_exists($name)) + { + $shutdown_functions[] = array('function' => $name, 'arguments' => $arguments); + return true; + } + + return false; +} + +/** + * Runs the shutdown items after the page has been sent to the browser. + * + */ +function run_shutdown() +{ + global $config, $db, $cache, $plugins, $error_handler, $shutdown_functions, $shutdown_queries, $done_shutdown, $mybb; + + if($done_shutdown == true || !$config || (isset($error_handler) && $error_handler->has_errors)) + { + return; + } + + if(empty($shutdown_queries) && empty($shutdown_functions)) + { + // Nothing to do + return; + } + + // Missing the core? Build + if(!is_object($mybb)) + { + require_once MYBB_ROOT."inc/class_core.php"; + $mybb = new MyBB; + + // Load the settings + require MYBB_ROOT."inc/settings.php"; + $mybb->settings = &$settings; + } + + // If our DB has been deconstructed already (bad PHP 5.2.0), reconstruct + if(!is_object($db)) + { + if(!isset($config) || empty($config['database']['type'])) + { + require MYBB_ROOT."inc/config.php"; + } + + if(isset($config)) + { + require_once MYBB_ROOT."inc/db_".$config['database']['type'].".php"; + switch($config['database']['type']) + { + case "sqlite": + $db = new DB_SQLite; + break; + case "pgsql": + $db = new DB_PgSQL; + break; + case "mysqli": + $db = new DB_MySQLi; + break; + default: + $db = new DB_MySQL; + } + + $db->connect($config['database']); + if(!defined("TABLE_PREFIX")) + { + define("TABLE_PREFIX", $config['database']['table_prefix']); + } + $db->set_table_prefix(TABLE_PREFIX); + } + } + + // Cache object deconstructed? reconstruct + if(!is_object($cache)) + { + require_once MYBB_ROOT."inc/class_datacache.php"; + $cache = new datacache; + $cache->cache(); + } + + // And finally.. plugins + if(!is_object($plugins) && !defined("NO_PLUGINS") && !($mybb->settings['no_plugins'] == 1)) + { + require_once MYBB_ROOT."inc/class_plugins.php"; + $plugins = new pluginSystem; + $plugins->load(); + } + + // We have some shutdown queries needing to be run + if(is_array($shutdown_queries)) + { + // Loop through and run them all + foreach($shutdown_queries as $query) + { + $db->query($query); + } + } + + // Run any shutdown functions if we have them + if(is_array($shutdown_functions)) + { + foreach($shutdown_functions as $function) + { + call_user_func_array($function['function'], $function['arguments']); + } + } + + $done_shutdown = true; +} + +/** + * Sends a specified amount of messages from the mail queue + * + * @param int The number of messages to send (Defaults to 10) + */ +function send_mail_queue($count=10) +{ + global $db, $cache, $plugins; + + $plugins->run_hooks("send_mail_queue_start"); + + // Check to see if the mail queue has messages needing to be sent + $mailcache = $cache->read("mailqueue"); + if($mailcache['queue_size'] > 0 && ($mailcache['locked'] == 0 || $mailcache['locked'] < TIME_NOW-300)) + { + // Lock the queue so no other messages can be sent whilst these are (for popular boards) + $cache->update_mailqueue(0, TIME_NOW); + + // Fetch emails for this page view - and send them + $query = $db->simple_select("mailqueue", "*", "", array("order_by" => "mid", "order_dir" => "asc", "limit_start" => 0, "limit" => $count)); + + while($email = $db->fetch_array($query)) + { + // Delete the message from the queue + $db->delete_query("mailqueue", "mid='{$email['mid']}'"); + + if($db->affected_rows() == 1) + { + my_mail($email['mailto'], $email['subject'], $email['message'], $email['mailfrom'], "", $email['headers'], true); + } + } + // Update the mailqueue cache and remove the lock + $cache->update_mailqueue(TIME_NOW, 0); + } + + $plugins->run_hooks("send_mail_queue_end"); +} + +/** + * Parses the contents of a page before outputting it. + * + * @param string The contents of the page. + * @return string The parsed page. + */ +function parse_page($contents) +{ + global $lang, $theme, $mybb, $htmldoctype, $archive_url, $error_handler; + + $contents = str_replace('', build_breadcrumb(), $contents); + $contents = str_replace('', $archive_url, $contents); + + if($htmldoctype) + { + $contents = $htmldoctype.$contents; + } + else + { + $contents = "\n".$contents; + } + + $contents = str_replace("settings['rtl'] == 1) + { + $contents = str_replace("settings['htmllang']) + { + $contents = str_replace("settings['htmllang']."\" lang=\"".$lang->settings['htmllang']."\"", $contents); + } + + if($error_handler->warnings) + { + $contents = str_replace("", "\n".$error_handler->show_warnings(), $contents); + } + + return $contents; +} + +/** + * Turn a unix timestamp in to a "friendly" date/time format for the user. + * + * @param string A date format according to PHP's date structure. + * @param int The unix timestamp the date should be generated for. + * @param int The offset in hours that should be applied to times. (timezones) + * @param int Whether or not to use today/yesterday formatting. + * @param boolean Whether or not to use the adodb time class for < 1970 or > 2038 times + * @return string The formatted timestamp. + */ +function my_date($format, $stamp="", $offset="", $ty=1, $adodb=false) +{ + global $mybb, $lang, $mybbadmin, $plugins; + + // If the stamp isn't set, use TIME_NOW + if(empty($stamp)) + { + $stamp = TIME_NOW; + } + + if(!$offset && $offset != '0') + { + if(isset($mybb->user['uid']) && $mybb->user['uid'] != 0 && array_key_exists("timezone", $mybb->user)) + { + $offset = $mybb->user['timezone']; + $dstcorrection = $mybb->user['dst']; + } + elseif(defined("IN_ADMINCP")) + { + $offset = $mybbadmin['timezone']; + $dstcorrection = $mybbadmin['dst']; + } + else + { + $offset = $mybb->settings['timezoneoffset']; + $dstcorrection = $mybb->settings['dstcorrection']; + } + + // If DST correction is enabled, add an additional hour to the timezone. + if($dstcorrection == 1) + { + ++$offset; + if(my_substr($offset, 0, 1) != "-") + { + $offset = "+".$offset; + } + } + } + + if($offset == "-") + { + $offset = 0; + } + + // Using ADOdb? + if($adodb == true && !function_exists('adodb_date')) + { + $adodb = false; + } + + $todaysdate = $yesterdaysdate = ''; + if($ty && ($format == $mybb->settings['dateformat'] || $format == 'relative')) + { + $_stamp = TIME_NOW; + if($adodb == true) + { + $date = adodb_date($mybb->settings['dateformat'], $stamp + ($offset * 3600)); + $todaysdate = adodb_date($mybb->settings['dateformat'], $_stamp + ($offset * 3600)); + $yesterdaysdate = adodb_date($mybb->settings['dateformat'], ($_stamp - 86400) + ($offset * 3600)); + } + else + { + $date = gmdate($mybb->settings['dateformat'], $stamp + ($offset * 3600)); + $todaysdate = gmdate($mybb->settings['dateformat'], $_stamp + ($offset * 3600)); + $yesterdaysdate = gmdate($mybb->settings['dateformat'], ($_stamp - 86400) + ($offset * 3600)); + } + } + + if($format == 'relative') + { + // Relative formats both date and time + if($ty != 2 && (TIME_NOW - $stamp) < 3600) + { + $diff = TIME_NOW - $stamp; + $relative = array('prefix' => '', 'minute' => 0, 'plural' => $lang->rel_minutes_plural, 'suffix' => $lang->rel_ago); + + if($diff < 0) + { + $diff = abs($diff); + $relative['suffix'] = ''; + $relative['prefix'] = $lang->rel_in; + } + + $relative['minute'] = floor($diff / 60); + + if($relative['minute'] <= 1) + { + $relative['minute'] = 1; + $relative['plural'] = $lang->rel_minutes_single; + } + + if($diff <= 60) + { + // Less than a minute + $relative['prefix'] = $lang->rel_less_than; + } + + $date = $lang->sprintf($lang->rel_time, $relative['prefix'], $relative['minute'], $relative['plural'], $relative['suffix']); + } + elseif($ty != 2 && (TIME_NOW - $stamp) >= 3600 && (TIME_NOW - $stamp) < 43200) + { + $diff = TIME_NOW - $stamp; + $relative = array('prefix' => '', 'hour' => 0, 'plural' => $lang->rel_hours_plural, 'suffix' => $lang->rel_ago); + + if($diff < 0) + { + $diff = abs($diff); + $relative['suffix'] = ''; + $relative['prefix'] = $lang->rel_in; + } + + $relative['hour'] = floor($diff / 3600); + + if($relative['hour'] <= 1) + { + $relative['hour'] = 1; + $relative['plural'] = $lang->rel_hours_single; + } + + $date = $lang->sprintf($lang->rel_time, $relative['prefix'], $relative['hour'], $relative['plural'], $relative['suffix']); + } + else + { + if($ty) + { + if($todaysdate == $date) + { + $date = $lang->today; + } + else if($yesterdaysdate == $date) + { + $date = $lang->yesterday; + } + } + + $date .= $mybb->settings['datetimesep']; + if($adodb == true) + { + $date .= adodb_date($mybb->settings['timeformat'], $stamp + ($offset * 3600)); + } + else + { + $date .= gmdate($mybb->settings['timeformat'], $stamp + ($offset * 3600)); + } + } + } + else + { + if($ty && $format == $mybb->settings['dateformat']) + { + if($todaysdate == $date) + { + $date = $lang->today; + } + else if($yesterdaysdate == $date) + { + $date = $lang->yesterday; + } + } + else + { + if($adodb == true) + { + $date = adodb_date($format, $stamp + ($offset * 3600)); + } + else + { + $date = gmdate($format, $stamp + ($offset * 3600)); + } + } + } + + if(is_object($plugins)) + { + $date = $plugins->run_hooks("my_date", $date); + } + + return $date; +} + +/** + * Sends an email using PHP's mail function, formatting it appropriately. + * + * @param string Address the email should be addressed to. + * @param string The subject of the email being sent. + * @param string The message being sent. + * @param string The from address of the email, if blank, the board name will be used. + * @param string The chracter set being used to send this email. + * @param boolean Do we wish to keep the connection to the mail server alive to send more than one message (SMTP only) + * @param string The format of the email to be sent (text or html). text is default + * @param string The text message of the email if being sent in html format, for email clients that don't support html + * @param string The email address to return to. Defaults to admin return email address. + */ +function my_mail($to, $subject, $message, $from="", $charset="", $headers="", $keep_alive=false, $format="text", $message_text="", $return_email="") +{ + global $mybb; + static $mail; + + // Does our object not exist? Create it + if(!is_object($mail)) + { + require_once MYBB_ROOT."inc/class_mailhandler.php"; + + if($mybb->settings['mail_handler'] == 'smtp') + { + require_once MYBB_ROOT."inc/mailhandlers/smtp.php"; + $mail = new SmtpMail(); + } + else + { + require_once MYBB_ROOT."inc/mailhandlers/php.php"; + $mail = new PhpMail(); + } + } + + // Using SMTP based mail + if($mybb->settings['mail_handler'] == 'smtp') + { + if($keep_alive == true) + { + $mail->keep_alive = true; + } + } + + // Using PHP based mail() + else + { + if($mybb->settings['mail_parameters'] != '') + { + $mail->additional_parameters = $mybb->settings['mail_parameters']; + } + } + + // Build and send + $mail->build_message($to, $subject, $message, $from, $charset, $headers, $format, $message_text, $return_email); + return $mail->send(); +} + +/** + * Generates a unique code for POST requests to prevent XSS/CSRF attacks + * + * @return string The generated code + */ +function generate_post_check() +{ + global $mybb, $session; + if($mybb->user['uid']) + { + return md5($mybb->user['loginkey'].$mybb->user['salt'].$mybb->user['regdate']); + } + // Guests get a special string + else + { + return md5($session->useragent.$mybb->config['database']['username'].$mybb->settings['internal']['encryption_key']); + } +} + +/** + * Verifies a POST check code is valid, if not shows an error (silently returns false on silent parameter) + * + * @param string The incoming POST check code + * @param boolean Silent mode or not (silent mode will not show the error to the user but returns false) + */ +function verify_post_check($code, $silent=false) +{ + global $lang; + if(generate_post_check() != $code) + { + if($silent == true) + { + return false; + } + else + { + if(defined("IN_ADMINCP")) + { + return false; + } + else + { + error($lang->invalid_post_code); + } + } + } + else + { + return true; + } +} + +/** + * Return a parent list for the specified forum. + * + * @param int The forum id to get the parent list for. + * @return string The comma-separated parent list. + */ +function get_parent_list($fid) +{ + global $forum_cache; + static $forumarraycache; + + if($forumarraycache[$fid]) + { + return $forumarraycache[$fid]['parentlist']; + } + elseif($forum_cache[$fid]) + { + return $forum_cache[$fid]['parentlist']; + } + else + { + cache_forums(); + return $forum_cache[$fid]['parentlist']; + } +} + +/** + * Build a parent list of a specific forum, suitable for querying + * + * @param int The forum ID + * @param string The column name to add to the query + * @param string The joiner for each forum for querying (OR | AND | etc) + * @param string The parent list of the forum - if you have it + * @return string The query string generated + */ +function build_parent_list($fid, $column="fid", $joiner="OR", $parentlist="") +{ + if(!$parentlist) + { + $parentlist = get_parent_list($fid); + } + + $parentsexploded = explode(",", $parentlist); + $builtlist = "("; + $sep = ''; + + foreach($parentsexploded as $key => $val) + { + $builtlist .= "$sep$column='$val'"; + $sep = " $joiner "; + } + + $builtlist .= ")"; + + return $builtlist; +} + +/** + * Load the forum cache in to memory + * + * @param boolean True to force a reload of the cache + */ +function cache_forums($force=false) +{ + global $forum_cache, $cache; + + if($force == true) + { + $forum_cache = $cache->read("forums", 1); + return $forum_cache; + } + + if(!$forum_cache) + { + $forum_cache = $cache->read("forums"); + if(!$forum_cache) + { + $cache->update_forums(); + $forum_cache = $cache->read("forums", 1); + } + } + return $forum_cache; +} + +/** + * Generate an array of all child and descendant forums for a specific forum. + * + * @param int The forum ID + * @param return Array of descendants + */ +function get_child_list($fid) +{ + static $forums_by_parent; + + $forums = array(); + if(!is_array($forums_by_parent)) + { + $forum_cache = cache_forums(); + foreach($forum_cache as $forum) + { + if($forum['active'] != 0) + { + $forums_by_parent[$forum['pid']][$forum['fid']] = $forum; + } + } + } + if(!is_array($forums_by_parent[$fid])) + { + return; + } + + foreach($forums_by_parent[$fid] as $forum) + { + $forums[] = $forum['fid']; + $children = get_child_list($forum['fid']); + if(is_array($children)) + { + $forums = array_merge($forums, $children); + } + } + return $forums; +} + +/** + * Produce a friendly error message page + * + * @param string The error message to be shown + * @param string The title of the message shown in the title of the page and the error table + */ +function error($error="", $title="") +{ + global $header, $footer, $theme, $headerinclude, $db, $templates, $lang, $mybb, $plugins; + + $error = $plugins->run_hooks("error", $error); + if(!$error) + { + $error = $lang->unknown_error; + } + + // AJAX error message? + if($mybb->get_input('ajax', 1)) + { + // Send our headers. + @header("Content-type: application/json; charset={$lang->settings['charset']}"); + echo json_encode(array("errors" => array($error))); + exit; + } + + if(!$title) + { + $title = $mybb->settings['bbname']; + } + + $timenow = my_date('relative', TIME_NOW); + reset_breadcrumb(); + add_breadcrumb($lang->error); + + eval("\$errorpage = \"".$templates->get("error")."\";"); + output_page($errorpage); + + exit; +} + +/** + * Produce an error message for displaying inline on a page + * + * @param array Array of errors to be shown + * @param string The title of the error message + * @param string JSON data to be encoded (we may want to send more data; e.g. newreply.php uses this for CAPTCHA) + * @return string The inline error HTML + */ +function inline_error($errors, $title="", $json_data=array()) +{ + global $theme, $mybb, $db, $lang, $templates; + + if(!$title) + { + $title = $lang->please_correct_errors; + } + + if(!is_array($errors)) + { + $errors = array($errors); + } + + // AJAX error message? + if($mybb->get_input('ajax', 1)) + { + // Send our headers. + @header("Content-type: application/json; charset={$lang->settings['charset']}"); + + if(empty($json_data)) + { + echo json_encode(array("errors" => $errors)); + } + else + { + echo json_encode(array_merge(array("errors" => $errors), $json_data)); + } + exit; + } + + $errorlist = ''; + + foreach($errors as $error) + { + $errorlist .= "
  • ".$error."
  • \n"; + } + + eval("\$errors = \"".$templates->get("error_inline")."\";"); + + return $errors; +} + +/** + * Presents the user with a "no permission" page + */ +function error_no_permission() +{ + global $mybb, $theme, $templates, $db, $lang, $plugins, $session; + + $time = TIME_NOW; + $plugins->run_hooks("no_permission"); + + $noperm_array = array ( + "nopermission" => '1', + "location1" => 0, + "location2" => 0 + ); + + $db->update_query("sessions", $noperm_array, "sid='{$session->sid}'"); + + if($mybb->get_input('ajax', 1)) + { + // Send our headers. + header("Content-type: application/json; charset={$lang->settings['charset']}"); + echo json_encode(array("errors" => array($lang->error_nopermission_user_ajax))); + exit; + } + + if($mybb->user['uid']) + { + $lang->error_nopermission_user_username = $lang->sprintf($lang->error_nopermission_user_username, $mybb->user['username']); + eval("\$errorpage = \"".$templates->get("error_nopermission_loggedin")."\";"); + } + else + { + // Redirect to where the user came from + $redirect_url = $_SERVER['PHP_SELF']; + if($_SERVER['QUERY_STRING']) + { + $redirect_url .= '?'.$_SERVER['QUERY_STRING']; + } + + $redirect_url = htmlspecialchars_uni($redirect_url); + + switch($mybb->settings['username_method']) + { + case 0: + $lang_username = $lang->username; + break; + case 1: + $lang_username = $lang->username1; + break; + case 2: + $lang_username = $lang->username2; + break; + default: + $lang_username = $lang->username; + break; + } + eval("\$errorpage = \"".$templates->get("error_nopermission")."\";"); + } + + error($errorpage); +} + +/** + * Redirect the user to a given URL with a given message + * + * @param string The URL to redirect the user to + * @param string The redirection message to be shown + * @param string The title of the redirection page + * @param boolean Force the redirect page regardless of settings + */ +function redirect($url, $message="", $title="", $force_redirect=false) +{ + global $header, $footer, $mybb, $theme, $headerinclude, $templates, $lang, $plugins; + + $redirect_args = array('url' => &$url, 'message' => &$message, 'title' => &$title); + + $plugins->run_hooks("redirect", $redirect_args); + + if($mybb->get_input('ajax', 1)) + { + // Send our headers. + //@header("Content-type: text/html; charset={$lang->settings['charset']}"); + $data = "\n"; + //exit; + + @header("Content-type: application/json; charset={$lang->settings['charset']}"); + echo json_encode(array("data" => $data)); + exit; + } + + if(!$message) + { + $message = $lang->redirect; + } + + $time = TIME_NOW; + $timenow = my_date('relative', $time); + + if(!$title) + { + $title = $mybb->settings['bbname']; + } + + // Show redirects only if both ACP and UCP settings are enabled, or ACP is enabled, and user is a guest, or they are forced. + if($force_redirect == true || ($mybb->settings['redirects'] == 1 && ($mybb->user['showredirect'] == 1 || !$mybb->user['uid']))) + { + $url = str_replace("&", "&", $url); + $url = htmlspecialchars_uni($url); + + eval("\$redirectpage = \"".$templates->get("redirect")."\";"); + output_page($redirectpage); + } + else + { + $url = htmlspecialchars_decode($url); + $url = str_replace(array("\n","\r",";"), "", $url); + + run_shutdown(); + + if(my_substr($url, 0, 7) !== 'http://' && my_substr($url, 0, 8) !== 'https://' && my_substr($url, 0, 1) !== '/') + { + header("Location: {$mybb->settings['bburl']}/{$url}"); + } + else + { + header("Location: {$url}"); + } + } + + exit; +} + +/** + * Generate a listing of page - pagination + * + * @param int The number of items + * @param int The number of items to be shown per page + * @param int The current page number + * @param string The URL to have page numbers tacked on to (If {page} is specified, the value will be replaced with the page #) + * @param boolean Whether or not the multipage is being shown in the navigation breadcrumb + * @return string The generated pagination + */ +function multipage($count, $perpage, $page, $url, $breadcrumb=false) +{ + global $theme, $templates, $lang, $mybb; + + if($count <= $perpage) + { + return; + } + + $url = str_replace("&", "&", $url); + $url = htmlspecialchars_uni($url); + + $pages = ceil($count / $perpage); + + $prevpage = ''; + if($page > 1) + { + $prev = $page-1; + $page_url = fetch_page_url($url, $prev); + eval("\$prevpage = \"".$templates->get("multipage_prevpage")."\";"); + } + + // Maximum number of "page bits" to show + if(!$mybb->settings['maxmultipagelinks']) + { + $mybb->settings['maxmultipagelinks'] = 5; + } + + $from = $page-floor($mybb->settings['maxmultipagelinks']/2); + $to = $page+floor($mybb->settings['maxmultipagelinks']/2); + + if($from <= 0) + { + $from = 1; + $to = $from+$mybb->settings['maxmultipagelinks']-1; + } + + if($to > $pages) + { + $to = $pages; + $from = $pages-$mybb->settings['maxmultipagelinks']+1; + if($from <= 0) + { + $from = 1; + } + } + + if($to == 0) + { + $to = $pages; + } + + $start = ''; + if($from > 1) + { + if($from-1 == 1) + { + $lang->multipage_link_start = ''; + } + + $page_url = fetch_page_url($url, 1); + eval("\$start = \"".$templates->get("multipage_start")."\";"); + } + + $mppage = ''; + for($i = $from; $i <= $to; ++$i) + { + $page_url = fetch_page_url($url, $i); + if($page == $i) + { + if($breadcrumb == true) + { + eval("\$mppage .= \"".$templates->get("multipage_page_link_current")."\";"); + } + else + { + eval("\$mppage .= \"".$templates->get("multipage_page_current")."\";"); + } + } + else + { + eval("\$mppage .= \"".$templates->get("multipage_page")."\";"); + } + } + + $end = ''; + if($to < $pages) + { + if($to+1 == $pages) + { + $lang->multipage_link_end = ''; + } + + $page_url = fetch_page_url($url, $pages); + eval("\$end = \"".$templates->get("multipage_end")."\";"); + } + + $nextpage = ''; + if($page < $pages) + { + $next = $page+1; + $page_url = fetch_page_url($url, $next); + eval("\$nextpage = \"".$templates->get("multipage_nextpage")."\";"); + } + + $jumptopage = ''; + if($pages > ($mybb->settings['maxmultipagelinks']+1) && $mybb->settings['jumptopagemultipage'] == 1) + { + // When the second parameter is set to 1, fetch_page_url thinks it's the first page and removes it from the URL as it's unnecessary + $jump_url = fetch_page_url($url, 1); + eval("\$jumptopage = \"".$templates->get("multipage_jump_page")."\";"); + } + + $lang->multipage_pages = $lang->sprintf($lang->multipage_pages, $pages); + + if($breadcrumb == true) + { + eval("\$multipage = \"".$templates->get("multipage_breadcrumb")."\";"); + } + else + { + eval("\$multipage = \"".$templates->get("multipage")."\";"); + } + + return $multipage; +} + +/** + * Generate a page URL for use by the multipage function + * + * @param string The URL being passed + * @param int The page number + */ +function fetch_page_url($url, $page) +{ + if($page <= 1) + { + $find = array( + "-page-{page}", + "&page={page}", + "{page}" + ); + + // Remove "Page 1" to the defacto URL + $url = str_replace($find, array("", "", $page), $url); + return $url; + } + else if(strpos($url, "{page}") === false) + { + // If no page identifier is specified we tack it on to the end of the URL + if(strpos($url, "?") === false) + { + $url .= "?"; + } + else + { + $url .= "&"; + } + + $url .= "page=$page"; + } + else + { + $url = str_replace("{page}", $page, $url); + } + + return $url; +} + +/** + * Fetch the permissions for a specific user + * + * @param int The user ID + * @return array Array of user permissions for the specified user + */ +function user_permissions($uid=0) +{ + global $mybb, $cache, $groupscache, $user_cache; + + // If no user id is specified, assume it is the current user + if($uid == 0) + { + $uid = $mybb->user['uid']; + } + + // User id does not match current user, fetch permissions + if($uid != $mybb->user['uid']) + { + // We've already cached permissions for this user, return them. + if($user_cache[$uid]['permissions']) + { + return $user_cache[$uid]['permissions']; + } + + // This user was not already cached, fetch their user information. + if(!$user_cache[$uid]) + { + $user_cache[$uid] = get_user($uid); + } + + // Collect group permissions. + $gid = $user_cache[$uid]['usergroup'].",".$user_cache[$uid]['additionalgroups']; + $groupperms = usergroup_permissions($gid); + + // Store group permissions in user cache. + $user_cache[$uid]['permissions'] = $groupperms; + return $groupperms; + } + // This user is the current user, return their permissions + else + { + return $mybb->usergroup; + } +} + +/** + * Fetch the usergroup permissions for a specic group or series of groups combined + * + * @param mixed A list of groups (Can be a single integer, or a list of groups separated by a comma) + * @return array Array of permissions generated for the groups + */ +function usergroup_permissions($gid=0) +{ + global $cache, $groupscache, $grouppermignore, $groupzerogreater; + + if(!is_array($groupscache)) + { + $groupscache = $cache->read("usergroups"); + } + + $groups = explode(",", $gid); + + + if(count($groups) == 1) + { + return $groupscache[$gid]; + } + + foreach($groups as $gid) + { + if(trim($gid) == "" || !$groupscache[$gid]) + { + continue; + } + + foreach($groupscache[$gid] as $perm => $access) + { + if(!in_array($perm, $grouppermignore)) + { + if(isset($usergroup[$perm])) + { + $permbit = $usergroup[$perm]; + } + else + { + $permbit = ""; + } + + // 0 represents unlimited for numerical group permissions (i.e. private message limit) so take that into account. + if(in_array($perm, $groupzerogreater) && ($access == 0 || $permbit === 0)) + { + $usergroup[$perm] = 0; + continue; + } + + if($access > $permbit || ($access == "yes" && $permbit == "no") || !$permbit) // Keep yes/no for compatibility? + { + $usergroup[$perm] = $access; + } + } + } + } + + return $usergroup; +} + +/** + * Fetch the display group properties for a specific display group + * + * @param int The group ID to fetch the display properties for + * @return array Array of display properties for the group + */ +function usergroup_displaygroup($gid) +{ + global $cache, $groupscache, $displaygroupfields; + + if(!is_array($groupscache)) + { + $groupscache = $cache->read("usergroups"); + } + + $displaygroup = array(); + $group = $groupscache[$gid]; + + foreach($displaygroupfields as $field) + { + $displaygroup[$field] = $group[$field]; + } + + return $displaygroup; +} + +/** + * Build the forum permissions for a specific forum, user or group + * + * @param int The forum ID to build permissions for (0 builds for all forums) + * @param int The user to build the permissions for (0 will select the uid automatically) + * @param int The group of the user to build permissions for (0 will fetch it) + * @return array Forum permissions for the specific forum or forums + */ +function forum_permissions($fid=0, $uid=0, $gid=0) +{ + global $db, $cache, $groupscache, $forum_cache, $fpermcache, $mybb, $cached_forum_permissions_permissions, $cached_forum_permissions; + + if($uid == 0) + { + $uid = $mybb->user['uid']; + } + + if(!$gid || $gid == 0) // If no group, we need to fetch it + { + if($uid != 0 && $uid != $mybb->user['uid']) + { + $user = get_user($uid); + + $gid = $user['usergroup'].",".$user['additionalgroups']; + $groupperms = usergroup_permissions($gid); + } + else + { + $gid = $mybb->user['usergroup']; + + if(isset($mybb->user['additionalgroups'])) + { + $gid .= ",".$mybb->user['additionalgroups']; + } + + $groupperms = $mybb->usergroup; + } + } + + if(!is_array($forum_cache)) + { + $forum_cache = cache_forums(); + + if(!$forum_cache) + { + return false; + } + } + + if(!is_array($fpermcache)) + { + $fpermcache = $cache->read("forumpermissions"); + } + + if($fid) // Fetch the permissions for a single forum + { + if(empty($cached_forum_permissions_permissions[$gid][$fid])) + { + $cached_forum_permissions_permissions[$gid][$fid] = fetch_forum_permissions($fid, $gid, $groupperms); + } + return $cached_forum_permissions_permissions[$gid][$fid]; + } + else + { + if(empty($cached_forum_permissions[$gid])) + { + foreach($forum_cache as $forum) + { + $cached_forum_permissions[$gid][$forum['fid']] = fetch_forum_permissions($forum['fid'], $gid, $groupperms); + } + } + return $cached_forum_permissions[$gid]; + } +} + +/** + * Fetches the permissions for a specific forum/group applying the inheritance scheme. + * Called by forum_permissions() + * + * @param int The forum ID + * @param string A comma separated list of usergroups + * @param array Group permissions + * @return array Permissions for this forum +*/ +function fetch_forum_permissions($fid, $gid, $groupperms) +{ + global $groupscache, $forum_cache, $fpermcache, $mybb, $fpermfields; + + $groups = explode(",", $gid); + + if(empty($fpermcache[$fid])) // This forum has no custom or inherited permissions so lets just return the group permissions + { + return $groupperms; + } + + $current_permissions = array(); + $only_view_own_threads = 1; + + foreach($groups as $gid) + { + if(!empty($groupscache[$gid])) + { + $level_permissions = $fpermcache[$fid][$gid]; + + // If our permissions arn't inherited we need to figure them out + if(empty($fpermcache[$fid][$gid])) + { + $parents = explode(',', $forum_cache[$fid]['parentlist']); + rsort($parents); + if(!empty($parents)) + { + foreach($parents as $parent_id) + { + if(!empty($fpermcache[$parent_id][$gid])) + { + $level_permissions = $fpermcache[$parent_id][$gid]; + break; + } + } + } + } + + // If we STILL don't have forum permissions we use the usergroup itself + if(empty($level_permissions)) + { + $level_permissions = $groupscache[$gid]; + } + + foreach($level_permissions as $permission => $access) + { + if(empty($current_permissions[$permission]) || $access >= $current_permissions[$permission] || ($access == "yes" && $current_permissions[$permission] == "no")) + { + $current_permissions[$permission] = $access; + } + } + + if($level_permissions["canview"] && empty($level_permissions["canonlyviewownthreads"])) + { + $only_view_own_threads = 0; + } + } + } + + // Figure out if we can view more than our own threads + if($only_view_own_threads == 0) + { + $current_permissions["canonlyviewownthreads"] = 0; + } + + if(count($current_permissions) == 0) + { + $current_permissions = $groupperms; + } + return $current_permissions; +} + +/** + * Check the password given on a certain forum for validity + * + * @param int The forum ID + * @param boolean The Parent ID + */ +function check_forum_password($fid, $pid=0) +{ + global $mybb, $header, $footer, $headerinclude, $theme, $templates, $lang, $forum_cache; + + $showform = true; + + if(!is_array($forum_cache)) + { + $forum_cache = cache_forums(); + if(!$forum_cache) + { + return false; + } + } + + // Loop through each of parent forums to ensure we have a password for them too + if(isset($forum_cache[$fid]['parentlist'])) + { + $parents = explode(',', $forum_cache[$fid]['parentlist']); + rsort($parents); + } + if(!empty($parents)) + { + foreach($parents as $parent_id) + { + if($parent_id == $fid || $parent_id == $pid) + { + continue; + } + + if($forum_cache[$parent_id]['password'] != "") + { + check_forum_password($parent_id, $fid); + } + } + } + + if(!empty($forum_cache[$fid]['password'])) + { + $password = $forum_cache[$fid]['password']; + if(isset($mybb->input['pwverify']) && $pid == 0) + { + if($password == $mybb->get_input('pwverify')) + { + my_setcookie("forumpass[$fid]", md5($mybb->user['uid'].$mybb->get_input('pwverify')), null, true); + $showform = false; + } + else + { + eval("\$pwnote = \"".$templates->get("forumdisplay_password_wrongpass")."\";"); + $showform = true; + } + } + else + { + if(!$mybb->cookies['forumpass'][$fid] || ($mybb->cookies['forumpass'][$fid] && md5($mybb->user['uid'].$password) != $mybb->cookies['forumpass'][$fid])) + { + $showform = true; + } + else + { + $showform = false; + } + } + } + else + { + $showform = false; + } + + if($showform) + { + if($pid) + { + header("Location: ".$mybb->settings['bburl']."/".get_forum_link($fid)); + } + else + { + $_SERVER['REQUEST_URI'] = htmlspecialchars_uni($_SERVER['REQUEST_URI']); + eval("\$pwform = \"".$templates->get("forumdisplay_password")."\";"); + output_page($pwform); + } + exit; + } +} + +/** + * Return the permissions for a moderator in a specific forum + * + * @param fid The forum ID + * @param uid The user ID to fetch permissions for (0 assumes current logged in user) + * @param string The parent list for the forum (if blank, will be fetched) + * @return array Array of moderator permissions for the specific forum + */ +function get_moderator_permissions($fid, $uid="0", $parentslist="") +{ + global $mybb, $cache, $db; + static $modpermscache; + + if($uid < 1) + { + $uid = $mybb->user['uid']; + } + + if($uid == 0) + { + return false; + } + + if(isset($modpermscache[$fid][$uid])) + { + return $modpermscache[$fid][$uid]; + } + + if(!$parentslist) + { + $parentslist = explode(',', get_parent_list($fid)); + } + + // Get user groups + $perms = array(); + $user = get_user($uid); + + $groups = array($user['usergroup']); + + if(!empty($user['additionalgroups'])) + { + $extra_groups = explode(",", $user['additionalgroups']); + + foreach($extra_groups as $extra_group) + { + $groups[] = $extra_group; + } + } + + $mod_cache = $cache->read("moderators"); + + foreach($mod_cache as $forumid => $forum) + { + if(!is_array($forum) || !in_array($forumid, $parentslist)) + { + // No perms or we're not after this forum + continue; + } + + // User settings override usergroup settings + if(is_array($forum['users'][$uid])) + { + $perm = $forum['users'][$uid]; + foreach($perm as $action => $value) + { + if(strpos($action, "can") === false) + { + continue; + } + + // Figure out the user permissions + if($value == 0) + { + // The user doesn't have permission to set this action + $perms[$action] = 0; + } + else + { + $perms[$action] = max($perm[$action], $perms[$action]); + } + } + } + + foreach($groups as $group) + { + if(!is_array($forum['usergroups'][$group])) + { + // There are no permissions set for this group + continue; + } + + $perm = $forum['usergroups'][$group]; + foreach($perm as $action => $value) + { + if(strpos($action, "can") === false) + { + continue; + } + + $perms[$action] = max($perm[$action], $perms[$action]); + } + } + } + + $modpermscache[$fid][$uid] = $perms; + + return $perms; +} + +/** + * Checks if a moderator has permissions to perform an action in a specific forum + * + * @param int The forum ID (0 assumes global) + * @param string The action tyring to be performed. (blank assumes any action at all) + * @param int The user ID (0 assumes current user) + * @return bool Returns true if the user has permission, false if they do not + */ +function is_moderator($fid="0", $action="", $uid="0") +{ + global $mybb, $cache; + + if($uid == 0) + { + $uid = $mybb->user['uid']; + } + + if($uid == 0) + { + return false; + } + + $user_perms = user_permissions($uid); + if($user_perms['issupermod'] == 1) + { + if($fid) + { + $forumpermissions = forum_permissions($fid); + if($forumpermissions['canview'] && $forumpermissions['canviewthreads'] && !$forumpermissions['canonlyviewownthreads']) + { + return true; + } + return false; + } + return true; + } + else + { + if(!$fid) + { + $modcache = $cache->read('moderators'); + if(!empty($modcache)) + { + foreach($modcache as $modusers) + { + if(isset($modusers['users'][$uid]) && $modusers['users'][$uid]['mid']) + { + return true; + } + elseif(isset($user_perms['gid']) && isset($modusers['usergroups'][$user_perms['gid']])) + { + // Moderating usergroup + return true; + } + } + } + return false; + } + else + { + $modperms = get_moderator_permissions($fid, $uid); + + if(!$action && $modperms) + { + return true; + } + else + { + if(isset($modperms[$action]) && $modperms[$action] == 1) + { + return true; + } + else + { + return false; + } + } + } + } +} + +/** + * Generate a list of the posticons. + * + * @return string The template of posticons. + */ +function get_post_icons() +{ + global $mybb, $cache, $icon, $theme, $templates, $lang; + + if(isset($mybb->input['icon'])) + { + $icon = $mybb->get_input('icon'); + } + + $iconlist = ''; + $no_icons_checked = " checked=\"checked\""; + // read post icons from cache, and sort them accordingly + $posticons_cache = $cache->read("posticons"); + $posticons = array(); + foreach($posticons_cache as $posticon) + { + $posticons[$posticon['name']] = $posticon; + } + krsort($posticons); + + foreach($posticons as $dbicon) + { + $dbicon['path'] = str_replace("{theme}", $theme['imgdir'], $dbicon['path']); + $dbicon['path'] = htmlspecialchars_uni($dbicon['path']); + $dbicon['name'] = htmlspecialchars_uni($dbicon['name']); + + if($icon == $dbicon['iid']) + { + $checked = " checked=\"checked\""; + $no_icons_checked = ''; + } + else + { + $checked = ''; + } + + eval("\$iconlist .= \"".$templates->get("posticons_icon")."\";"); + } + + eval("\$posticons = \"".$templates->get("posticons")."\";"); + + return $posticons; +} + +/** + * MyBB setcookie() wrapper. + * + * @param string The cookie identifier. + * @param string The cookie value. + * @param int The timestamp of the expiry date. + * @param boolean True if setting a HttpOnly cookie (supported by IE, Opera 9, Konqueror) + */ +function my_setcookie($name, $value="", $expires="", $httponly=false) +{ + global $mybb; + + if(!$mybb->settings['cookiepath']) + { + $mybb->settings['cookiepath'] = "/"; + } + + if($expires == -1) + { + $expires = 0; + } + elseif($expires == "" || $expires == null) + { + $expires = TIME_NOW + (60*60*24*365); // Make the cookie expire in a years time + } + else + { + $expires = TIME_NOW + (int)$expires; + } + + $mybb->settings['cookiepath'] = str_replace(array("\n","\r"), "", $mybb->settings['cookiepath']); + $mybb->settings['cookiedomain'] = str_replace(array("\n","\r"), "", $mybb->settings['cookiedomain']); + $mybb->settings['cookieprefix'] = str_replace(array("\n","\r", " "), "", $mybb->settings['cookieprefix']); + + // Versions of PHP prior to 5.2 do not support HttpOnly cookies and IE is buggy when specifying a blank domain so set the cookie manually + $cookie = "Set-Cookie: {$mybb->settings['cookieprefix']}{$name}=".urlencode($value); + + if($expires > 0) + { + $cookie .= "; expires=".@gmdate('D, d-M-Y H:i:s \\G\\M\\T', $expires); + } + + if(!empty($mybb->settings['cookiepath'])) + { + $cookie .= "; path={$mybb->settings['cookiepath']}"; + } + + if(!empty($mybb->settings['cookiedomain'])) + { + $cookie .= "; domain={$mybb->settings['cookiedomain']}"; + } + + if($httponly == true) + { + $cookie .= "; HttpOnly"; + } + + $mybb->cookies[$name] = $value; + + header($cookie, false); +} + +/** + * Unset a cookie set by MyBB. + * + * @param string The cookie identifier. + */ +function my_unsetcookie($name) +{ + global $mybb; + + $expires = -3600; + my_setcookie($name, "", $expires); + + unset($mybb->cookies[$name]); +} + +/** + * Get the contents from a serialised cookie array. + * + * @param string The cookie identifier. + * @param int The cookie content id. + * @return array|boolean The cookie id's content array or false when non-existent. + */ +function my_get_array_cookie($name, $id) +{ + global $mybb; + + if(!isset($mybb->cookies['mybb'][$name])) + { + return false; + } + + $cookie = my_unserialize($mybb->cookies['mybb'][$name]); + + if(is_array($cookie) && isset($cookie[$id])) + { + return $cookie[$id]; + } + else + { + return 0; + } +} + +/** + * Set a serialised cookie array. + * + * @param string The cookie identifier. + * @param int The cookie content id. + * @param string The value to set the cookie to. + * @param int The timestamp of the expiry date. + */ +function my_set_array_cookie($name, $id, $value, $expires="") +{ + global $mybb; + + $cookie = $mybb->cookies['mybb']; + if(isset($cookie[$name])) + { + $newcookie = my_unserialize($cookie[$name]); + } + else + { + $newcookie = array(); + } + + $newcookie[$id] = $value; + $newcookie = serialize($newcookie); + my_setcookie("mybb[$name]", addslashes($newcookie), $expires); + + // Make sure our current viarables are up-to-date as well + $mybb->cookies['mybb'][$name] = $newcookie; +} + +/** + * Verifies that data passed is an array + * + * @param array Data to unserialize + * @return array Unserialized data array + */ +function my_unserialize($data) +{ + // Do no unserialize objects + if(substr($data, 0, 1) == 'O') + { + return array(); + } + + $array = unserialize($data); + + if(!is_array($array)) + { + $array = array(); + } + + return $array; +} + +/** + * Returns the serverload of the system. + * + * @return int The serverload of the system. + */ +function get_server_load() +{ + global $mybb, $lang; + + $serverload = array(); + + // DIRECTORY_SEPARATOR checks if running windows + if(DIRECTORY_SEPARATOR != '\\') + { + if(function_exists("sys_getloadavg")) + { + // sys_getloadavg() will return an array with [0] being load within the last minute. + $serverload = sys_getloadavg(); + $serverload[0] = round($serverload[0], 4); + } + else if(@file_exists("/proc/loadavg") && $load = @file_get_contents("/proc/loadavg")) + { + $serverload = explode(" ", $load); + $serverload[0] = round($serverload[0], 4); + } + if(!is_numeric($serverload[0])) + { + if($mybb->safemode) + { + return $lang->unknown; + } + + // Suhosin likes to throw a warning if exec is disabled then die - weird + if($func_blacklist = @ini_get('suhosin.executor.func.blacklist')) + { + if(strpos(",".$func_blacklist.",", 'exec') !== false) + { + return $lang->unknown; + } + } + // PHP disabled functions? + if($func_blacklist = @ini_get('disable_functions')) + { + if(strpos(",".$func_blacklist.",", 'exec') !== false) + { + return $lang->unknown; + } + } + + $load = @exec("uptime"); + $load = explode("load average: ", $load); + $serverload = explode(",", $load[1]); + if(!is_array($serverload)) + { + return $lang->unknown; + } + } + } + else + { + return $lang->unknown; + } + + $returnload = trim($serverload[0]); + + return $returnload; +} + +/** + * Returns the amount of memory allocated to the script. + * + * @return int The amount of memory allocated to the script. + */ +function get_memory_usage() +{ + if(function_exists('memory_get_peak_usage')) + { + return memory_get_peak_usage(true); + } + elseif(function_exists('memory_get_usage')) + { + return memory_get_usage(true); + } + return false; +} + +/** + * Updates the forum statistics with specific values (or addition/subtraction of the previous value) + * + * @param array Array of items being updated (numthreads,numposts,numusers,numunapprovedthreads,numunapprovedposts,numdeletedposts,numdeletedthreads) + * @param boolean Force stats update? + */ +function update_stats($changes=array(), $force=false) +{ + global $cache, $db; + static $stats_changes; + + if(empty($stats_changes)) + { + // Update stats after all changes are done + add_shutdown('update_stats', array(array(), true)); + } + + if(empty($stats_changes) || $stats_changes['inserted']) + { + $stats_changes = array( + 'numthreads' => '+0', + 'numposts' => '+0', + 'numusers' => '+0', + 'numunapprovedthreads' => '+0', + 'numunapprovedposts' => '+0', + 'numdeletedposts' => '+0', + 'numdeletedthreads' => '+0', + 'inserted' => false // Reset after changes are inserted into cache + ); + $stats = $stats_changes; + } + + if($force) // Force writing to cache? + { + if(!empty($changes)) + { + // Calculate before writing to cache + update_stats($changes); + } + $stats = $cache->read("stats"); + $changes = $stats_changes; + } + else + { + $stats = $stats_changes; + } + + $new_stats = array(); + $counters = array('numthreads', 'numunapprovedthreads', 'numposts', 'numunapprovedposts', 'numusers', 'numdeletedposts', 'numdeletedthreads'); + foreach($counters as $counter) + { + if(array_key_exists($counter, $changes)) + { + if(substr($changes[$counter], 0, 2) == "+-") + { + $changes[$counter] = substr($changes[$counter], 1); + } + // Adding or subtracting from previous value? + if(substr($changes[$counter], 0, 1) == "+" || substr($changes[$counter], 0, 1) == "-") + { + if((int)$changes[$counter] != 0) + { + $new_stats[$counter] = $stats[$counter] + $changes[$counter]; + if(!$force && (substr($stats[$counter], 0, 1) == "+" || substr($stats[$counter], 0, 1) == "-")) + { + // We had relative values? Then it is still relative + if($new_stats[$counter] >= 0) + { + $new_stats[$counter] = "+{$new_stats[$counter]}"; + } + } + // Less than 0? That's bad + elseif($new_stats[$counter] < 0) + { + $new_stats[$counter] = 0; + } + } + } + else + { + $new_stats[$counter] = $changes[$counter]; + // Less than 0? That's bad + if($new_stats[$counter] < 0) + { + $new_stats[$counter] = 0; + } + } + } + } + + if(!$force) + { + $stats_changes = array_merge($stats, $new_stats); // Overwrite changed values + return; + } + + // Fetch latest user if the user count is changing + if(array_key_exists('numusers', $changes)) + { + $query = $db->simple_select("users", "uid, username", "", array('order_by' => 'regdate', 'order_dir' => 'DESC', 'limit' => 1)); + $lastmember = $db->fetch_array($query); + $new_stats['lastuid'] = $lastmember['uid']; + $new_stats['lastusername'] = $lastmember['username']; + } + + if(!empty($new_stats)) + { + if(is_array($stats)) + { + $stats = array_merge($stats, $new_stats); // Overwrite changed values + } + else + { + $stats = $new_stats; + } + } + + // Update stats row for today in the database + $todays_stats = array( + "dateline" => mktime(0, 0, 0, date("m"), date("j"), date("Y")), + "numusers" => $stats['numusers'], + "numthreads" => $stats['numthreads'], + "numposts" => $stats['numposts'] + ); + $db->replace_query("stats", $todays_stats, "dateline"); + + $cache->update("stats", $stats, "dateline"); + $stats_changes['inserted'] = true; +} + +/** + * Updates the forum counters with a specific value (or addition/subtraction of the previous value) + * + * @param int The forum ID + * @param array Array of items being updated (threads, posts, unapprovedthreads, unapprovedposts, deletedposts, deletedthreads) and their value (ex, 1, +1, -1) + */ +function update_forum_counters($fid, $changes=array()) +{ + global $db; + + $update_query = array(); + + $counters = array('threads', 'unapprovedthreads', 'posts', 'unapprovedposts', 'deletedposts', 'deletedthreads'); + + // Fetch above counters for this forum + $query = $db->simple_select("forums", implode(",", $counters), "fid='{$fid}'"); + $forum = $db->fetch_array($query); + + foreach($counters as $counter) + { + if(array_key_exists($counter, $changes)) + { + if(substr($changes[$counter], 0, 2) == "+-") + { + $changes[$counter] = substr($changes[$counter], 1); + } + // Adding or subtracting from previous value? + if(substr($changes[$counter], 0, 1) == "+" || substr($changes[$counter], 0, 1) == "-") + { + if((int)$changes[$counter] != 0) + { + $update_query[$counter] = $forum[$counter] + $changes[$counter]; + } + } + else + { + $update_query[$counter] = $changes[$counter]; + } + + // Less than 0? That's bad + if(isset($update_query[$counter]) && $update_query[$counter] < 0) + { + $update_query[$counter] = 0; + } + } + } + + // Only update if we're actually doing something + if(count($update_query) > 0) + { + $db->update_query("forums", $update_query, "fid='".(int)$fid."'"); + } + + // Guess we should update the statistics too? + $new_stats = array(); + if(array_key_exists('threads', $update_query)) + { + $threads_diff = $update_query['threads'] - $forum['threads']; + if($threads_diff > -1) + { + $new_stats['numthreads'] = "+{$threads_diff}"; + } + else + { + $new_stats['numthreads'] = "{$threads_diff}"; + } + } + + if(array_key_exists('unapprovedthreads', $update_query)) + { + $unapprovedthreads_diff = $update_query['unapprovedthreads'] - $forum['unapprovedthreads']; + if($unapprovedthreads_diff > -1) + { + $new_stats['numunapprovedthreads'] = "+{$unapprovedthreads_diff}"; + } + else + { + $new_stats['numunapprovedthreads'] = "{$unapprovedthreads_diff}"; + } + } + + if(array_key_exists('posts', $update_query)) + { + $posts_diff = $update_query['posts'] - $forum['posts']; + if($posts_diff > -1) + { + $new_stats['numposts'] = "+{$posts_diff}"; + } + else + { + $new_stats['numposts'] = "{$posts_diff}"; + } + } + + if(array_key_exists('unapprovedposts', $update_query)) + { + $unapprovedposts_diff = $update_query['unapprovedposts'] - $forum['unapprovedposts']; + if($unapprovedposts_diff > -1) + { + $new_stats['numunapprovedposts'] = "+{$unapprovedposts_diff}"; + } + else + { + $new_stats['numunapprovedposts'] = "{$unapprovedposts_diff}"; + } + } + + if(array_key_exists('deletedposts', $update_query)) + { + $deletedposts_diff = $update_query['deletedposts'] - $forum['deletedposts']; + if($deletedposts_diff > -1) + { + $new_stats['numdeletedposts'] = "+{$deletedposts_diff}"; + } + else + { + $new_stats['numdeletedposts'] = "{$deletedposts_diff}"; + } + } + + if(array_key_exists('deletedthreads', $update_query)) + { + $deletedthreads_diff = $update_query['deletedthreads'] - $forum['deletedthreads']; + if($deletedthreads_diff > -1) + { + $new_stats['numdeletedthreads'] = "+{$deletedthreads_diff}"; + } + else + { + $new_stats['numdeletedthreads'] = "{$deletedthreads_diff}"; + } + } + + if(!empty($new_stats)) + { + update_stats($new_stats); + } +} + +/** + * Update the last post information for a specific forum + * + * @param int The forum ID + */ +function update_forum_lastpost($fid) +{ + global $db; + + // Fetch the last post for this forum + $query = $db->query(" + SELECT tid, lastpost, lastposter, lastposteruid, subject + FROM ".TABLE_PREFIX."threads + WHERE fid='{$fid}' AND visible='1' AND closed NOT LIKE 'moved|%' + ORDER BY lastpost DESC + LIMIT 0, 1 + "); + $lastpost = $db->fetch_array($query); + + $updated_forum = array( + "lastpost" => (int)$lastpost['lastpost'], + "lastposter" => $db->escape_string($lastpost['lastposter']), + "lastposteruid" => (int)$lastpost['lastposteruid'], + "lastposttid" => (int)$lastpost['tid'], + "lastpostsubject" => $db->escape_string($lastpost['subject']) + ); + + $db->update_query("forums", $updated_forum, "fid='{$fid}'"); +} + +/** + * Updates the thread counters with a specific value (or addition/subtraction of the previous value) + * + * @param int The thread ID + * @param array Array of items being updated (replies, unapprovedposts, deletedposts, attachmentcount) and their value (ex, 1, +1, -1) + */ +function update_thread_counters($tid, $changes=array()) +{ + global $db; + + $update_query = array(); + $tid = (int)$tid; + + $counters = array('replies', 'unapprovedposts', 'attachmentcount', 'deletedposts', 'attachmentcount'); + + // Fetch above counters for this thread + $query = $db->simple_select("threads", implode(",", $counters), "tid='{$tid}'"); + $thread = $db->fetch_array($query); + + foreach($counters as $counter) + { + if(array_key_exists($counter, $changes)) + { + if(substr($changes[$counter], 0, 2) == "+-") + { + $changes[$counter] = substr($changes[$counter], 1); + } + // Adding or subtracting from previous value? + if(substr($changes[$counter], 0, 1) == "+" || substr($changes[$counter], 0, 1) == "-") + { + if((int)$changes[$counter] != 0) + { + $update_query[$counter] = $thread[$counter] + $changes[$counter]; + } + } + else + { + $update_query[$counter] = $changes[$counter]; + } + + // Less than 0? That's bad + if(isset($update_query[$counter]) && $update_query[$counter] < 0) + { + $update_query[$counter] = 0; + } + } + } + + $db->free_result($query); + + // Only update if we're actually doing something + if(count($update_query) > 0) + { + $db->update_query("threads", $update_query, "tid='{$tid}'"); + } +} + +/** + * Update the first post and lastpost data for a specific thread + * + * @param int The thread ID + */ +function update_thread_data($tid) +{ + global $db; + + $thread = get_thread($tid); + + // If this is a moved thread marker, don't update it - we need it to stay as it is + if(strpos($thread['closed'], 'moved|') !== false) + { + return false; + } + + $query = $db->query(" + SELECT u.uid, u.username, p.username AS postusername, p.dateline + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) + WHERE p.tid='$tid' AND p.visible='1' + ORDER BY p.dateline DESC + LIMIT 1" + ); + $lastpost = $db->fetch_array($query); + + $db->free_result($query); + + $query = $db->query(" + SELECT u.uid, u.username, p.pid, p.username AS postusername, p.dateline + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) + WHERE p.tid='$tid' + ORDER BY p.dateline ASC + LIMIT 1 + "); + $firstpost = $db->fetch_array($query); + + $db->free_result($query); + + if(empty($firstpost['username'])) + { + $firstpost['username'] = $firstpost['postusername']; + } + + if(empty($lastpost['username'])) + { + $lastpost['username'] = $lastpost['postusername']; + } + + if(empty($lastpost['dateline'])) + { + $lastpost['username'] = $firstpost['username']; + $lastpost['uid'] = $firstpost['uid']; + $lastpost['dateline'] = $firstpost['dateline']; + } + + $lastpost['username'] = $db->escape_string($lastpost['username']); + $firstpost['username'] = $db->escape_string($firstpost['username']); + + $update_array = array( + 'firstpost' => (int)$firstpost['pid'], + 'username' => $firstpost['username'], + 'uid' => (int)$firstpost['uid'], + 'dateline' => (int)$firstpost['dateline'], + 'lastpost' => (int)$lastpost['dateline'], + 'lastposter' => $lastpost['username'], + 'lastposteruid' => (int)$lastpost['uid'], + ); + $db->update_query("threads", $update_array, "tid='{$tid}'"); +} + +/** + * Updates the user counters with a specific value (or addition/subtraction of the previous value) + * + * @param int The user ID + * @param array Array of items being updated (postnum, threadnum) and their value (ex, 1, +1, -1) + */ +function update_user_counters($uid, $changes=array()) +{ + global $db; + + $update_query = array(); + + $counters = array('postnum', 'threadnum'); + $uid = (int)$uid; + + // Fetch above counters for this user + $query = $db->simple_select("users", implode(",", $counters), "uid='{$uid}'"); + $user = $db->fetch_array($query); + + foreach($counters as $counter) + { + if(array_key_exists($counter, $changes)) + { + if(substr($changes[$counter], 0, 2) == "+-") + { + $changes[$counter] = substr($changes[$counter], 1); + } + // Adding or subtracting from previous value? + if(substr($changes[$counter], 0, 1) == "+" || substr($changes[$counter], 0, 1) == "-") + { + if((int)$changes[$counter] != 0) + { + $update_query[$counter] = $user[$counter] + $changes[$counter]; + } + } + else + { + $update_query[$counter] = $changes[$counter]; + } + + // Less than 0? That's bad + if(isset($update_query[$counter]) && $update_query[$counter] < 0) + { + $update_query[$counter] = 0; + } + } + } + + $db->free_result($query); + + // Only update if we're actually doing something + if(count($update_query) > 0) + { + $db->update_query("users", $update_query, "uid='{$uid}'"); + } +} + +/** + * Deletes a thread from the database + * + * @param int The thread ID + */ +function delete_thread($tid) +{ + global $moderation; + + if(!is_object($moderation)) + { + require_once MYBB_ROOT."inc/class_moderation.php"; + $moderation = new Moderation; + } + + return $moderation->delete_thread($tid); +} + +/** + * Deletes a post from the database + * + * @param int The thread ID + */ +function delete_post($pid) +{ + global $moderation; + + if(!is_object($moderation)) + { + require_once MYBB_ROOT."inc/class_moderation.php"; + $moderation = new Moderation; + } + + return $moderation->delete_post($pid); +} + +/** + * Builds a forum jump menu + * + * @param int The parent forum to start with + * @param int The selected item ID + * @param int If we need to add select boxes to this cal or not + * @param int The current depth of forums we're at + * @param int Whether or not to show extra items such as User CP, Forum home + * @param boolean Ignore the showinjump setting and show all forums (for moderation pages) + * @param array Array of permissions + * @param string The name of the forum jump + * @return string Forum jump items + */ +function build_forum_jump($pid="0", $selitem="", $addselect="1", $depth="", $showextras="1", $showall=false, $permissions="", $name="fid") +{ + global $forum_cache, $jumpfcache, $permissioncache, $mybb, $selecteddone, $forumjump, $forumjumpbits, $gobutton, $theme, $templates, $lang; + + $pid = (int)$pid; + $jumpsel['default'] = ''; + + if($permissions) + { + $permissions = $mybb->usergroup; + } + + if(!is_array($jumpfcache)) + { + if(!is_array($forum_cache)) + { + cache_forums(); + } + + foreach($forum_cache as $fid => $forum) + { + if($forum['active'] != 0) + { + $jumpfcache[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum; + } + } + } + + if(!is_array($permissioncache)) + { + $permissioncache = forum_permissions(); + } + + if(isset($jumpfcache[$pid]) && is_array($jumpfcache[$pid])) + { + foreach($jumpfcache[$pid] as $main) + { + foreach($main as $forum) + { + $perms = $permissioncache[$forum['fid']]; + + if($forum['fid'] != "0" && ($perms['canview'] != 0 || $mybb->settings['hideprivateforums'] == 0) && $forum['linkto'] == '' && ($forum['showinjump'] != 0 || $showall == true)) + { + $optionselected = ""; + + if($selitem == $forum['fid']) + { + $optionselected = "selected=\"selected\""; + $selecteddone = 1; + } + + $forum['name'] = htmlspecialchars_uni(strip_tags($forum['name'])); + + eval("\$forumjumpbits .= \"".$templates->get("forumjump_bit")."\";"); + + if($forum_cache[$forum['fid']]) + { + $newdepth = $depth."--"; + $forumjumpbits .= build_forum_jump($forum['fid'], $selitem, 0, $newdepth, $showextras, $showall); + } + } + } + } + } + + if($addselect) + { + if(!$selecteddone) + { + if(!$selitem) + { + $selitem = "default"; + } + + $jumpsel[$selitem] = 'selected="selected"'; + } + + if($showextras == 0) + { + $template = "special"; + } + else + { + $template = "advanced"; + + if(strpos(FORUM_URL, '.html') !== false) + { + $forum_link = "'".str_replace('{fid}', "'+this.options[this.selectedIndex].value+'", FORUM_URL)."'"; + } + else + { + $forum_link = "'".str_replace('{fid}', "'+this.options[this.selectedIndex].value", FORUM_URL); + } + } + + eval("\$forumjump = \"".$templates->get("forumjump_".$template)."\";"); + } + + return $forumjump; +} + +/** + * Returns the extension of a file. + * + * @param string The filename. + * @return string The extension of the file. + */ +function get_extension($file) +{ + return my_strtolower(my_substr(strrchr($file, "."), 1)); +} + +/** + * Generates a random string. + * + * @param int The length of the string to generate. + * @return string The random string. + */ +function random_str($length="8") +{ + $set = array("a","A","b","B","c","C","d","D","e","E","f","F","g","G","h","H","i","I","j","J","k","K","l","L","m","M","n","N","o","O","p","P","q","Q","r","R","s","S","t","T","u","U","v","V","w","W","x","X","y","Y","z","Z","1","2","3","4","5","6","7","8","9"); + $str = ''; + + for($i = 1; $i <= $length; ++$i) + { + $ch = my_rand(0, count($set)-1); + $str .= $set[$ch]; + } + + return $str; +} + +/** + * Formats a username based on their display group + * + * @param string The username + * @param int The usergroup for the user (if not specified, will be fetched) + * @param int The display group for the user (if not specified, will be fetched) + * @return string The formatted username + */ +function format_name($username, $usergroup, $displaygroup="") +{ + global $groupscache, $cache; + + if(!is_array($groupscache)) + { + $groupscache = $cache->read("usergroups"); + } + + if($displaygroup != 0) + { + $usergroup = $displaygroup; + } + + $ugroup = $groupscache[$usergroup]; + $format = $ugroup['namestyle']; + $userin = substr_count($format, "{username}"); + + if($userin == 0) + { + $format = "{username}"; + } + + $format = stripslashes($format); + + return str_replace("{username}", $username, $format); +} + +/** + * Formats an avatar to a certain dimension + * + * @param string The avatar file name + * @param string Dimensions of the avatar, width x height (e.g. 44|44) + * @param string The maximum dimensions of the formatted avatar + * @return array Information for the formatted avatar + */ +function format_avatar($avatar, $dimensions = '', $max_dimensions = '') +{ + global $mybb; + static $avatars; + + if(!isset($avatars)) + { + $avatars = array(); + } + + if(!$avatar) + { + // Default avatar + $avatar = $mybb->settings['useravatar']; + $dimensions = $mybb->settings['useravatardims']; + } + + if(isset($avatars[$avatar])) + { + return $avatars[$avatar]; + } + + if(!$max_dimensions) + { + $max_dimensions = $mybb->settings['maxavatardims']; + } + + $avatar_width_height = ''; + + if($dimensions) + { + $dimensions = explode("|", $dimensions); + + if($dimensions[0] && $dimensions[1]) + { + list($max_width, $max_height) = explode('x', $max_dimensions); + + if($dimensions[0] > $max_width || $dimensions[1] > $max_height) + { + require_once MYBB_ROOT."inc/functions_image.php"; + $scaled_dimensions = scale_image($dimensions[0], $dimensions[1], $max_width, $max_height); + $avatar_width_height = "width=\"{$scaled_dimensions['width']}\" height=\"{$scaled_dimensions['height']}\""; + } + else + { + $avatar_width_height = "width=\"{$dimensions[0]}\" height=\"{$dimensions[1]}\""; + } + } + } + + $avatars[$avatar] = array( + 'image' => $mybb->get_asset_url($avatar), + 'width_height' => $avatar_width_height + ); + + return $avatars[$avatar]; +} + +/** + * Build the javascript based MyCode inserter. + * + * @param string $bind The ID of the textarea to bind to. Defaults to "message". + * @param bool $smilies Whether to include smilies. Defaults to true. + * + * @return string The MyCode inserter + */ +function build_mycode_inserter($bind="message", $smilies = true) +{ + global $db, $mybb, $theme, $templates, $lang, $plugins, $smiliecache, $cache; + + if($mybb->settings['bbcodeinserter'] != 0) + { + $editor_lang_strings = array( + "editor_bold" => "Bold", + "editor_italic" => "Italic", + "editor_underline" => "Underline", + "editor_strikethrough" => "Strikethrough", + "editor_subscript" => "Subscript", + "editor_superscript" => "Superscript", + "editor_alignleft" => "Align left", + "editor_center" => "Center", + "editor_alignright" => "Align right", + "editor_justify" => "Justify", + "editor_fontname" => "Font Name", + "editor_fontsize" => "Font Size", + "editor_fontcolor" => "Font Color", + "editor_removeformatting" => "Remove Formatting", + "editor_cut" => "Cut", + "editor_cutnosupport" => "Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X", + "editor_copy" => "Copy", + "editor_copynosupport" => "Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C", + "editor_paste" => "Paste", + "editor_pastenosupport" => "Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V", + "editor_pasteentertext" => "Paste your text inside the following box:", + "editor_pastetext" => "PasteText", + "editor_numlist" => "Numbered list", + "editor_bullist" => "Bullet list", + "editor_undo" => "Undo", + "editor_redo" => "Redo", + "editor_rows" => "Rows:", + "editor_cols" => "Cols:", + "editor_inserttable" => "Insert a table", + "editor_inserthr" => "Insert a horizontal rule", + "editor_code" => "Code", + "editor_width" => "Width (optional):", + "editor_height" => "Height (optional):", + "editor_insertimg" => "Insert an image", + "editor_email" => "E-mail:", + "editor_insertemail" => "Insert an email", + "editor_url" => "URL:", + "editor_insertlink" => "Insert a link", + "editor_unlink" => "Unlink", + "editor_more" => "More", + "editor_insertemoticon" => "Insert an emoticon", + "editor_videourl" => "Video URL:", + "editor_videotype" => "Video Type:", + "editor_insert" => "Insert", + "editor_insertyoutubevideo" => "Insert a YouTube video", + "editor_currentdate" => "Insert current date", + "editor_currenttime" => "Insert current time", + "editor_print" => "Print", + "editor_viewsource" => "View source", + "editor_description" => "Description (optional):", + "editor_enterimgurl" => "Enter the image URL:", + "editor_enteremail" => "Enter the e-mail address:", + "editor_enterdisplayedtext" => "Enter the displayed text:", + "editor_enterurl" => "Enter URL:", + "editor_enteryoutubeurl" => "Enter the YouTube video URL or ID:", + "editor_insertquote" => "Insert a Quote", + "editor_invalidyoutube" => "Invalid YouTube video", + "editor_dailymotion" => "Dailymotion", + "editor_metacafe" => "MetaCafe", + "editor_veoh" => "Veoh", + "editor_vimeo" => "Vimeo", + "editor_youtube" => "Youtube", + "editor_facebook" => "Facebook", + "editor_liveleak" => "LiveLeak", + "editor_insertvideo" => "Insert a video", + "editor_php" => "PHP", + "editor_maximize" => "Maximize" + ); + $editor_language = "(function ($) {\n$.sceditor.locale[\"mybblang\"] = {\n"; + + $editor_lang_strings = $plugins->run_hooks("mycode_add_codebuttons", $editor_lang_strings); + + $editor_languages_count = count($editor_lang_strings); + $i = 0; + foreach($editor_lang_strings as $lang_string => $key) + { + $i++; + $js_lang_string = str_replace("\"", "\\\"", $key); + $string = str_replace("\"", "\\\"", $lang->$lang_string); + $editor_language .= "\t\"{$js_lang_string}\": \"{$string}\""; + + if($i < $editor_languages_count) + { + $editor_language .= ","; + } + + $editor_language .= "\n"; + } + + $editor_language .= "}})(jQuery);"; + + if(defined("IN_ADMINCP")) + { + global $page; + $codeinsert = $page->build_codebuttons_editor($bind, $editor_language, $smilies); + } + else + { + // Smilies + $emoticon = ""; + $emoticons_enabled = "false"; + if($smilies && $mybb->settings['smilieinserter'] != 0 && $mybb->settings['smilieinsertercols'] && $mybb->settings['smilieinsertertot']) + { + $emoticon = ",emoticon"; + $emoticons_enabled = "true"; + + if(!$smiliecache) + { + if(!isset($smilie_cache) || !is_array($smilie_cache)) + { + $smilie_cache = $cache->read("smilies"); + } + foreach($smilie_cache as $smilie) + { + if($smilie['showclickable'] != 0) + { + $smilie['image'] = str_replace("{theme}", $theme['imgdir'], $smilie['image']); + $smiliecache[$smilie['sid']] = $smilie; + } + } + } + + unset($smilie); + + if(is_array($smiliecache)) + { + reset($smiliecache); + + $dropdownsmilies = $moresmilies = $hiddensmilies = ""; + $i = 0; + + foreach($smiliecache as $smilie) + { + $finds = explode("\n", $smilie['find']); + $finds_count = count($finds); + + // Only show the first text to replace in the box + $smilie['find'] = $finds[0]; + + $find = htmlspecialchars_uni($smilie['find']); + $image = $mybb->get_asset_url($smilie['image']); + $image = htmlspecialchars_uni($image); + if($i < $mybb->settings['smilieinsertertot']) + { + $dropdownsmilies .= '"'.$find.'": "'.$image.'",'; + } + else + { + $moresmilies .= '"'.$find.'": "'.$image.'",'; + } + + for($j = 1; $j < $finds_count; ++$j) + { + $find = htmlspecialchars_uni($finds[$j]); + $hiddensmilies .= '"'.$find.'": "'.$image.'",'; + } + ++$i; + } + } + } + + $basic1 = $basic2 = $align = $font = $size = $color = $removeformat = $email = $link = $list = $code = $sourcemode = ""; + + if($mybb->settings['allowbasicmycode'] == 1) + { + $basic1 = "bold,italic,underline,strike|"; + $basic2 = "horizontalrule,"; + } + + if($mybb->settings['allowalignmycode'] == 1) + { + $align = "left,center,right,justify|"; + } + + if($mybb->settings['allowfontmycode'] == 1) + { + $font = "font,"; + } + + if($mybb->settings['allowsizemycode'] == 1) + { + $size = "size,"; + } + + if($mybb->settings['allowcolormycode'] == 1) + { + $color = "color,"; + } + + if($mybb->settings['allowfontmycode'] == 1 || $mybb->settings['allowsizemycode'] == 1 || $mybb->settings['allowcolormycode'] == 1) + { + $removeformat = "removeformat|"; + } + + if($mybb->settings['allowemailmycode'] == 1) + { + $email = "email,"; + } + + if($mybb->settings['allowlinkmycode'] == 1) + { + $link = "link,unlink"; + } + + if($mybb->settings['allowlistmycode'] == 1) + { + $list = "bulletlist,orderedlist|"; + } + + if($mybb->settings['allowcodemycode'] == 1) + { + $code = "code,php,"; + } + + if($mybb->user['sourceeditor'] == 1) + { + $sourcemode = "MyBBEditor.sourceMode(true);"; + } + + eval("\$codeinsert = \"".$templates->get("codebuttons")."\";"); + } + } + + return $codeinsert; +} + +/** + * Build the javascript clickable smilie inserter + * + * @return string The clickable smilies list + */ +function build_clickable_smilies() +{ + global $cache, $smiliecache, $theme, $templates, $lang, $mybb, $smiliecount; + + if($mybb->settings['smilieinserter'] != 0 && $mybb->settings['smilieinsertercols'] && $mybb->settings['smilieinsertertot']) + { + if(!$smiliecount) + { + $smilie_cache = $cache->read("smilies"); + $smiliecount = count($smilie_cache); + } + + if(!$smiliecache) + { + if(!is_array($smilie_cache)) + { + $smilie_cache = $cache->read("smilies"); + } + foreach($smilie_cache as $smilie) + { + if($smilie['showclickable'] != 0) + { + $smilie['image'] = str_replace("{theme}", $theme['imgdir'], $smilie['image']); + $smiliecache[$smilie['sid']] = $smilie; + } + } + } + + unset($smilie); + + if(is_array($smiliecache)) + { + reset($smiliecache); + + $getmore = ''; + if($mybb->settings['smilieinsertertot'] >= $smiliecount) + { + $mybb->settings['smilieinsertertot'] = $smiliecount; + } + else if($mybb->settings['smilieinsertertot'] < $smiliecount) + { + $smiliecount = $mybb->settings['smilieinsertertot']; + eval("\$getmore = \"".$templates->get("smilieinsert_getmore")."\";"); + } + + $smilies = ""; + $counter = 0; + $i = 0; + + $extra_class = ''; + foreach($smiliecache as $smilie) + { + if($i < $mybb->settings['smilieinsertertot']) + { + if($counter == 0) + { + $smilies .= "\n"; + } + + // Only show the first text to replace in the box + $temp = explode("\n", $smilie['find']); // assign to temporary variable for php 5.3 compatibility + $smilie['find'] = $temp[0]; + + $find = htmlspecialchars_uni($smilie['find']); + + $onclick = ' onclick="MyBBEditor.insertText(\' '.$smilie['find'].' \');"'; + $extra_class = ' smilie_pointer'; + eval('$smilie = "'.$templates->get('smilie', 1, 0).'";'); + eval("\$smilies .= \"".$templates->get("smilieinsert_smilie")."\";"); + ++$i; + ++$counter; + + if($counter == $mybb->settings['smilieinsertercols']) + { + $counter = 0; + $smilies .= "\n"; + } + } + } + + if($counter != 0) + { + $colspan = $mybb->settings['smilieinsertercols'] - $counter; + $smilies .= " \n\n"; + } + + eval("\$clickablesmilies = \"".$templates->get("smilieinsert")."\";"); + } + else + { + $clickablesmilies = ""; + } + } + else + { + $clickablesmilies = ""; + } + + return $clickablesmilies; +} + +/** + * Builds thread prefixes and returns a selected prefix (or all) + * + * @param int The prefix ID (0 to return all) + * @return array The thread prefix's values (or all thread prefixes) + */ +function build_prefixes($pid=0) +{ + global $cache; + static $prefixes_cache; + + if(is_array($prefixes_cache)) + { + if($pid > 0 && is_array($prefixes_cache[$pid])) + { + return $prefixes_cache[$pid]; + } + + return $prefixes_cache; + } + + $prefix_cache = $cache->read("threadprefixes"); + + if(!is_array($prefix_cache)) + { + // No cache + $prefix_cache = $cache->read("threadprefixes", true); + + if(!is_array($prefix_cache)) + { + return array(); + } + } + + $prefixes_cache = array(); + foreach($prefix_cache as $prefix) + { + $prefixes_cache[$prefix['pid']] = $prefix; + } + + if($pid != 0 && is_array($prefixes_cache[$pid])) + { + return $prefixes_cache[$pid]; + } + else if(!empty($prefixes_cache)) + { + return $prefixes_cache; + } + + return false; +} + +/** + * Build the thread prefix selection menu + * + * @param mixed The forum ID (integer ID or string all) + * @param mixed The selected prefix ID (integer ID or string any) + * @param int Allow multiple prefix selection + * @return string The thread prefix selection menu + */ +function build_prefix_select($fid, $selected_pid=0, $multiple=0) +{ + global $cache, $db, $lang, $mybb, $templates; + + if($fid != 'all') + { + $fid = (int)$fid; + } + + $prefix_cache = build_prefixes(0); + if(empty($prefix_cache)) + { + return false; // We've got no prefixes to show + } + + $groups = array($mybb->user['usergroup']); + if($mybb->user['additionalgroups']) + { + $exp = explode(",", $mybb->user['additionalgroups']); + + foreach($exp as $group) + { + $groups[] = $group; + } + } + + // Go through each of our prefixes and decide which ones we can use + $prefixes = array(); + foreach($prefix_cache as $prefix) + { + if($fid != "all" && $prefix['forums'] != "-1") + { + // Decide whether this prefix can be used in our forum + $forums = explode(",", $prefix['forums']); + + if(!in_array($fid, $forums)) + { + // This prefix is not in our forum list + continue; + } + } + + if($prefix['groups'] != "-1") + { + $prefix_groups = explode(",", $prefix['groups']); + + foreach($groups as $group) + { + if(in_array($group, $prefix_groups) && !isset($prefixes[$prefix['pid']])) + { + // Our group can use this prefix! + $prefixes[$prefix['pid']] = $prefix; + } + } + } + else + { + // This prefix is for anybody to use... + $prefixes[$prefix['pid']] = $prefix; + } + } + + if(empty($prefixes)) + { + return false; + } + + $prefixselect = $prefixselect_prefix = ''; + + if($multiple == 1) + { + $any_selected = ""; + if($selected_pid == 'any') + { + $any_selected = " selected=\"selected\""; + } + } + + $default_selected = ""; + if(((int)$selected_pid == 0) && $selected_pid != 'any') + { + $default_selected = " selected=\"selected\""; + } + + foreach($prefixes as $prefix) + { + $selected = ""; + if($prefix['pid'] == $selected_pid) + { + $selected = " selected=\"selected\""; + } + + $prefix['prefix'] = htmlspecialchars_uni($prefix['prefix']); + eval("\$prefixselect_prefix .= \"".$templates->get("post_prefixselect_prefix")."\";"); + } + + if($multiple != 0) + { + eval("\$prefixselect = \"".$templates->get("post_prefixselect_multiple")."\";"); + } + else + { + eval("\$prefixselect = \"".$templates->get("post_prefixselect_single")."\";"); + } + + return $prefixselect; +} + +/** + * Build the thread prefix selection menu for a forum + * + * @param mixed The forum ID (integer ID) + * @param mixed The selected prefix ID (integer ID) + */ +function build_forum_prefix_select($fid, $selected_pid=0) +{ + global $cache, $db, $lang, $mybb, $templates; + + $fid = (int)$fid; + + $prefix_cache = build_prefixes(0); + if(empty($prefix_cache)) + { + return false; // We've got no prefixes to show + } + + // Go through each of our prefixes and decide which ones we can use + $prefixes = array(); + foreach($prefix_cache as $prefix) + { + if($prefix['forums'] != "-1") + { + // Decide whether this prefix can be used in our forum + $forums = explode(",", $prefix['forums']); + + if(in_array($fid, $forums)) + { + // This forum can use this prefix! + $prefixes[$prefix['pid']] = $prefix; + } + } + else + { + // This prefix is for anybody to use... + $prefixes[$prefix['pid']] = $prefix; + } + } + + if(empty($prefixes)) + { + return false; + } + + $default_selected = array(); + $selected_pid = (int)$selected_pid; + + if($selected_pid == 0) + { + $default_selected['all'] = ' selected="selected"'; + } + else if($selected_pid == -1) + { + $default_selected['none'] = ' selected="selected"'; + } + else if($selected_pid == -2) + { + $default_selected['any'] = ' selected="selected"'; + } + + foreach($prefixes as $prefix) + { + $selected = ''; + if($prefix['pid'] == $selected_pid) + { + $selected = ' selected="selected"'; + } + + $prefix['prefix'] = htmlspecialchars_uni($prefix['prefix']); + eval('$prefixselect_prefix .= "'.$templates->get("forumdisplay_threadlist_prefixes_prefix").'";'); + } + + eval('$prefixselect = "'.$templates->get("forumdisplay_threadlist_prefixes").'";'); + return $prefixselect; +} + +/** + * Gzip encodes text to a specified level + * + * @param string The string to encode + * @param int The level (1-9) to encode at + * @return string The encoded string + */ +function gzip_encode($contents, $level=1) +{ + if(function_exists("gzcompress") && function_exists("crc32") && !headers_sent() && !(ini_get('output_buffering') && my_strpos(' '.ini_get('output_handler'), 'ob_gzhandler'))) + { + $httpaccept_encoding = ''; + + if(isset($_SERVER['HTTP_ACCEPT_ENCODING'])) + { + $httpaccept_encoding = $_SERVER['HTTP_ACCEPT_ENCODING']; + } + + if(my_strpos(" ".$httpaccept_encoding, "x-gzip")) + { + $encoding = "x-gzip"; + } + + if(my_strpos(" ".$httpaccept_encoding, "gzip")) + { + $encoding = "gzip"; + } + + if(isset($encoding)) + { + header("Content-Encoding: $encoding"); + + if(function_exists("gzencode")) + { + $contents = gzencode($contents, $level); + } + else + { + $size = strlen($contents); + $crc = crc32($contents); + $gzdata = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff"; + $gzdata .= my_substr(gzcompress($contents, $level), 2, -4); + $gzdata .= pack("V", $crc); + $gzdata .= pack("V", $size); + $contents = $gzdata; + } + } + } + + return $contents; +} + +/** + * Log the actions of a moderator. + * + * @param array The data of the moderator's action. + * @param string The message to enter for the action the moderator performed. + */ +function log_moderator_action($data, $action="") +{ + global $mybb, $db, $session; + + $fid = 0; + if(isset($data['fid'])) + { + $fid = (int)$data['fid']; + unset($data['fid']); + } + + $tid = 0; + if(isset($data['tid'])) + { + $tid = (int)$data['tid']; + unset($data['tid']); + } + + $pid = 0; + if(isset($data['pid'])) + { + $pid = (int)$data['pid']; + unset($data['pid']); + } + + // Any remaining extra data - we serialize and insert in to its own column + if(is_array($data)) + { + $data = serialize($data); + } + + $sql_array = array( + "uid" => (int)$mybb->user['uid'], + "dateline" => TIME_NOW, + "fid" => (int)$fid, + "tid" => $tid, + "pid" => $pid, + "action" => $db->escape_string($action), + "data" => $db->escape_string($data), + "ipaddress" => $db->escape_binary($session->packedip) + ); + $db->insert_query("moderatorlog", $sql_array); +} + +/** + * Get the formatted reputation for a user. + * + * @param int The reputation value + * @param int The user ID (if not specified, the generated reputation will not be a link) + * @return string The formatted repuation + */ +function get_reputation($reputation, $uid=0) +{ + global $theme, $templates; + + $display_reputation = $reputation_class = ''; + if($reputation < 0) + { + $reputation_class = "reputation_negative"; + } + elseif($reputation > 0) + { + $reputation_class = "reputation_positive"; + } + else + { + $reputation_class = "reputation_neutral"; + } + + if($uid != 0) + { + eval("\$display_reputation = \"".$templates->get("postbit_reputation_formatted_link")."\";"); + } + else + { + eval("\$display_reputation = \"".$templates->get("postbit_reputation_formatted")."\";"); + } + + return $display_reputation; +} + +/** + * Fetch a color coded version of a warning level (based on it's percentage) + * + * @param int The warning level (percentage of 100) + * @return string Formatted warning level + */ +function get_colored_warning_level($level) +{ + global $templates; + + $warning_class = ''; + if($level >= 80) + { + $warning_class = "high_warning"; + } + else if($level >= 50) + { + $warning_class = "moderate_warning"; + } + else if($level >= 25) + { + $warning_class = "low_warning"; + } + else + { + $warning_class = "normal_warning"; + } + + eval("\$level = \"".$templates->get("postbit_warninglevel_formatted")."\";"); + return $level; +} + +/** + * Fetch the IP address of the current user. + * + * @return string The IP address. + */ +function get_ip() +{ + global $mybb, $plugins; + + $ip = $_SERVER['REMOTE_ADDR']; + + if($mybb->settings['ip_forwarded_check']) + { + $addresses = array(); + + if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) + { + $addresses = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); + } + elseif(isset($_SERVER['HTTP_X_REAL_IP'])) + { + $addresses = explode(',', $_SERVER['HTTP_X_REAL_IP']); + } + + if(is_array($addresses)) + { + foreach($addresses as $val) + { + $val = trim($val); + // Validate IP address and exclude private addresses + if(my_inet_ntop(my_inet_pton($val)) == $val && !preg_match("#^(10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.|fe80:|fe[c-f][0-f]:|f[c-d][0-f]{2}:)#", $val)) + { + $ip = $val; + break; + } + } + } + } + + if(!$ip) + { + if(isset($_SERVER['HTTP_CLIENT_IP'])) + { + $ip = $_SERVER['HTTP_CLIENT_IP']; + } + } + + if($plugins) + { + $ip_array = array("ip" => &$ip); // Used for backwards compatibility on this hook with the updated run_hooks() function. + $plugins->run_hooks("get_ip", $ip_array); + } + + return $ip; +} + +/** + * Fetch the friendly size (GB, MB, KB, B) for a specified file size. + * + * @param int The size in bytes + * @return string The friendly file size + */ +function get_friendly_size($size) +{ + global $lang; + + if(!is_numeric($size)) + { + return $lang->na; + } + + // Yottabyte (1024 Zettabytes) + if($size >= 1208925819614629174706176) + { + $size = my_number_format(round(($size / 1208925819614629174706176), 2))." ".$lang->size_yb; + } + // Zetabyte (1024 Exabytes) + elseif($size >= 1180591620717411303424) + { + $size = my_number_format(round(($size / 1180591620717411303424), 2))." ".$lang->size_zb; + } + // Exabyte (1024 Petabytes) + elseif($size >= 1152921504606846976) + { + $size = my_number_format(round(($size / 1152921504606846976), 2))." ".$lang->size_eb; + } + // Petabyte (1024 Terabytes) + elseif($size >= 1125899906842624) + { + $size = my_number_format(round(($size / 1125899906842624), 2))." ".$lang->size_pb; + } + // Terabyte (1024 Gigabytes) + elseif($size >= 1099511627776) + { + $size = my_number_format(round(($size / 1099511627776), 2))." ".$lang->size_tb; + } + // Gigabyte (1024 Megabytes) + elseif($size >= 1073741824) + { + $size = my_number_format(round(($size / 1073741824), 2))." ".$lang->size_gb; + } + // Megabyte (1024 Kilobytes) + elseif($size >= 1048576) + { + $size = my_number_format(round(($size / 1048576), 2))." ".$lang->size_mb; + } + // Kilobyte (1024 bytes) + elseif($size >= 1024) + { + $size = my_number_format(round(($size / 1024), 2))." ".$lang->size_kb; + } + elseif($size == 0) + { + $size = "0 ".$lang->size_bytes; + } + else + { + $size = my_number_format($size)." ".$lang->size_bytes; + } + + return $size; +} + +/** + * Format a decimal number in to microseconds, milliseconds, or seconds. + * + * @param int The time in microseconds + * @return string The friendly time duration + */ +function format_time_duration($time) +{ + global $lang; + + if(!is_numeric($time)) + { + return $lang->na; + } + + if(round(1000000 * $time, 2) < 1000) + { + $time = number_format(round(1000000 * $time, 2))." μs"; + } + elseif(round(1000000 * $time, 2) >= 1000 && round(1000000 * $time, 2) < 1000000) + { + $time = number_format(round((1000 * $time), 2))." ms"; + } + else + { + $time = round($time, 3)." seconds"; + } + + return $time; +} + +/** + * Get the attachment icon for a specific file extension + * + * @param string The file extension + * @return string The attachment icon + */ +function get_attachment_icon($ext) +{ + global $cache, $attachtypes, $theme, $templates, $lang; + + if(!$attachtypes) + { + $attachtypes = $cache->read("attachtypes"); + } + + $ext = my_strtolower($ext); + + if($attachtypes[$ext]['icon']) + { + if(defined("IN_ADMINCP")) + { + $icon = str_replace("{theme}", "", $attachtypes[$ext]['icon']); + if(my_substr($icon, 0, 1) != "/" && my_substr($icon, 0, 7) != "http://") + { + $icon = "../".$icon; + } + } + elseif(defined("IN_PORTAL")) + { + global $change_dir; + $icon = $change_dir."/".str_replace("{theme}", $theme['imgdir'], $attachtypes[$ext]['icon']); + } + else + { + $icon = str_replace("{theme}", $theme['imgdir'], $attachtypes[$ext]['icon']); + } + + $name = htmlspecialchars_uni($attachtypes[$ext]['name']); + } + else + { + if(defined("IN_ADMINCP")) + { + $theme['imgdir'] = "../images"; + } + else if(defined("IN_PORTAL")) + { + global $change_dir; + $theme['imgdir'] = "{$change_dir}/images"; + } + + $icon = "{$theme['imgdir']}/attachtypes/unknown.png"; + $name = $lang->unknown; + } + + eval("\$attachment_icon = \"".$templates->get("attachment_icon")."\";"); + return $attachment_icon; +} + +/** + * Get a list of the unviewable forums for the current user + * + * @param boolean Set to true to only fetch those forums for which users can actually read a thread in. + * @return string Comma separated values list of the forum IDs which the user cannot view + */ +function get_unviewable_forums($only_readable_threads=false) +{ + global $forum_cache, $permissioncache, $mybb, $unviewable, $templates, $forumpass; + + if(!isset($permissions)) + { + $permissions = $mybb->usergroup; + } + + if(!is_array($forum_cache)) + { + cache_forums(); + } + + if(!is_array($permissioncache)) + { + $permissioncache = forum_permissions(); + } + + $unviewableforums = ''; + $password_forums = array(); + foreach($forum_cache as $fid => $forum) + { + if($permissioncache[$forum['fid']]) + { + $perms = $permissioncache[$forum['fid']]; + } + else + { + $perms = $mybb->usergroup; + } + + $pwverified = 1; + + if($forum['password'] != "") + { + if($mybb->cookies['forumpass'][$forum['fid']] != md5($mybb->user['uid'].$forum['password'])) + { + $pwverified = 0; + } + + $password_forums[$forum['fid']] = $forum['password']; + } + else + { + // Check parents for passwords + $parents = explode(",", $forum['parentlist']); + foreach($parents as $parent) + { + if(isset($password_forums[$parent]) && $mybb->cookies['forumpass'][$parent] != md5($mybb->user['uid'].$password_forums[$parent])) + { + $pwverified = 0; + } + } + } + + if($perms['canview'] == 0 || $pwverified == 0 || ($only_readable_threads == true && $perms['canviewthreads'] == 0)) + { + if($unviewableforums) + { + $unviewableforums .= ","; + } + + $unviewableforums .= "'".$forum['fid']."'"; + } + } + + if(isset($unviewableforums)) + { + return $unviewableforums; + } +} + +/** + * Fixes mktime for dates earlier than 1970 + * + * @param string The date format to use + * @param int The year of the date + * @return string The correct date format + */ +function fix_mktime($format, $year) +{ + // Our little work around for the date < 1970 thing. + // -2 idea provided by Matt Light (http://www.mephex.com) + $format = str_replace("Y", $year, $format); + $format = str_replace("y", my_substr($year, -2), $format); + + return $format; +} + +/** + * Build the breadcrumb navigation trail from the specified items + * + * @return The formatted breadcrumb navigation trail + */ +function build_breadcrumb() +{ + global $nav, $navbits, $templates, $theme, $lang, $mybb; + + eval("\$navsep = \"".$templates->get("nav_sep")."\";"); + + $i = 0; + $activesep = ''; + + if(is_array($navbits)) + { + reset($navbits); + foreach($navbits as $key => $navbit) + { + if(isset($navbits[$key+1])) + { + if(isset($navbits[$key+2])) + { + $sep = $navsep; + } + else + { + $sep = ""; + } + + $multipage = null; + $multipage_dropdown = null; + if(!empty($navbit['multipage'])) + { + if(!$mybb->settings['threadsperpage'] || (int)$mybb->settings['threadsperpage'] < 1) + { + $mybb->settings['threadsperpage'] = 20; + } + + $multipage = multipage($navbit['multipage']['num_threads'], $mybb->settings['threadsperpage'], $navbit['multipage']['current_page'], $navbit['multipage']['url'], true); + if($multipage) + { + ++$i; + eval("\$multipage_dropdown = \"".$templates->get("nav_dropdown")."\";"); + $sep = $multipage_dropdown.$sep; + } + } + + // Replace page 1 URLs + $navbit['url'] = str_replace("-page-1.html", ".html", $navbit['url']); + $navbit['url'] = preg_replace("/&page=1$/", "", $navbit['url']); + + eval("\$nav .= \"".$templates->get("nav_bit")."\";"); + } + } + } + + $activesep = ''; + $navsize = count($navbits); + $navbit = $navbits[$navsize-1]; + + if($nav) + { + eval("\$activesep = \"".$templates->get("nav_sep_active")."\";"); + } + + eval("\$activebit = \"".$templates->get("nav_bit_active")."\";"); + eval("\$donenav = \"".$templates->get("nav")."\";"); + + return $donenav; +} + +/** + * Add a breadcrumb menu item to the list. + * + * @param string The name of the item to add + * @param string The URL of the item to add + */ +function add_breadcrumb($name, $url="") +{ + global $navbits; + + $navsize = count($navbits); + $navbits[$navsize]['name'] = $name; + $navbits[$navsize]['url'] = $url; +} + +/** + * Build the forum breadcrumb nagiation (the navigation to a specific forum including all parent forums) + * + * @param int The forum ID to build the navigation for + * @param array The multipage drop down array of information + */ +function build_forum_breadcrumb($fid, $multipage=array()) +{ + global $pforumcache, $currentitem, $forum_cache, $navbits, $lang, $base_url, $archiveurl; + + if(!$pforumcache) + { + if(!is_array($forum_cache)) + { + cache_forums(); + } + + foreach($forum_cache as $key => $val) + { + $pforumcache[$val['fid']][$val['pid']] = $val; + } + } + + if(is_array($pforumcache[$fid])) + { + foreach($pforumcache[$fid] as $key => $forumnav) + { + if($fid == $forumnav['fid']) + { + if(!empty($pforumcache[$forumnav['pid']])) + { + build_forum_breadcrumb($forumnav['pid']); + } + + $navsize = count($navbits); + // Convert & to & + $navbits[$navsize]['name'] = preg_replace("#&(?!\#[0-9]+;)#si", "&", $forumnav['name']); + + if(defined("IN_ARCHIVE")) + { + // Set up link to forum in breadcrumb. + if($pforumcache[$fid][$forumnav['pid']]['type'] == 'f' || $pforumcache[$fid][$forumnav['pid']]['type'] == 'c') + { + $navbits[$navsize]['url'] = "{$base_url}forum-".$forumnav['fid'].".html"; + } + else + { + $navbits[$navsize]['url'] = $archiveurl."/index.php"; + } + } + elseif(!empty($multipage)) + { + $navbits[$navsize]['url'] = get_forum_link($forumnav['fid'], $multipage['current_page']); + + $navbits[$navsize]['multipage'] = $multipage; + $navbits[$navsize]['multipage']['url'] = str_replace('{fid}', $forumnav['fid'], FORUM_URL_PAGED); + } + else + { + $navbits[$navsize]['url'] = get_forum_link($forumnav['fid']); + } + } + } + } + + return 1; +} + +/** + * Resets the breadcrumb navigation to the first item, and clears the rest + */ +function reset_breadcrumb() +{ + global $navbits; + + $newnav[0]['name'] = $navbits[0]['name']; + $newnav[0]['url'] = $navbits[0]['url']; + if(!empty($navbits[0]['options'])) + { + $newnav[0]['options'] = $navbits[0]['options']; + } + + unset($GLOBALS['navbits']); + $GLOBALS['navbits'] = $newnav; +} + +/** + * Builds a URL to an archive mode page + * + * @param string The type of page (thread|announcement|forum) + * @param int The ID of the item + * @return string The URL + */ +function build_archive_link($type="", $id="") +{ + global $mybb; + + // If the server OS is not Windows and not Apache or the PHP is running as a CGI or we have defined ARCHIVE_QUERY_STRINGS, use query strings - DIRECTORY_SEPARATOR checks if running windows + //if((DIRECTORY_SEPARATOR == '\\' && is_numeric(stripos($_SERVER['SERVER_SOFTWARE'], "apache")) == false) || is_numeric(stripos(SAPI_NAME, "cgi")) !== false || defined("ARCHIVE_QUERY_STRINGS")) + if($mybb->settings['seourls_archive'] == 1) + { + $base_url = $mybb->settings['bburl']."/archive/index.php/"; + } + else + { + $base_url = $mybb->settings['bburl']."/archive/index.php?"; + } + + switch($type) + { + case "thread": + $url = "{$base_url}thread-{$id}.html"; + break; + case "announcement": + $url = "{$base_url}announcement-{$id}.html"; + break; + case "forum": + $url = "{$base_url}forum-{$id}.html"; + break; + default: + $url = $mybb->settings['bburl']."/archive/index.php"; + } + + return $url; +} + +/** + * Prints a debug information page + */ +function debug_page() +{ + global $db, $debug, $templates, $templatelist, $mybb, $maintimer, $globaltime, $ptimer, $parsetime, $lang, $cache; + + $totaltime = format_time_duration($maintimer->totaltime); + $phptime = $maintimer->totaltime - $db->query_time; + $query_time = $db->query_time; + $globaltime = format_time_duration($globaltime); + + $percentphp = number_format((($phptime/$maintimer->totaltime)*100), 2); + $percentsql = number_format((($query_time/$maintimer->totaltime)*100), 2); + + $phptime = format_time_duration($maintimer->totaltime - $db->query_time); + $query_time = format_time_duration($db->query_time); + + $call_time = format_time_duration($cache->call_time); + + $phpversion = PHP_VERSION; + + $serverload = get_server_load(); + + if($mybb->settings['gzipoutput'] != 0) + { + $gzipen = "Enabled"; + } + else + { + $gzipen = "Disabled"; + } + + echo "\n"; + echo ""; + echo ""; + echo ""; + echo ""; + echo "MyBB Debug Information"; + echo ""; + echo ""; + echo "

    MyBB Debug Information

    \n"; + echo "

    Page Generation

    \n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + + $memory_usage = get_memory_usage(); + if(!$memory_usage) + { + $memory_usage = $lang->unknown; + } + else + { + $memory_usage = get_friendly_size($memory_usage)." ({$memory_usage} bytes)"; + } + $memory_limit = @ini_get("memory_limit"); + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + + echo "
    Page Generation Statistics
    Page Generation Time:$totaltimeNo. DB Queries:$db->query_count
    PHP Processing Time:$phptime ($percentphp%)DB Processing Time:$query_time ($percentsql%)
    Extensions Used:{$mybb->config['database']['type']}, xmlGlobal.php Processing Time:$globaltime
    PHP Version:$phpversionServer Load:$serverload
    GZip Encoding Status:$gzipenNo. Templates Used:".count($templates->cache)." (".(int)count(explode(",", $templatelist))." Cached / ".(int)count($templates->uncached_templates)." Manually Loaded)
    Memory Usage:{$memory_usage}Memory Limit:{$memory_limit}
    \n"; + + echo "

    Database Connections (".count($db->connections)." Total)

    \n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "
    ".implode("
    ", $db->connections)."
    \n"; + echo "
    \n"; + + echo "

    Database Queries (".$db->query_count." Total)

    \n"; + echo $db->explain; + + if($cache->call_count > 0) + { + echo "

    Cache Calls (".$cache->call_count." Total, ".$call_time.")

    \n"; + echo $cache->cache_debug; + } + + echo "

    Template Statistics

    \n"; + + if(count($templates->cache) > 0) + { + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "
    Templates Used (Loaded for this Page) - ".count($templates->cache)." Total
    ".implode(", ", array_keys($templates->cache))."
    \n"; + echo "
    \n"; + } + + if(count($templates->uncached_templates) > 0) + { + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "
    Templates Requiring Additional Calls (Not Cached at Startup) - ".count($templates->uncached_templates)." Total
    ".implode(", ", $templates->uncached_templates)."
    \n"; + echo "
    \n"; + } + echo ""; + echo ""; + exit; +} + +/** + * Outputs the correct page headers. + */ +function send_page_headers() +{ + global $mybb; + + if($mybb->settings['nocacheheaders'] == 1) + { + header("Expires: Sat, 1 Jan 2000 01:00:00 GMT"); + header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); + header("Cache-Control: no-cache, must-revalidate"); + header("Pragma: no-cache"); + } +} + +/** + * Mark specific reported posts of a certain type as dealt with + * + * @param mixed An array or int of the ID numbers you're marking as dealt with + * @param string The type of item the above IDs are for - post, posts, thread, threads, forum, all + */ +function mark_reports($id, $type="post") +{ + global $db, $cache, $plugins; + + switch($type) + { + case "posts": + if(is_array($id)) + { + $rids = implode($id, "','"); + $rids = "'0','$rids'"; + $db->update_query("reportedcontent", array('reportstatus' => 1), "id IN($rids) AND reportstatus='0' AND (type = 'post' OR type = '')"); + } + break; + case "post": + $db->update_query("reportedcontent", array('reportstatus' => 1), "id='$id' AND reportstatus='0' AND (type = 'post' OR type = '')"); + break; + case "threads": + if(is_array($id)) + { + $rids = implode($id, "','"); + $rids = "'0','$rids'"; + $db->update_query("reportedcontent", array('reportstatus' => 1), "id2 IN($rids) AND reportstatus='0' AND (type = 'post' OR type = '')"); + } + break; + case "thread": + $db->update_query("reportedcontent", array('reportstatus' => 1), "id2='$id' AND reportstatus='0' AND (type = 'post' OR type = '')"); + break; + case "forum": + $db->update_query("reportedcontent", array('reportstatus' => 1), "id3='$id' AND reportstatus='0' AND (type = 'post' OR type = '')"); + break; + case "all": + $db->update_query("reportedcontent", array('reportstatus' => 1), "reportstatus='0' AND (type = 'post' OR type = '')"); + break; + } + + $arguments = array('id' => $id, 'type' => $type); + $plugins->run_hooks("mark_reports", $arguments); + $cache->update_reportedcontent(); +} + +/** + * Fetch a friendly x days, y months etc date stamp from a timestamp + * + * @param int The timestamp + * @param array Array of options + * @return string The friendly formatted timestamp + */ +function nice_time($stamp, $options=array()) +{ + global $lang; + + $ysecs = 365*24*60*60; + $mosecs = 31*24*60*60; + $wsecs = 7*24*60*60; + $dsecs = 24*60*60; + $hsecs = 60*60; + $msecs = 60; + + if(isset($options['short'])) + { + $lang_year = $lang->year_short; + $lang_years = $lang->years_short; + $lang_month = $lang->month_short; + $lang_months = $lang->months_short; + $lang_week = $lang->week_short; + $lang_weeks = $lang->weeks_short; + $lang_day = $lang->day_short; + $lang_days = $lang->days_short; + $lang_hour = $lang->hour_short; + $lang_hours = $lang->hours_short; + $lang_minute = $lang->minute_short; + $lang_minutes = $lang->minutes_short; + $lang_second = $lang->second_short; + $lang_seconds = $lang->seconds_short; + } + else + { + $lang_year = " ".$lang->year; + $lang_years = " ".$lang->years; + $lang_month = " ".$lang->month; + $lang_months = " ".$lang->months; + $lang_week = " ".$lang->week; + $lang_weeks = " ".$lang->weeks; + $lang_day = " ".$lang->day; + $lang_days = " ".$lang->days; + $lang_hour = " ".$lang->hour; + $lang_hours = " ".$lang->hours; + $lang_minute = " ".$lang->minute; + $lang_minutes = " ".$lang->minutes; + $lang_second = " ".$lang->second; + $lang_seconds = " ".$lang->seconds; + } + + $years = floor($stamp/$ysecs); + $stamp %= $ysecs; + $months = floor($stamp/$mosecs); + $stamp %= $mosecs; + $weeks = floor($stamp/$wsecs); + $stamp %= $wsecs; + $days = floor($stamp/$dsecs); + $stamp %= $dsecs; + $hours = floor($stamp/$hsecs); + $stamp %= $hsecs; + $minutes = floor($stamp/$msecs); + $stamp %= $msecs; + $seconds = $stamp; + + if($years == 1) + { + $nicetime['years'] = "1".$lang_year; + } + else if($years > 1) + { + $nicetime['years'] = $years.$lang_years; + } + + if($months == 1) + { + $nicetime['months'] = "1".$lang_month; + } + else if($months > 1) + { + $nicetime['months'] = $months.$lang_months; + } + + if($weeks == 1) + { + $nicetime['weeks'] = "1".$lang_week; + } + else if($weeks > 1) + { + $nicetime['weeks'] = $weeks.$lang_weeks; + } + + if($days == 1) + { + $nicetime['days'] = "1".$lang_day; + } + else if($days > 1) + { + $nicetime['days'] = $days.$lang_days; + } + + if(!isset($options['hours']) || $options['hours'] !== false) + { + if($hours == 1) + { + $nicetime['hours'] = "1".$lang_hour; + } + else if($hours > 1) + { + $nicetime['hours'] = $hours.$lang_hours; + } + } + + if(!isset($options['minutes']) || $options['minutes'] !== false) + { + if($minutes == 1) + { + $nicetime['minutes'] = "1".$lang_minute; + } + else if($minutes > 1) + { + $nicetime['minutes'] = $minutes.$lang_minutes; + } + } + + if(!isset($options['seconds']) || $options['seconds'] !== false) + { + if($seconds == 1) + { + $nicetime['seconds'] = "1".$lang_second; + } + else if($seconds > 1) + { + $nicetime['seconds'] = $seconds.$lang_seconds; + } + } + + if(is_array($nicetime)) + { + return implode(", ", $nicetime); + } +} + +/** + * Select an alternating row colour based on the previous call to this function + * + * @param int 1 to reset the row to trow1. + * @return string trow1 or trow2 depending on the previous call + */ +function alt_trow($reset=0) +{ + global $alttrow; + + if($alttrow == "trow1" && !$reset) + { + $trow = "trow2"; + } + else + { + $trow = "trow1"; + } + + $alttrow = $trow; + + return $trow; +} + +/** + * Add a user to a specific additional user group. + * + * @param int The user ID + * @param int The user group ID to join + */ +function join_usergroup($uid, $joingroup) +{ + global $db, $mybb; + + if($uid == $mybb->user['uid']) + { + $user = $mybb->user; + } + else + { + $query = $db->simple_select("users", "additionalgroups, usergroup", "uid='".(int)$uid."'"); + $user = $db->fetch_array($query); + } + + // Build the new list of additional groups for this user and make sure they're in the right format + $usergroups = ""; + $usergroups = $user['additionalgroups'].",".$joingroup; + $groupslist = ""; + $groups = explode(",", $usergroups); + + if(is_array($groups)) + { + $comma = ''; + foreach($groups as $gid) + { + if(trim($gid) != "" && $gid != $user['usergroup'] && !isset($donegroup[$gid])) + { + $groupslist .= $comma.$gid; + $comma = ","; + $donegroup[$gid] = 1; + } + } + } + + // What's the point in updating if they're the same? + if($groupslist != $user['additionalgroups']) + { + $db->update_query("users", array('additionalgroups' => $groupslist), "uid='".(int)$uid."'"); + return true; + } + else + { + return false; + } +} + +/** + * Remove a user from a specific additional user group + * + * @param int The user ID + * @param int The user group ID + */ +function leave_usergroup($uid, $leavegroup) +{ + global $db, $mybb, $cache; + + if($uid == $mybb->user['uid']) + { + $user = $mybb->user; + } + else + { + $user = get_user($uid); + } + + $groupslist = $comma = ''; + $usergroups = $user['additionalgroups'].","; + $donegroup = array(); + + $groups = explode(",", $user['additionalgroups']); + + if(is_array($groups)) + { + foreach($groups as $gid) + { + if(trim($gid) != "" && $leavegroup != $gid && empty($donegroup[$gid])) + { + $groupslist .= $comma.$gid; + $comma = ","; + $donegroup[$gid] = 1; + } + } + } + + $dispupdate = ""; + if($leavegroup == $user['displaygroup']) + { + $dispupdate = ", displaygroup=usergroup"; + } + + $db->write_query(" + UPDATE ".TABLE_PREFIX."users + SET additionalgroups='$groupslist' $dispupdate + WHERE uid='".(int)$uid."' + "); + + $cache->update_moderators(); +} + +/** + * Get the current location taking in to account different web serves and systems + * + * @param boolean True to return as "hidden" fields + * @param array Array of fields to ignore if first argument is true + * @return string The current URL being accessed + */ +function get_current_location($fields=false, $ignore=array()) +{ + if(defined("MYBB_LOCATION")) + { + return MYBB_LOCATION; + } + + if(!empty($_SERVER['PATH_INFO'])) + { + $location = htmlspecialchars_uni($_SERVER['PATH_INFO']); + } + elseif(!empty($_ENV['PATH_INFO'])) + { + $location = htmlspecialchars_uni($_ENV['PATH_INFO']); + } + elseif(!empty($_ENV['PHP_SELF'])) + { + $location = htmlspecialchars_uni($_ENV['PHP_SELF']); + } + else + { + $location = htmlspecialchars_uni($_SERVER['PHP_SELF']); + } + + if($fields == true) + { + global $mybb; + + if(!is_array($ignore)) + { + $ignore = array($ignore); + } + + $form_html = ''; + if(!empty($mybb->input)) + { + foreach($mybb->input as $name => $value) + { + if(in_array($name, $ignore) || is_array($name) || is_array($value)) + { + continue; + } + + $form_html .= "\n"; + } + } + + return array('location' => $location, 'form_html' => $form_html, 'form_method' => $mybb->request_method); + } + else + { + if(isset($_SERVER['QUERY_STRING'])) + { + $location .= "?".htmlspecialchars_uni($_SERVER['QUERY_STRING']); + } + else if(isset($_ENV['QUERY_STRING'])) + { + $location .= "?".htmlspecialchars_uni($_ENV['QUERY_STRING']); + } + + if((isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == "POST") || (isset($_ENV['REQUEST_METHOD']) && $_ENV['REQUEST_METHOD'] == "POST")) + { + $post_array = array('action', 'fid', 'pid', 'tid', 'uid', 'eid'); + + foreach($post_array as $var) + { + if(isset($_POST[$var])) + { + $addloc[] = urlencode($var).'='.urlencode($_POST[$var]); + } + } + + if(isset($addloc) && is_array($addloc)) + { + if(strpos($location, "?") === false) + { + $location .= "?"; + } + else + { + $location .= "&"; + } + $location .= implode("&", $addloc); + } + } + + if(strlen($location) > 150) + { + $location = substr($location, 0, 150); + } + + return $location; + } +} + +/** + * Build a theme selection menu + * + * @param string The name of the menu + * @param int The ID of the selected theme + * @param int The ID of the parent theme to select from + * @param int The current selection depth + * @param boolean Whether or not to override usergroup permissions (true to override) + * @param boolean Whether or not theme select is in the footer (true if it is) + * @param boolean Whether or not to override output based on theme count (true to override) + * @return string The theme selection list + */ +function build_theme_select($name, $selected="", $tid=0, $depth="", $usergroup_override=false, $footer=false, $count_override=false) +{ + global $db, $themeselect, $tcache, $lang, $mybb, $limit, $templates, $num_themes, $themeselect_option; + + if($tid == 0) + { + $tid = 1; + $num_themes = 0; + $themeselect_option = ''; + + if(!isset($lang->use_default)) + { + $lang->use_default = $lang->lang_select_default; + } + } + + if(!is_array($tcache)) + { + $query = $db->simple_select("themes", "name, pid, tid, allowedgroups", "pid != '0'", array('order_by' => 'pid, name')); + + while($theme = $db->fetch_array($query)) + { + $tcache[$theme['pid']][$theme['tid']] = $theme; + } + } + + if(is_array($tcache[$tid])) + { + // Figure out what groups this user is in + if(isset($mybb->user['additionalgroups'])) + { + $in_groups = explode(",", $mybb->user['additionalgroups']); + } + $in_groups[] = $mybb->user['usergroup']; + + foreach($tcache[$tid] as $theme) + { + $sel = ""; + // Make theme allowed groups into array + $is_allowed = false; + if($theme['allowedgroups'] != "all") + { + $allowed_groups = explode(",", $theme['allowedgroups']); + // See if groups user is in is allowed + foreach($allowed_groups as $agid) + { + if(in_array($agid, $in_groups)) + { + $is_allowed = true; + break; + } + } + } + + // Show theme if allowed, or if override is on + if($is_allowed || $theme['allowedgroups'] == "all" || $usergroup_override == true) + { + if($theme['tid'] == $selected) + { + $sel = " selected=\"selected\""; + } + + if($theme['pid'] != 0) + { + $theme['name'] = htmlspecialchars_uni($theme['name']); + eval("\$themeselect_option .= \"".$templates->get("usercp_themeselector_option")."\";"); + ++$num_themes; + $depthit = $depth."--"; + } + + if(array_key_exists($theme['tid'], $tcache)) + { + build_theme_select($name, $selected, $theme['tid'], $depthit, $usergroup_override, $footer); + } + } + } + } + + if($tid == 1 && ($num_themes > 1 || $count_override == true)) + { + if($footer == true) + { + eval("\$themeselect = \"".$templates->get("footer_themeselector")."\";"); + } + else + { + eval("\$themeselect = \"".$templates->get("usercp_themeselector")."\";"); + } + + return $themeselect; + } + else + { + return false; + } +} + +/** + * Custom function for htmlspecialchars which takes in to account unicode + * + * @param string The string to format + * @return string The string with htmlspecialchars applied + */ +function htmlspecialchars_uni($message) +{ + $message = preg_replace("#&(?!\#[0-9]+;)#si", "&", $message); // Fix & but allow unicode + $message = str_replace("<", "<", $message); + $message = str_replace(">", ">", $message); + $message = str_replace("\"", """, $message); + return $message; +} + +/** + * Custom function for formatting numbers. + * + * @param int The number to format. + * @return int The formatted number. + */ +function my_number_format($number) +{ + global $mybb; + + if($number == "-") + { + return $number; + } + + if(is_int($number)) + { + return number_format($number, 0, $mybb->settings['decpoint'], $mybb->settings['thousandssep']); + } + else + { + $parts = explode('.', $number); + + if(isset($parts[1])) + { + $decimals = my_strlen($parts[1]); + } + else + { + $decimals = 0; + } + + return number_format((double)$number, $decimals, $mybb->settings['decpoint'], $mybb->settings['thousandssep']); + } +} + +/** + * Converts a string of text to or from UTF-8. + * + * @param string The string of text to convert + * @param boolean Whether or not the string is being converted to or from UTF-8 (true if converting to) + * @return string The converted string + */ +function convert_through_utf8($str, $to=true) +{ + global $lang; + static $charset; + static $use_mb; + static $use_iconv; + + if(!isset($charset)) + { + $charset = my_strtolower($lang->settings['charset']); + } + + if($charset == "utf-8") + { + return $str; + } + + if(!isset($use_iconv)) + { + $use_iconv = function_exists("iconv"); + } + + if(!isset($use_mb)) + { + $use_mb = function_exists("mb_convert_encoding"); + } + + if($use_iconv || $use_mb) + { + if($to) + { + $from_charset = $lang->settings['charset']; + $to_charset = "UTF-8"; + } + else + { + $from_charset = "UTF-8"; + $to_charset = $lang->settings['charset']; + } + if($use_iconv) + { + return iconv($from_charset, $to_charset."//IGNORE", $str); + } + else + { + return @mb_convert_encoding($str, $to_charset, $from_charset); + } + } + elseif($charset == "iso-8859-1" && function_exists("utf8_encode")) + { + if($to) + { + return utf8_encode($str); + } + else + { + return utf8_decode($str); + } + } + else + { + return $str; + } +} + +/** + * Replacement function for PHP's wordwrap(). This version does not break up HTML tags, URLs or unicode references. + * + * @param string The string to be word wrapped + * @return string The word wraped string + */ +function my_wordwrap($message) +{ + global $mybb; + + if($mybb->settings['wordwrap'] > 0) + { + $message = convert_through_utf8($message); + + if(!($new_message = @preg_replace("#(((?>[^\s&/<>\"\\-\[\]])|(&\#[a-z0-9]{1,10};)){{$mybb->settings['wordwrap']}})#u", "$0​", $message))) + { + $new_message = preg_replace("#(((?>[^\s&/<>\"\\-\[\]])|(&\#[a-z0-9]{1,10};)){{$mybb->settings['wordwrap']}})#", "$0​", $message); + } + + $new_message = convert_through_utf8($new_message, false); + + return $new_message; + } + + return $message; +} + +/** + * Workaround for date limitation in PHP to establish the day of a birthday (Provided by meme) + * + * @param int The month of the birthday + * @param int The day of the birthday + * @param int The year of the bithday + * @return int The numeric day of the week for the birthday + */ +function get_weekday($month, $day, $year) +{ + $h = 4; + + for($i = 1969; $i >= $year; $i--) + { + $j = get_bdays($i); + + for($k = 11; $k >= 0; $k--) + { + $l = ($k + 1); + + for($m = $j[$k]; $m >= 1; $m--) + { + $h--; + + if($i == $year && $l == $month && $m == $day) + { + return $h; + } + + if($h == 0) + { + $h = 7; + } + } + } + } +} + +/** + * Workaround for date limitation in PHP to establish the day of a birthday (Provided by meme) + * + * @param int The year. + * @return array The number of days in each month of that year + */ +function get_bdays($in) +{ + return array( + 31, + ($in % 4 == 0 && ($in % 100 > 0 || $in % 400 == 0) ? 29 : 28), + 31, + 30, + 31, + 30, + 31, + 31, + 30, + 31, + 30, + 31 + ); +} + +/** + * Formats a birthday appropriately + * + * @param string The PHP date format string + * @param int The month of the birthday + * @param int The day of the birthday + * @param int The year of the birthday + * @param int The weekday of the birthday + * @return string The formatted birthday + */ +function format_bdays($display, $bm, $bd, $by, $wd) +{ + global $lang; + + $bdays = array( + $lang->sunday, + $lang->monday, + $lang->tuesday, + $lang->wednesday, + $lang->thursday, + $lang->friday, + $lang->saturday + ); + + $bmonth = array( + $lang->month_1, + $lang->month_2, + $lang->month_3, + $lang->month_4, + $lang->month_5, + $lang->month_6, + $lang->month_7, + $lang->month_8, + $lang->month_9, + $lang->month_10, + $lang->month_11, + $lang->month_12 + ); + + + // This needs to be in this specific order + $find = array( + 'm', + 'd', + 'D', + 'y', + 'Y', + 'j', + 'S', + 'F', + 'l', + 'M', + ); + + $html = array( + 'm', + 'c', + 'D', + 'y', + 'Y', + 'j', + 'S', + 'F', + 'l', + 'M', + ); + + $bdays = str_replace($find, $html, $bdays); + $bmonth = str_replace($find, $html, $bmonth); + + $replace = array( + sprintf('%02s', $bm), + sprintf('%02s', $bd), + ($wd == 2 ? my_substr($bdays[$wd], 0, 4) : ($wd == 4 ? my_substr($bdays[$wd], 0, 5) : my_substr($bdays[$wd], 0, 3))), + my_substr($by, 2), + $by, + ($bd[0] == 0 ? my_substr($bd, 1) : $bd), + ($bd == 1 || $bd == 21 || $bd == 31 ? 'st' : ($bd == 2 || $bd == 22 ? 'nd' : ($bd == 3 || $bd == 23 ? 'rd' : 'th'))), + $bmonth[$bm-1], + $wd, + ($bm == 9 ? my_substr($bmonth[$bm-1], 0, 4) : my_substr($bmonth[$bm-1], 0, 3)), + ); + + // Do we have the full month in our output? + // If so there's no need for the short month + if(strpos($display, 'F') !== false) + { + array_pop($find); + array_pop($replace); + } + + return str_replace($find, $replace, $display); +} + +/** + * Returns the age of a user with specified birthday. + * + * @param string The birthday of a user. + * @return float The age of a user with that birthday. + */ +function get_age($birthday) +{ + $bday = explode("-", $birthday); + if(!$bday[2]) + { + return; + } + + list($day, $month, $year) = explode("-", my_date("j-n-Y", TIME_NOW, 0, 0)); + + $age = $year-$bday[2]; + + if(($month == $bday[1] && $day < $bday[0]) || $month < $bday[1]) + { + --$age; + } + return $age; +} + +/** + * Updates the first posts in a thread. + * + * @param int The thread id for which to update the first post id. + */ +function update_first_post($tid) +{ + global $db; + + $query = $db->query(" + SELECT u.uid, u.username, p.pid, p.username AS postusername, p.dateline + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) + WHERE p.tid='$tid' + ORDER BY p.dateline ASC + LIMIT 1 + "); + $firstpost = $db->fetch_array($query); + + if(empty($firstpost['username'])) + { + $firstpost['username'] = $firstpost['postusername']; + } + $firstpost['username'] = $db->escape_string($firstpost['username']); + + $update_array = array( + 'firstpost' => (int)$firstpost['pid'], + 'username' => $firstpost['username'], + 'uid' => (int)$firstpost['uid'], + 'dateline' => (int)$firstpost['dateline'] + ); + $db->update_query("threads", $update_array, "tid='{$tid}'"); +} + +/** + * Updates the last posts in a thread. + * + * @param int The thread id for which to update the last post id. + */ +function update_last_post($tid) +{ + global $db; + + $query = $db->query(" + SELECT u.uid, u.username, p.username AS postusername, p.dateline + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) + WHERE p.tid='$tid' AND p.visible='1' + ORDER BY p.dateline DESC + LIMIT 1" + ); + $lastpost = $db->fetch_array($query); + + if(empty($lastpost['username'])) + { + $lastpost['username'] = $lastpost['postusername']; + } + + if(empty($lastpost['dateline'])) + { + $query = $db->query(" + SELECT u.uid, u.username, p.pid, p.username AS postusername, p.dateline + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=p.uid) + WHERE p.tid='$tid' + ORDER BY p.dateline ASC + LIMIT 1 + "); + $firstpost = $db->fetch_array($query); + + $lastpost['username'] = $firstpost['username']; + $lastpost['uid'] = $firstpost['uid']; + $lastpost['dateline'] = $firstpost['dateline']; + } + + $lastpost['username'] = $db->escape_string($lastpost['username']); + + $update_array = array( + 'lastpost' => (int)$lastpost['dateline'], + 'lastposter' => $lastpost['username'], + 'lastposteruid' => (int)$lastpost['uid'] + ); + $db->update_query("threads", $update_array, "tid='{$tid}'"); +} + +/** + * Checks for the length of a string, mb strings accounted for + * + * @param string The string to check the length of. + * @return int The length of the string. + */ +function my_strlen($string) +{ + global $lang; + + $string = preg_replace("#&\#([0-9]+);#", "-", $string); + + if(strtolower($lang->settings['charset']) == "utf-8") + { + // Get rid of any excess RTL and LTR override for they are the workings of the devil + $string = str_replace(dec_to_utf8(8238), "", $string); + $string = str_replace(dec_to_utf8(8237), "", $string); + + // Remove dodgy whitespaces + $string = str_replace(chr(0xCA), "", $string); + } + $string = trim($string); + + if(function_exists("mb_strlen")) + { + $string_length = mb_strlen($string); + } + else + { + $string_length = strlen($string); + } + + return $string_length; +} + +/** + * Cuts a string at a specified point, mb strings accounted for + * + * @param string The string to cut. + * @param int Where to cut + * @param int (optional) How much to cut + * @param bool (optional) Properly handle HTML entities? + * @return int The cut part of the string. + */ +function my_substr($string, $start, $length="", $handle_entities = false) +{ + if($handle_entities) + { + $string = unhtmlentities($string); + } + if(function_exists("mb_substr")) + { + if($length != "") + { + $cut_string = mb_substr($string, $start, $length); + } + else + { + $cut_string = mb_substr($string, $start); + } + } + else + { + if($length != "") + { + $cut_string = substr($string, $start, $length); + } + else + { + $cut_string = substr($string, $start); + } + } + + if($handle_entities) + { + $cut_string = htmlspecialchars_uni($cut_string); + } + return $cut_string; +} + +/** + * Lowers the case of a string, mb strings accounted for + * + * @param string The string to lower. + * @return int The lowered string. + */ +function my_strtolower($string) +{ + if(function_exists("mb_strtolower")) + { + $string = mb_strtolower($string); + } + else + { + $string = strtolower($string); + } + + return $string; +} + +/** + * Finds a needle in a haystack and returns it position, mb strings accounted for + * + * @param string String to look in (haystack) + * @param string What to look for (needle) + * @param int (optional) How much to offset + * @return int false on needle not found, integer position if found + */ +function my_strpos($haystack, $needle, $offset=0) +{ + if($needle == '') + { + return false; + } + + if(function_exists("mb_strpos")) + { + $position = mb_strpos($haystack, $needle, $offset); + } + else + { + $position = strpos($haystack, $needle, $offset); + } + + return $position; +} + +/** + * Ups the case of a string, mb strings accounted for + * + * @param string The string to up. + * @return int The uped string. + */ +function my_strtoupper($string) +{ + if(function_exists("mb_strtoupper")) + { + $string = mb_strtoupper($string); + } + else + { + $string = strtoupper($string); + } + + return $string; +} + +/** + * Returns any html entities to their original character + * + * @param string The string to un-htmlentitize. + * @return int The un-htmlentitied' string. + */ +function unhtmlentities($string) +{ + // Replace numeric entities + $string = preg_replace_callback('~&#x([0-9a-f]+);~i', create_function('$matches', 'return unichr(hexdec($matches[1]));'), $string); + $string = preg_replace_callback('~&#([0-9]+);~', create_function('$matches', 'return unichr($matches[1]);'), $string); + + // Replace literal entities + $trans_tbl = get_html_translation_table(HTML_ENTITIES); + $trans_tbl = array_flip($trans_tbl); + + return strtr($string, $trans_tbl); +} + +/** + * Returns any ascii to it's character (utf-8 safe). + * + * @param string The ascii to characterize. + * @return int The characterized ascii. + */ +function unichr($c) +{ + if($c <= 0x7F) + { + return chr($c); + } + else if($c <= 0x7FF) + { + return chr(0xC0 | $c >> 6) . chr(0x80 | $c & 0x3F); + } + else if($c <= 0xFFFF) + { + return chr(0xE0 | $c >> 12) . chr(0x80 | $c >> 6 & 0x3F) + . chr(0x80 | $c & 0x3F); + } + else if($c <= 0x10FFFF) + { + return chr(0xF0 | $c >> 18) . chr(0x80 | $c >> 12 & 0x3F) + . chr(0x80 | $c >> 6 & 0x3F) + . chr(0x80 | $c & 0x3F); + } + else + { + return false; + } +} + +/** + * Get the event poster. + * + * @param array The event data array. + * @return string The link to the event poster. + */ +function get_event_poster($event) +{ + $event['username'] = format_name($event['username'], $event['usergroup'], $event['displaygroup']); + $event_poster = build_profile_link($event['username'], $event['author']); + return $event_poster; +} + +/** + * Get the event date. + * + * @param array The event data array. + * @return string The event date. + */ +function get_event_date($event) +{ + global $mybb; + + $event_date = explode("-", $event['date']); + $event_date = mktime(0, 0, 0, $event_date[1], $event_date[0], $event_date[2]); + $event_date = my_date($mybb->settings['dateformat'], $event_date); + + return $event_date; +} + +/** + * Get the profile link. + * + * @param int The user id of the profile. + * @return string The url to the profile. + */ +function get_profile_link($uid=0) +{ + $link = str_replace("{uid}", $uid, PROFILE_URL); + return htmlspecialchars_uni($link); +} + +/** + * Get the announcement link. + * + * @param int The announement id of the announcement. + * @return string The url to the announcement. + */ +function get_announcement_link($aid=0) +{ + $link = str_replace("{aid}", $aid, ANNOUNCEMENT_URL); + return htmlspecialchars_uni($link); +} + +/** + * Build the profile link. + * + * @param string The Username of the profile. + * @param int The user id of the profile. + * @param string The target frame + * @param string Any onclick javascript. + * @return string The complete profile link. + */ +function build_profile_link($username="", $uid=0, $target="", $onclick="") +{ + global $mybb, $lang; + + if(!$username && $uid == 0) + { + // Return Guest phrase for no UID, no guest nickname + return $lang->guest; + } + elseif($uid == 0) + { + // Return the guest's nickname if user is a guest but has a nickname + return $username; + } + else + { + // Build the profile link for the registered user + if(!empty($target)) + { + $target = " target=\"{$target}\""; + } + + if(!empty($onclick)) + { + $onclick = " onclick=\"{$onclick}\""; + } + + return "settings['bburl']}/".get_profile_link($uid)."\"{$target}{$onclick}>{$username}"; + } +} + +/** + * Build the forum link. + * + * @param int The forum id of the forum. + * @param int (Optional) The page number of the forum. + * @return string The url to the forum. + */ +function get_forum_link($fid, $page=0) +{ + if($page > 0) + { + $link = str_replace("{fid}", $fid, FORUM_URL_PAGED); + $link = str_replace("{page}", $page, $link); + return htmlspecialchars_uni($link); + } + else + { + $link = str_replace("{fid}", $fid, FORUM_URL); + return htmlspecialchars_uni($link); + } +} + +/** + * Build the thread link. + * + * @param int The thread id of the thread. + * @param int (Optional) The page number of the thread. + * @param string (Optional) The action we're performing (ex, lastpost, newpost, etc) + * @return string The url to the thread. + */ +function get_thread_link($tid, $page=0, $action='') +{ + if($page > 1) + { + if($action) + { + $link = THREAD_URL_ACTION; + $link = str_replace("{action}", $action, $link); + } + else + { + $link = THREAD_URL_PAGED; + } + $link = str_replace("{tid}", $tid, $link); + $link = str_replace("{page}", $page, $link); + return htmlspecialchars_uni($link); + } + else + { + if($action) + { + $link = THREAD_URL_ACTION; + $link = str_replace("{action}", $action, $link); + } + else + { + $link = THREAD_URL; + } + $link = str_replace("{tid}", $tid, $link); + return htmlspecialchars_uni($link); + } +} + +/** + * Build the post link. + * + * @param int The post ID of the post + * @param int The thread id of the post. + * @return string The url to the post. + */ +function get_post_link($pid, $tid=0) +{ + if($tid > 0) + { + $link = str_replace("{tid}", $tid, THREAD_URL_POST); + $link = str_replace("{pid}", $pid, $link); + return htmlspecialchars_uni($link); + } + else + { + $link = str_replace("{pid}", $pid, POST_URL); + return htmlspecialchars_uni($link); + } +} + +/** + * Build the event link. + * + * @param int The event ID of the event + * @return string The URL of the event + */ +function get_event_link($eid) +{ + $link = str_replace("{eid}", $eid, EVENT_URL); + return htmlspecialchars_uni($link); +} + +/** + * Build the link to a specified date on the calendar + * + * @param int The ID of the calendar + * @param int The year + * @param int The month + * @param int The day (optional) + * @return string The URL of the calendar + */ +function get_calendar_link($calendar, $year=0, $month=0, $day=0) +{ + if($day > 0) + { + $link = str_replace("{month}", $month, CALENDAR_URL_DAY); + $link = str_replace("{year}", $year, $link); + $link = str_replace("{day}", $day, $link); + $link = str_replace("{calendar}", $calendar, $link); + return htmlspecialchars_uni($link); + } + else if($month > 0) + { + $link = str_replace("{month}", $month, CALENDAR_URL_MONTH); + $link = str_replace("{year}", $year, $link); + $link = str_replace("{calendar}", $calendar, $link); + return htmlspecialchars_uni($link); + } + /* Not implemented + else if($year > 0) + { + }*/ + else + { + $link = str_replace("{calendar}", $calendar, CALENDAR_URL); + return htmlspecialchars_uni($link); + } +} + +/** + * Build the link to a specified week on the calendar + * + * @param int The ID of the calendar + * @param int The year + * @param int The week + * @return string The URL of the calendar + */ +function get_calendar_week_link($calendar, $week) +{ + if($week < 0) + { + $week = str_replace('-', "n", $week); + } + $link = str_replace("{week}", $week, CALENDAR_URL_WEEK); + $link = str_replace("{calendar}", $calendar, $link); + return htmlspecialchars_uni($link); +} + +/** + * Get the user data of an user id. + * + * @param int The user id of the user. + * @return array The users data + */ +function get_user($uid) +{ + global $mybb, $db; + static $user_cache; + + $uid = (int)$uid; + + if(!empty($mybb->user) && $uid == $mybb->user['uid']) + { + return $mybb->user; + } + elseif(isset($user_cache[$uid])) + { + return $user_cache[$uid]; + } + elseif($uid > 0) + { + $query = $db->simple_select("users", "*", "uid = '{$uid}'"); + $user_cache[$uid] = $db->fetch_array($query); + + return $user_cache[$uid]; + } + return array(); +} + +/** + * Get the user data of an user username. + * + * @param string The user username of the user. + * @return array The users data + */ +function get_user_by_username($username, $options=array()) +{ + global $mybb, $db; + + $username = $db->escape_string(my_strtolower($username)); + + if(!isset($options['username_method'])) + { + $options['username_method'] = 0; + } + + switch($options['username_method']) + { + case 1: + $sqlwhere = 'LOWER(email)=\''.$username.'\''; + break; + case 2: + $sqlwhere = 'LOWER(username)=\''.$username.'\' OR LOWER(email)=\''.$username.'\''; + break; + default: + $sqlwhere = 'LOWER(username)=\''.$username.'\''; + break; + } + + $fields = array('uid'); + if(isset($options['fields'])) + { + $fields = array_merge((array)$options['fields'], $fields); + } + + $query = $db->simple_select('users', implode(',', array_unique($fields)), $sqlwhere, array('limit' => 1)); + + if(isset($options['exists'])) + { + return (bool)$db->num_rows($query); + } + + return $db->fetch_array($query); +} + +/** + * Get the forum of a specific forum id. + * + * @param int The forum id of the forum. + * @param int (Optional) If set to 1, will override the active forum status + * @return array The database row of a forum. + */ +function get_forum($fid, $active_override=0) +{ + global $cache; + static $forum_cache; + + if(!isset($forum_cache) || is_array($forum_cache)) + { + $forum_cache = $cache->read("forums"); + } + + if(empty($forum_cache[$fid])) + { + return false; + } + + if($active_override != 1) + { + $parents = explode(",", $forum_cache[$fid]['parentlist']); + if(is_array($parents)) + { + foreach($parents as $parent) + { + if($forum_cache[$parent]['active'] == 0) + { + return false; + } + } + } + } + + return $forum_cache[$fid]; +} + +/** + * Get the thread of a thread id. + * + * @param int The thread id of the thread. + * @param boolean Whether or not to recache the thread. + * @return string The database row of the thread. + */ +function get_thread($tid, $recache = false) +{ + global $db; + static $thread_cache; + + $tid = (int)$tid; + + if(isset($thread_cache[$tid]) && !$recache) + { + return $thread_cache[$tid]; + } + else + { + $query = $db->simple_select("threads", "*", "tid = '{$tid}'"); + $thread = $db->fetch_array($query); + + if($thread) + { + $thread_cache[$tid] = $thread; + return $thread; + } + else + { + $thread_cache[$tid] = false; + return false; + } + } +} + +/** + * Get the post of a post id. + * + * @param int The post id of the post. + * @param boolean Whether or not to recache the post. + * @param array An array of fields to gather from the database + * @return string The database row of the post. + */ +function get_post($pid) +{ + global $db; + static $post_cache; + + $pid = (int)$pid; + + if(isset($post_cache[$pid])) + { + return $post_cache[$pid]; + } + else + { + $query = $db->simple_select("posts", "*", "pid = '{$pid}'"); + $post = $db->fetch_array($query); + + if($post) + { + $post_cache[$pid] = $post; + return $post; + } + else + { + $post_cache[$pid] = false; + return false; + } + } +} + +/** + * Get inactivate forums. + * + * @return string The comma separated values of the inactivate forum. + */ +function get_inactive_forums() +{ + global $forum_cache, $cache, $inactiveforums; + + if(!$forum_cache) + { + cache_forums(); + } + + $inactive = array(); + + foreach($forum_cache as $fid => $forum) + { + if($forum['active'] == 0) + { + $inactive[] = $fid; + foreach($forum_cache as $fid1 => $forum1) + { + if(my_strpos(",".$forum1['parentlist'].",", ",".$fid.",") !== false && !in_array($fid1, $inactive)) + { + $inactive[] = $fid1; + } + } + } + } + $inactiveforums = implode(",", $inactive); + + return $inactiveforums; +} + +/** + * Checks to make sure a user has not tried to login more times than permitted + * + * @param bool (Optional) Stop execution if it finds an error with the login. Default is True + * @return bool Number of logins when success, false if failed. + */ +function login_attempt_check($fatal = true) +{ + global $mybb, $lang, $session, $db; + + if($mybb->settings['failedlogincount'] == 0) + { + return 1; + } + // Note: Number of logins is defaulted to 1, because using 0 seems to clear cookie data. Not really a problem as long as we account for 1 being default. + + // Use cookie if possible, otherwise use session + // Find better solution to prevent clearing cookies + $loginattempts = 0; + $failedlogin = 0; + + if(!empty($mybb->cookies['loginattempts'])) + { + $loginattempts = $mybb->cookies['loginattempts']; + } + + if(!empty($mybb->cookies['failedlogin'])) + { + $failedlogin = $mybb->cookies['failedlogin']; + } + + // Work out if the user has had more than the allowed number of login attempts + if($loginattempts > $mybb->settings['failedlogincount']) + { + // If so, then we need to work out if they can try to login again + // Some maths to work out how long they have left and display it to them + $now = TIME_NOW; + + if(empty($mybb->cookies['failedlogin'])) + { + $failedtime = $now; + } + else + { + $failedtime = $mybb->cookies['failedlogin']; + } + + $secondsleft = $mybb->settings['failedlogintime'] * 60 + $failedtime - $now; + $hoursleft = floor($secondsleft / 3600); + $minsleft = floor(($secondsleft / 60) % 60); + $secsleft = floor($secondsleft % 60); + + // This value will be empty the first time the user doesn't login in, set it + if(empty($failedlogin)) + { + my_setcookie('failedlogin', $now); + if($fatal) + { + error($lang->sprintf($lang->failed_login_wait, $hoursleft, $minsleft, $secsleft)); + } + + return false; + } + + // Work out if the user has waited long enough before letting them login again + if($mybb->cookies['failedlogin'] < ($now - $mybb->settings['failedlogintime'] * 60)) + { + my_setcookie('loginattempts', 1); + my_unsetcookie('failedlogin'); + if($mybb->user['uid'] != 0) + { + $update_array = array( + 'loginattempts' => 1 + ); + $db->update_query("users", $update_array, "uid = '{$mybb->user['uid']}'"); + } + return 1; + } + // Not waited long enough + else if($mybb->cookies['failedlogin'] > ($now - $mybb->settings['failedlogintime'] * 60)) + { + if($fatal) + { + error($lang->sprintf($lang->failed_login_wait, $hoursleft, $minsleft, $secsleft)); + } + + return false; + } + } + + // User can attempt another login + return $loginattempts; +} + +/** + * Validates the format of an email address. + * + * @param string The string to check. + * @return boolean True when valid, false when invalid. + */ +function validate_email_format($email) +{ + if(strpos($email, ' ') !== false) + { + return false; + } + // Valid local characters for email addresses: http://www.remote.org/jochen/mail/info/chars.html + return preg_match("/^[a-zA-Z0-9&*+\-_.{}~^\?=\/]+@[a-zA-Z0-9-]+\.([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]{2,}$/si", $email); +} + +/** + * Checks to see if the email is already in use by another + * + * @param string The email to check. + * @param string User ID of the user (updating only) + * @return boolean True when in use, false when not. + */ +function email_already_in_use($email, $uid="") +{ + global $db; + + $uid_string = ""; + if($uid) + { + $uid_string = " AND uid != '".(int)$uid."'"; + } + $query = $db->simple_select("users", "COUNT(email) as emails", "email = '".$db->escape_string($email)."'{$uid_string}"); + + if($db->fetch_field($query, "emails") > 0) + { + return true; + } + + return false; +} + +/** + * Rebuilds settings.php + * + */ +function rebuild_settings() +{ + global $db, $mybb; + + if(!file_exists(MYBB_ROOT."inc/settings.php")) + { + $mode = "x"; + } + else + { + $mode = "w"; + } + + $options = array( + "order_by" => "title", + "order_dir" => "ASC" + ); + $query = $db->simple_select("settings", "value, name", "", $options); + + $settings = null; + while($setting = $db->fetch_array($query)) + { + $mybb->settings[$setting['name']] = $setting['value']; + $setting['value'] = addcslashes($setting['value'], '\\"$'); + $settings .= "\$settings['{$setting['name']}'] = \"{$setting['value']}\";\n"; + } + + $settings = "<"."?php\n/*********************************\ \n DO NOT EDIT THIS FILE, PLEASE USE\n THE SETTINGS EDITOR\n\*********************************/\n\n$settings\n"; + $file = @fopen(MYBB_ROOT."inc/settings.php", $mode); + @fwrite($file, $settings); + @fclose($file); + + $GLOBALS['settings'] = &$mybb->settings; +} + +/** + * Build a PREG compatible array of search highlight terms to replace in posts. + * + * @param string Incoming terms to highlight + * @return array PREG compatible array of terms + */ +function build_highlight_array($terms) +{ + global $mybb; + + if($mybb->settings['minsearchword'] < 1) + { + $mybb->settings['minsearchword'] = 3; + } + + if(is_array($terms)) + { + $terms = implode(' ', $terms); + } + + // Strip out any characters that shouldn't be included + $bad_characters = array( + "(", + ")", + "+", + "-", + "~" + ); + $terms = str_replace($bad_characters, '', $terms); + + // Check if this is a "series of words" - should be treated as an EXACT match + if(my_strpos($terms, "\"") !== false) + { + $inquote = false; + $terms = explode("\"", $terms); + $words = array(); + foreach($terms as $phrase) + { + $phrase = htmlspecialchars_uni($phrase); + if($phrase != "") + { + if($inquote) + { + $words[] = trim($phrase); + } + else + { + $split_words = preg_split("#\s{1,}#", $phrase, -1); + if(!is_array($split_words)) + { + continue; + } + foreach($split_words as $word) + { + if(!$word || strlen($word) < $mybb->settings['minsearchword']) + { + continue; + } + $words[] = trim($word); + } + } + } + $inquote = !$inquote; + } + } + // Otherwise just a simple search query with no phrases + else + { + $terms = htmlspecialchars_uni($terms); + $split_words = preg_split("#\s{1,}#", $terms, -1); + if(is_array($split_words)) + { + foreach($split_words as $word) + { + if(!$word || strlen($word) < $mybb->settings['minsearchword']) + { + continue; + } + $words[] = trim($word); + } + } + } + + if(!is_array($words)) + { + return false; + } + + // Sort the word array by length. Largest terms go first and work their way down to the smallest term. + // This resolves problems like "test tes" where "tes" will be highlighted first, then "test" can't be highlighted because of the changed html + usort($words, create_function('$a,$b', 'return strlen($b) - strlen($a);')); + + // Loop through our words to build the PREG compatible strings + foreach($words as $word) + { + $word = trim($word); + + $word = my_strtolower($word); + + // Special boolean operators should be stripped + if($word == "" || $word == "or" || $word == "not" || $word == "and") + { + continue; + } + + // Now make PREG compatible + $find = "#(?!<.*?)(".preg_quote($word, "#").")(?![^<>]*?>)#ui"; + $replacement = "$1"; + $highlight_cache[$find] = $replacement; + } + + return $highlight_cache; +} + +/** + * Converts a decimal reference of a character to its UTF-8 equivalent + * (Code by Anne van Kesteren, http://annevankesteren.nl/2005/05/character-references) + * + * @param string Decimal value of a character reference + */ +function dec_to_utf8($src) +{ + $dest = ''; + + if($src < 0) + { + return false; + } + elseif($src <= 0x007f) + { + $dest .= chr($src); + } + elseif($src <= 0x07ff) + { + $dest .= chr(0xc0 | ($src >> 6)); + $dest .= chr(0x80 | ($src & 0x003f)); + } + elseif($src <= 0xffff) + { + $dest .= chr(0xe0 | ($src >> 12)); + $dest .= chr(0x80 | (($src >> 6) & 0x003f)); + $dest .= chr(0x80 | ($src & 0x003f)); + } + elseif($src <= 0x10ffff) + { + $dest .= chr(0xf0 | ($src >> 18)); + $dest .= chr(0x80 | (($src >> 12) & 0x3f)); + $dest .= chr(0x80 | (($src >> 6) & 0x3f)); + $dest .= chr(0x80 | ($src & 0x3f)); + } + else + { + // Out of range + return false; + } + + return $dest; +} + +/** + * Checks if a username has been disallowed for registration/use. + * + * @param string The username + * @param boolean True if the 'last used' dateline should be updated if a match is found. + * @return boolean True if banned, false if not banned + */ +function is_banned_username($username, $update_lastuse=false) +{ + global $db; + $query = $db->simple_select('banfilters', 'filter, fid', "type='2'"); + while($banned_username = $db->fetch_array($query)) + { + // Make regular expression * match + $banned_username['filter'] = str_replace('\*', '(.*)', preg_quote($banned_username['filter'], '#')); + if(preg_match("#(^|\b){$banned_username['filter']}($|\b)#i", $username)) + { + // Updating last use + if($update_lastuse == true) + { + $db->update_query("banfilters", array("lastuse" => TIME_NOW), "fid='{$banned_username['fid']}'"); + } + return true; + } + } + // Still here - good username + return false; +} + +/** + * Check if a specific email address has been banned. + * + * @param string The email address. + * @param boolean True if the 'last used' dateline should be updated if a match is found. + * @return boolean True if banned, false if not banned + */ +function is_banned_email($email, $update_lastuse=false) +{ + global $cache, $db; + + $banned_cache = $cache->read("bannedemails"); + + if($banned_cache === false) + { + // Failed to read cache, see if we can rebuild it + $cache->update_bannedemails(); + $banned_cache = $cache->read("bannedemails"); + } + + if(is_array($banned_cache) && !empty($banned_cache)) + { + foreach($banned_cache as $banned_email) + { + // Make regular expression * match + $banned_email['filter'] = str_replace('\*', '(.*)', preg_quote($banned_email['filter'], '#')); + + if(preg_match("#{$banned_email['filter']}#i", $email)) + { + // Updating last use + if($update_lastuse == true) + { + $db->update_query("banfilters", array("lastuse" => TIME_NOW), "fid='{$banned_email['fid']}'"); + } + return true; + } + } + } + + // Still here - good email + return false; +} + +/** + * Checks if a specific IP address has been banned. + * + * @param string The IP address. + * @param boolean True if the 'last used' dateline should be updated if a match is found. + * @return boolean True if banned, false if not banned. + */ +function is_banned_ip($ip_address, $update_lastuse=false) +{ + global $db, $cache; + + $banned_ips = $cache->read("bannedips"); + if(!is_array($banned_ips)) + { + return false; + } + + $ip_address = my_inet_pton($ip_address); + foreach($banned_ips as $banned_ip) + { + if(!$banned_ip['filter']) + { + continue; + } + + $banned = false; + + $ip_range = fetch_ip_range($banned_ip['filter']); + if(is_array($ip_range)) + { + if(strcmp($ip_range[0], $ip_address) >= 0 && strcmp($ip_range[1], $ip_address) <= 0) + { + $banned = true; + } + } + elseif($ip_address == $ip_range) + { + $banned = true; + } + if($banned) + { + // Updating last use + if($update_lastuse == true) + { + $db->update_query("banfilters", array("lastuse" => TIME_NOW), "fid='{$banned_ip['fid']}'"); + } + return true; + } + } + + // Still here - good ip + return false; +} + +/** + * Build a time zone selection list. + * + * @param string The name of the select + * @param int The selected time zone (defaults to GMT) + * @param boolean True to generate a "short" list with just timezone and current time + */ +function build_timezone_select($name, $selected=0, $short=false) +{ + global $mybb, $lang, $templates; + + $timezones = array( + "-12" => $lang->timezone_gmt_minus_1200, + "-11" => $lang->timezone_gmt_minus_1100, + "-10" => $lang->timezone_gmt_minus_1000, + "-9.5" => $lang->timezone_gmt_minus_950, + "-9" => $lang->timezone_gmt_minus_900, + "-8" => $lang->timezone_gmt_minus_800, + "-7" => $lang->timezone_gmt_minus_700, + "-6" => $lang->timezone_gmt_minus_600, + "-5" => $lang->timezone_gmt_minus_500, + "-4.5" => $lang->timezone_gmt_minus_450, + "-4" => $lang->timezone_gmt_minus_400, + "-3.5" => $lang->timezone_gmt_minus_350, + "-3" => $lang->timezone_gmt_minus_300, + "-2" => $lang->timezone_gmt_minus_200, + "-1" => $lang->timezone_gmt_minus_100, + "0" => $lang->timezone_gmt, + "1" => $lang->timezone_gmt_100, + "2" => $lang->timezone_gmt_200, + "3" => $lang->timezone_gmt_300, + "3.5" => $lang->timezone_gmt_350, + "4" => $lang->timezone_gmt_400, + "4.5" => $lang->timezone_gmt_450, + "5" => $lang->timezone_gmt_500, + "5.5" => $lang->timezone_gmt_550, + "5.75" => $lang->timezone_gmt_575, + "6" => $lang->timezone_gmt_600, + "6.5" => $lang->timezone_gmt_650, + "7" => $lang->timezone_gmt_700, + "8" => $lang->timezone_gmt_800, + "9" => $lang->timezone_gmt_900, + "9.5" => $lang->timezone_gmt_950, + "10" => $lang->timezone_gmt_1000, + "10.5" => $lang->timezone_gmt_1050, + "11" => $lang->timezone_gmt_1100, + "11.5" => $lang->timezone_gmt_1150, + "12" => $lang->timezone_gmt_1200, + "12.75" => $lang->timezone_gmt_1275, + "13" => $lang->timezone_gmt_1300, + "14" => $lang->timezone_gmt_1400 + ); + + $selected = str_replace("+", "", $selected); + foreach($timezones as $timezone => $label) + { + $selected_add = ""; + if($selected == $timezone) + { + $selected_add = " selected=\"selected\""; + } + if($short == true) + { + $label = ''; + if($timezone != 0) + { + $label = $timezone; + if($timezone > 0) + { + $label = "+{$label}"; + } + if(strpos($timezone, ".") !== false) + { + $label = str_replace(".", ":", $label); + $label = str_replace(":5", ":30", $label); + $label = str_replace(":75", ":45", $label); + } + else + { + $label .= ":00"; + } + } + $time_in_zone = my_date($mybb->settings['timeformat'], TIME_NOW, $timezone); + $label = $lang->sprintf($lang->timezone_gmt_short, $label." ", $time_in_zone); + } + + eval("\$timezone_option .= \"".$templates->get("usercp_options_timezone_option")."\";"); + } + + eval("\$select = \"".$templates->get("usercp_options_timezone")."\";"); + return $select; +} + +/** + * Fetch the contents of a remote fle. + * + * @param string The URL of the remote file + * @param array The array of post data + * @return string The remote file contents. + */ +function fetch_remote_file($url, $post_data=array()) +{ + $post_body = ''; + if(!empty($post_data)) + { + foreach($post_data as $key => $val) + { + $post_body .= '&'.urlencode($key).'='.urlencode($val); + } + $post_body = ltrim($post_body, '&'); + } + + if(function_exists("curl_init")) + { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + if(!empty($post_body)) + { + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $post_body); + } + $data = curl_exec($ch); + curl_close($ch); + return $data; + } + else if(function_exists("fsockopen")) + { + $url = @parse_url($url); + if(!$url['host']) + { + return false; + } + if(!$url['port']) + { + $url['port'] = 80; + } + if(!$url['path']) + { + $url['path'] = "/"; + } + if($url['query']) + { + $url['path'] .= "?{$url['query']}"; + } + $fp = @fsockopen($url['host'], $url['port'], $error_no, $error, 10); + @stream_set_timeout($fp, 10); + if(!$fp) + { + return false; + } + $headers = array(); + if(!empty($post_body)) + { + $headers[] = "POST {$url['path']} HTTP/1.0"; + $headers[] = "Content-Length: ".strlen($post_body); + $headers[] = "Content-Type: application/x-www-form-urlencoded"; + } + else + { + $headers[] = "GET {$url['path']} HTTP/1.0"; + } + + $headers[] = "Host: {$url['host']}"; + $headers[] = "Connection: Close"; + $headers[] = ''; + + if(!empty($post_body)) + { + $headers[] = $post_body; + } + else + { + // If we have no post body, we need to add an empty element to make sure we've got \r\n\r\n before the (non-existent) body starts + $headers[] = ''; + } + + $headers = implode("\r\n", $headers); + if(!@fwrite($fp, $headers)) + { + return false; + } + while(!feof($fp)) + { + $data .= fgets($fp, 12800); + } + fclose($fp); + $data = explode("\r\n\r\n", $data, 2); + return $data[1]; + } + else if(empty($post_data)) + { + return @implode("", @file($url)); + } + else + { + return false; + } +} + +/** + * Checks if a particular user is a super administrator. + * + * @param int The user ID to check against the list of super admins + * @return boolean True if a super admin, false if not + */ +function is_super_admin($uid) +{ + static $super_admins; + + if(!isset($super_admins)) + { + global $mybb; + $super_admins = str_replace(" ", "", $mybb->config['super_admins']); + } + + if(my_strpos(",{$super_admins},", ",{$uid},") === false) + { + return false; + } + else + { + return true; + } +} + +/** + * Checks if a user is a member of a particular group + * Originates from frostschutz's PluginLibrary + * github.com/frostschutz + * + * @param mixed A selection of groups to check + * @param mixed User to check selection against + * @return mixed Array of groups this user belongs to + */ +function is_member($groups, $user = false) +{ + global $mybb; + + if($user == false) + { + $user = $mybb->user; + } + else if(!is_array($user)) + { + // Assume it's a UID + $user = get_user($user); + } + + $memberships = array_map('intval', explode(',', $user['additionalgroups'])); + $memberships[] = $user['usergroup']; + + if(!is_array($groups)) + { + if(is_string($groups)) + { + $groups = explode(',', $groups); + } + else + { + $groups = (array)$groups; + } + } + + $groups = array_filter(array_map('intval', $groups)); + + return array_intersect($groups, $memberships); +} + +/** + * Split a string based on the specified delimeter, ignoring said delimeter in escaped strings. + * Ex: the "quick brown fox" jumped, could return 1 => the, 2 => quick brown fox, 3 => jumped + * + * @param string The delimeter to split by + * @param string The string to split + * @param string The escape character or string if we have one. + * @return array Array of split string + */ +function escaped_explode($delimeter, $string, $escape="") +{ + $strings = array(); + $original = $string; + $in_escape = false; + if($escape) + { + if(is_array($escape)) + { + function escaped_explode_escape($string) + { + return preg_quote($string, "#"); + } + $escape_preg = "(".implode("|", array_map("escaped_explode_escape", $escape)).")"; + } + else + { + $escape_preg = preg_quote($escape, "#"); + } + $quoted_strings = preg_split("#(? "1 {$lang->day}", + "2-0-0" => "2 {$lang->days}", + "3-0-0" => "3 {$lang->days}", + "4-0-0" => "4 {$lang->days}", + "5-0-0" => "5 {$lang->days}", + "6-0-0" => "6 {$lang->days}", + "7-0-0" => "1 {$lang->week}", + "14-0-0" => "2 {$lang->weeks}", + "21-0-0" => "3 {$lang->weeks}", + "0-1-0" => "1 {$lang->month}", + "0-2-0" => "2 {$lang->months}", + "0-3-0" => "3 {$lang->months}", + "0-4-0" => "4 {$lang->months}", + "0-5-0" => "5 {$lang->months}", + "0-6-0" => "6 {$lang->months}", + "0-0-1" => "1 {$lang->year}", + "0-0-2" => "2 {$lang->years}" + ); + + $ban_times = $plugins->run_hooks("functions_fetch_ban_times", $ban_times); + + $ban_times['---'] = $lang->permanent; + return $ban_times; +} + +/** + * Format a ban length in to a UNIX timestamp. + * + * @param string The ban length string + * @param int The optional UNIX timestamp, if 0, current time is used. + * @return int The UNIX timestamp when the ban will be lifted + */ +function ban_date2timestamp($date, $stamp=0) +{ + if($stamp == 0) + { + $stamp = TIME_NOW; + } + $d = explode('-', $date); + $nowdate = date("H-j-n-Y", $stamp); + $n = explode('-', $nowdate); + $n[1] += $d[0]; + $n[2] += $d[1]; + $n[3] += $d[2]; + return mktime(date("G"), date("i"), 0, $n[2], $n[1], $n[3]); +} + +/** + * Expire old warnings in the database. + * + */ +function expire_warnings() +{ + global $warningshandler; + + if(!is_object($warningshandler)) + { + require_once MYBB_ROOT.'inc/datahandlers/warnings.php'; + $warningshandler = new WarningsHandler('update'); + } + + return $warningshandler->expire_warnings(); +} + +/** + * Custom chmod function to fix problems with hosts who's server configurations screw up umasks + * + * @param string The file to chmod + * @param string The mode to chmod(i.e. 0666) + */ +function my_chmod($file, $mode) +{ + // Passing $mode as an octal number causes strlen and substr to return incorrect values. Instead pass as a string + if(substr($mode, 0, 1) != '0' || strlen($mode) !== 4) + { + return false; + } + $old_umask = umask(0); + + // We convert the octal string to a decimal number because passing a octal string doesn't work with chmod + // and type casting subsequently removes the prepended 0 which is needed for octal numbers + $result = chmod($file, octdec($mode)); + umask($old_umask); + return $result; +} + +/** + * Custom rmdir function to loop through an entire directory and delete all files/folders within + * + * @param string The path to the directory + * @param array Any files you wish to ignore (optional) + */ +function my_rmdir_recursive($path, $ignore=array()) +{ + global $orig_dir; + + if(!isset($orig_dir)) + { + $orig_dir = $path; + } + + if(@is_dir($path) && !@is_link($path)) + { + if($dh = @opendir($path)) + { + while(($file = @readdir($dh)) !== false) + { + if($file == '.' || $file == '..' || $file == '.svn' || in_array($path.'/'.$file, $ignore) || !my_rmdir_recursive($path.'/'.$file)) + { + continue; + } + } + @closedir($dh); + } + + // Are we done? Don't delete the main folder too and return true + if($path == $orig_dir) + { + return true; + } + + return @rmdir($path); + } + + return @unlink($path); +} + +/** + * Counts the number of subforums in a array([pid][disporder][fid]) starting from the pid + * + * @param array The array of forums + * @return integer The number of sub forums + */ +function subforums_count($array) +{ + $count = 0; + foreach($array as $array2) + { + $count += count($array2); + } + + return $count; +} + +/** + * DEPRECATED! Please use IPv6 compatible my_inet_pton! + * Fix for PHP's ip2long to guarantee a 32-bit signed integer value is produced (this is aimed + * at 64-bit versions of PHP) + * + * @param string The IP to convert + * @return integer IP in 32-bit signed format + */ +function my_ip2long($ip) +{ + $ip_long = ip2long($ip); + + if(!$ip_long) + { + $ip_long = sprintf("%u", ip2long($ip)); + + if(!$ip_long) + { + return 0; + } + } + + if($ip_long >= 2147483648) // Won't occur on 32-bit PHP + { + $ip_long -= 4294967296; + } + + return $ip_long; +} + +/** + * DEPRECATED! Please use IPv6 compatible my_inet_ntop! + * As above, fix for PHP's long2ip on 64-bit versions + * + * @param integer The IP to convert (will accept 64-bit IPs as well) + * @return string IP in IPv4 format + */ +function my_long2ip($long) +{ + // On 64-bit machines is_int will return true. On 32-bit it will return false + if($long < 0 && is_int(2147483648)) + { + // We have a 64-bit system + $long += 4294967296; + } + return long2ip($long); +} + +/** + * Converts a human readable IP address to its packed in_addr representation + * + * @param string The IP to convert + * @return string IP in 32bit or 128bit binary format + */ +function my_inet_pton($ip) +{ + if(function_exists('inet_pton')) + { + return @inet_pton($ip); + } + else + { + /** + * Replace inet_pton() + * + * @category PHP + * @package PHP_Compat + * @license LGPL - http://www.gnu.org/licenses/lgpl.html + * @copyright 2004-2007 Aidan Lister , Arpad Ray + * @link http://php.net/inet_pton + * @author Arpad Ray + * @version $Revision: 269597 $ + */ + $r = ip2long($ip); + if($r !== false && $r != -1) + { + return pack('N', $r); + } + + $delim_count = substr_count($ip, ':'); + if($delim_count < 1 || $delim_count > 7) + { + return false; + } + + $r = explode(':', $ip); + $rcount = count($r); + if(($doub = array_search('', $r, 1)) !== false) + { + $length = (!$doub || $doub == $rcount - 1 ? 2 : 1); + array_splice($r, $doub, $length, array_fill(0, 8 + $length - $rcount, 0)); + } + + $r = array_map('hexdec', $r); + array_unshift($r, 'n*'); + $r = call_user_func_array('pack', $r); + + return $r; + } +} + +/** + * Converts a packed internet address to a human readable representation + * + * @param string IP in 32bit or 128bit binary format + * @return string IP in human readable format + */ +function my_inet_ntop($ip) +{ + if(function_exists('inet_ntop')) + { + return @inet_ntop($ip); + } + else + { + /** + * Replace inet_ntop() + * + * @category PHP + * @package PHP_Compat + * @license LGPL - http://www.gnu.org/licenses/lgpl.html + * @copyright 2004-2007 Aidan Lister , Arpad Ray + * @link http://php.net/inet_ntop + * @author Arpad Ray + * @version $Revision: 269597 $ + */ + switch(strlen($ip)) + { + case 4: + list(,$r) = unpack('N', $ip); + return long2ip($r); + case 16: + $r = substr(chunk_split(bin2hex($ip), 4, ':'), 0, -1); + $r = preg_replace( + array('/(?::?\b0+\b:?){2,}/', '/\b0+([^0])/e'), + array('::', '(int)"$1"?"$1":"0$1"'), + $r); + return $r; + } + return false; + } +} + +/** + * Fetch an binary formatted range for searching IPv4 and IPv6 IP addresses. + * + * @param string The IP address to convert to a range + * @rturn mixed If a full IP address is provided, the in_addr representation, otherwise an array of the upper & lower extremities of the IP + */ +function fetch_ip_range($ipaddress) +{ + // Wildcard + if(strpos($ipaddress, '*') !== false) + { + if(strpos($ipaddress, ':') !== false) + { + // IPv6 + $upper = str_replace('*', 'ffff', $ipaddress); + $lower = str_replace('*', '0', $ipaddress); + } + else + { + // IPv4 + $upper = str_replace('*', '255', $ipaddress); + $lower = str_replace('*', '0', $ipaddress); + } + $upper = my_inet_pton($upper); + $lower = my_inet_pton($lower); + if($upper === false || $lower === false) + { + return false; + } + return array($lower, $upper); + } + // CIDR notation + elseif(strpos($ipaddress, '/') !== false) + { + $ipaddress = explode('/', $ipaddress); + $ip_address = $ipaddress[0]; + $ip_range = (int)$ipaddress[1]; + + if(empty($ip_address) || empty($ip_range)) + { + // Invalid input + return false; + } + else + { + $ip_address = my_inet_pton($ip_address); + + if(!$ip_address) + { + // Invalid IP address + return false; + } + } + + /** + * Taken from: https://github.com/NewEraCracker/php_work/blob/master/ipRangeCalculate.php + * Author: NewEraCracker + * License: Public Domain + */ + + // Pack IP, Set some vars + $ip_pack = $ip_address; + $ip_pack_size = strlen($ip_pack); + $ip_bits_size = $ip_pack_size*8; + + // IP bits (lots of 0's and 1's) + $ip_bits = ''; + for($i = 0; $i < $ip_pack_size; $i = $i+1) + { + $bit = decbin(ord($ip_pack[$i])); + $bit = str_pad($bit, 8, '0', STR_PAD_LEFT); + $ip_bits .= $bit; + } + + // Significative bits (from the ip range) + $ip_bits = substr($ip_bits, 0, $ip_range); + + // Some calculations + $ip_lower_bits = str_pad($ip_bits, $ip_bits_size, '0', STR_PAD_RIGHT); + $ip_higher_bits = str_pad($ip_bits, $ip_bits_size, '1', STR_PAD_RIGHT); + + // Lower IP + $ip_lower_pack = ''; + for($i=0; $i < $ip_bits_size; $i=$i+8) + { + $chr = substr($ip_lower_bits, $i, 8); + $chr = chr(bindec($chr)); + $ip_lower_pack .= $chr; + } + + // Higher IP + $ip_higher_pack = ''; + for($i=0; $i < $ip_bits_size; $i=$i+8) + { + $chr = substr($ip_higher_bits, $i, 8); + $chr = chr( bindec($chr) ); + $ip_higher_pack .= $chr; + } + + return array($ip_lower_pack, $ip_higher_pack); + } + // Just on IP address + else + { + return my_inet_pton($ipaddress); + } +} + +/** + * Time how long it takes for a particular piece of code to run. Place calls above & below the block of code. + * + * @return float The time taken + */ +function get_execution_time() +{ + static $time_start; + + $time = microtime(true); + + + // Just starting timer, init and return + if(!$time_start) + { + $time_start = $time; + return; + } + // Timer has run, return execution time + else + { + $total = $time-$time_start; + if($total < 0) $total = 0; + $time_start = 0; + return $total; + } +} + +/** + * Processes a checksum list on MyBB files and returns a result set + * + * @param array The array of checksums and their corresponding files + * @param int The count of files + * @return array The bad files + */ +function verify_files($path=MYBB_ROOT, $count=0) +{ + global $mybb, $checksums, $bad_verify_files; + + // We don't need to check these types of files + $ignore = array(".", "..", ".svn", "config.php", "settings.php", "Thumb.db", "config.default.php", "lock", "htaccess.txt", "logo.gif", "logo.png"); + $ignore_ext = array("attach"); + + if(substr($path, -1, 1) == "/") + { + $path = substr($path, 0, -1); + } + + if(!is_array($bad_verify_files)) + { + $bad_verify_files = array(); + } + + // Make sure that we're in a directory and it's not a symbolic link + if(@is_dir($path) && !@is_link($path)) + { + if($dh = @opendir($path)) + { + // Loop through all the files/directories in this directory + while(($file = @readdir($dh)) !== false) + { + if(in_array($file, $ignore) || in_array(get_extension($file), $ignore_ext)) + { + continue; + } + + // Recurse through the directory tree + if(is_dir($path."/".$file)) + { + verify_files($path."/".$file, ($count+1)); + continue; + } + + // We only need the last part of the path (from the MyBB directory to the file. i.e. inc/functions.php) + $file_path = ".".str_replace(substr(MYBB_ROOT, 0, -1), "", $path)."/".$file; + + // Does this file even exist in our official list? Perhaps it's a plugin + if(array_key_exists($file_path, $checksums)) + { + $filename = $path."/".$file; + $handle = fopen($filename, "rb"); + $contents = ''; + while(!feof($handle)) + { + $contents .= fread($handle, 8192); + } + fclose($handle); + + $md5 = md5($contents); + + // Does it match any of our hashes (unix/windows new lines taken into consideration with the hashes) + if(!in_array($md5, $checksums[$file_path])) + { + $bad_verify_files[] = array("status" => "changed", "path" => $file_path); + } + } + unset($checksums[$file_path]); + } + @closedir($dh); + } + } + + if($count == 0) + { + if(!empty($checksums)) + { + foreach($checksums as $file_path => $hashes) + { + if(in_array(basename($file_path), $ignore)) + { + continue; + } + $bad_verify_files[] = array("status" => "missing", "path" => $file_path); + } + } + } + + // uh oh + if($count == 0) + { + return $bad_verify_files; + } +} + +/** + * Returns a signed value equal to an integer + * + * @param int The integer + * @return string The signed equivalent + */ +function signed($int) +{ + if($int < 0) + { + return "$int"; + } + else + { + return "+$int"; + } +} + +/** + * Returns a securely generated seed for PHP's RNG (Random Number Generator) + * + * @param int Length of the seed bytes (8 is default. Provides good cryptographic variance) + * @return int An integer equivalent of a secure hexadecimal seed + */ +function secure_seed_rng($count=8) +{ + $output = ''; + // DIRECTORY_SEPARATOR checks if running windows + if(DIRECTORY_SEPARATOR != '\\') + { + // Unix/Linux + // Use OpenSSL when available + if(function_exists('openssl_random_pseudo_bytes')) + { + $output = openssl_random_pseudo_bytes($count); + } + // Try mcrypt + elseif(function_exists('mcrypt_create_iv')) + { + $output = mcrypt_create_iv($count, MCRYPT_DEV_URANDOM); + } + // Try /dev/urandom + elseif(@is_readable('/dev/urandom') && ($handle = @fopen('/dev/urandom', 'rb'))) + { + $output = @fread($handle, $count); + @fclose($handle); + } + } + else + { + // Windows + // Use OpenSSL when available + // PHP <5.3.4 had a bug which makes that function unusable on Windows + if(function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) + { + $output = openssl_random_pseudo_bytes($count); + } + // Try mcrypt + elseif(function_exists('mcrypt_create_iv')) + { + $output = mcrypt_create_iv($count, MCRYPT_RAND); + } + // Try Windows CAPICOM before using our own generator + elseif(class_exists('COM')) + { + try + { + $CAPI_Util = new COM('CAPICOM.Utilities.1'); + if(is_callable(array($CAPI_Util, 'GetRandom'))) + { + $output = $CAPI_Util->GetRandom($count, 0); + } + } catch (Exception $e) { + } + } + } + + // Didn't work? Do we still not have enough bytes? Use our own (less secure) rng generator + if(strlen($output) < $count) + { + $output = ''; + + // Close to what PHP basically uses internally to seed, but not quite. + $unique_state = microtime().@getmypid(); + + for($i = 0; $i < $count; $i += 16) + { + $unique_state = md5(microtime().$unique_state); + $output .= pack('H*', md5($unique_state)); + } + } + + // /dev/urandom and openssl will always be twice as long as $count. base64_encode will roughly take up 33% more space but crc32 will put it to 32 characters + $output = hexdec(substr(dechex(crc32(base64_encode($output))), 0, $count)); + + return $output; +} + +/** + * Wrapper function for mt_rand. Automatically seeds using a secure seed once. + * + * @param int Optional lowest value to be returned (default: 0) + * @param int Optional highest value to be returned (default: mt_getrandmax()) + * @param boolean True forces it to reseed the RNG first + * @return int An integer equivalent of a secure hexadecimal seed + */ +function my_rand($min=null, $max=null, $force_seed=false) +{ + static $seeded = false; + static $obfuscator = 0; + + if($seeded == false || $force_seed == true) + { + mt_srand(secure_seed_rng()); + $seeded = true; + + $obfuscator = abs((int) secure_seed_rng()); + + // Ensure that $obfuscator is <= mt_getrandmax() for 64 bit systems. + if($obfuscator > mt_getrandmax()) + { + $obfuscator -= mt_getrandmax(); + } + } + + if($min !== null && $max !== null) + { + $distance = $max - $min; + if($distance > 0) + { + return $min + (int)((float)($distance + 1) * (float)(mt_rand() ^ $obfuscator) / (mt_getrandmax() + 1)); + } + else + { + return mt_rand($min, $max); + } + } + else + { + $val = mt_rand() ^ $obfuscator; + return $val; + } +} + +/** + * More robust version of PHP's trim() function. It includes a list of UTF-16 blank characters + * from http://kb.mozillazine.org/Network.IDN.blacklist_chars + * + * @param string The string to trim from + * @param string Optional. The stripped characters can also be specified using the charlist parameter + * @return string The trimmed string + */ +function trim_blank_chrs($string, $charlist=false) +{ + $hex_chrs = array( + 0x20 => 1, + 0x09 => 1, + 0x0A => 1, + 0x0D => 1, + 0x0B => 1, + 0xAD => 1, + 0xA0 => 1, + 0xAD => 1, + 0xBF => 1, + 0x81 => 1, + 0x8D => 1, + 0x90 => 1, + 0x9D => 1, + 0xCC => array(0xB7 => 1, 0xB8 => 1), // \x{0337} or \x{0338} + 0xE1 => array(0x85 => array(0x9F => 1, 0xA0 => 1)), // \x{115F} or \x{1160} + 0xE2 => array(0x80 => array(0x80 => 1, 0x81 => 1, 0x82 => 1, 0x83 => 1, 0x84 => 1, 0x85 => 1, 0x86 => 1, 0x87 => 1, 0x88 => 1, 0x89 => 1, 0x8A => 1, 0x8B => 1, // \x{2000} to \x{200B} + 0xA8 => 1, 0xA9 => 1, 0xAA => 1, 0xAB => 1, 0xAC => 1, 0xAD => 1, 0xAE => 1, 0xAF => 1), // \x{2028} to \x{202F} + 0x81 => array(0x9F => 1)), // \x{205F} + 0xE3 => array(0x80 => array(0x80 => 1), // \x{3000} + 0x85 => array(0xA4 => 1)), // \x{3164} + 0xEF => array(0xBB => array(0xBF => 1), // \x{FEFF} + 0xBE => array(0xA0 => 1), // \x{FFA0} + 0xBF => array(0xB9 => 1, 0xBA => 1, 0xBB => 1)), // \x{FFF9} to \x{FFFB} + ); + + $hex_chrs_rev = array( + 0x20 => 1, + 0x09 => 1, + 0x0A => 1, + 0x0D => 1, + 0x0B => 1, + 0xA0 => array(0xC2 => 1), + 0xAD => array(0xC2 => 1), + 0xBF => array(0xC2 => 1), + 0x81 => array(0xC2 => 1), + 0x8D => array(0xC2 => 1), + 0x90 => array(0xC2 => 1), + 0x9D => array(0xC2 => 1), + 0xB8 => array(0xCC => 1), // \x{0338} + 0xB7 => array(0xCC => 1), // \x{0337} + 0xA0 => array(0x85 => array(0xE1 => 1)), // \x{1160} + 0x9F => array(0x85 => array(0xE1 => 1), // \x{115F} + 0x81 => array(0xE2 => 1)), // \x{205F} + 0x80 => array(0x80 => array(0xE3 => 1, 0xE2 => 1)), // \x{3000}, \x{2000} + 0x81 => array(0x80 => array(0xE2 => 1)), // \x{2001} + 0x82 => array(0x80 => array(0xE2 => 1)), // \x{2002} + 0x83 => array(0x80 => array(0xE2 => 1)), // \x{2003} + 0x84 => array(0x80 => array(0xE2 => 1)), // \x{2004} + 0x85 => array(0x80 => array(0xE2 => 1)), // \x{2005} + 0x86 => array(0x80 => array(0xE2 => 1)), // \x{2006} + 0x87 => array(0x80 => array(0xE2 => 1)), // \x{2007} + 0x88 => array(0x80 => array(0xE2 => 1)), // \x{2008} + 0x89 => array(0x80 => array(0xE2 => 1)), // \x{2009} + 0x8A => array(0x80 => array(0xE2 => 1)), // \x{200A} + 0x8B => array(0x80 => array(0xE2 => 1)), // \x{200B} + 0xA8 => array(0x80 => array(0xE2 => 1)), // \x{2028} + 0xA9 => array(0x80 => array(0xE2 => 1)), // \x{2029} + 0xAA => array(0x80 => array(0xE2 => 1)), // \x{202A} + 0xAB => array(0x80 => array(0xE2 => 1)), // \x{202B} + 0xAC => array(0x80 => array(0xE2 => 1)), // \x{202C} + 0xAD => array(0x80 => array(0xE2 => 1)), // \x{202D} + 0xAE => array(0x80 => array(0xE2 => 1)), // \x{202E} + 0xAF => array(0x80 => array(0xE2 => 1)), // \x{202F} + 0xA4 => array(0x85 => array(0xE3 => 1)), // \x{3164} + 0xBF => array(0xBB => array(0xEF => 1)), // \x{FEFF} + 0xA0 => array(0xBE => array(0xEF => 1)), // \x{FFA0} + 0xB9 => array(0xBF => array(0xEF => 1)), // \x{FFF9} + 0xBA => array(0xBF => array(0xEF => 1)), // \x{FFFA} + 0xBB => array(0xBF => array(0xEF => 1)), // \x{FFFB} + ); + + // Start from the beginning and work our way in + do + { + // Check to see if we have matched a first character in our utf-16 array + $offset = match_sequence($string, $hex_chrs); + if(!$offset) + { + // If not, then we must have a "good" character and we don't need to do anymore processing + break; + } + $string = substr($string, $offset); + } + while(++$i); + + // Start from the end and work our way in + $string = strrev($string); + do + { + // Check to see if we have matched a first character in our utf-16 array + $offset = match_sequence($string, $hex_chrs_rev); + if(!$offset) + { + // If not, then we must have a "good" character and we don't need to do anymore processing + break; + } + $string = substr($string, $offset); + } + while(++$i); + $string = strrev($string); + + if($charlist !== false) + { + $string = trim($string, $charlist); + } + else + { + $string = trim($string); + } + + return $string; +} + +/** + * Match a sequence + * + * @param string The string to match from + * @param array The array to match from + * @param int Number in the string + * @param int Number of matches + * @return int The number matched + */ +function match_sequence($string, $array, $i=0, $n=0) +{ + if($string === "") + { + return 0; + } + + $ord = ord($string[$i]); + if(array_key_exists($ord, $array)) + { + $level = $array[$ord]; + ++$n; + if(is_array($level)) + { + ++$i; + return match_sequence($string, $level, $i, $n); + } + return $n; + } + + return 0; +} + +/** + * Obtain the version of GD installed. + * + * @return float Version of GD + */ +function gd_version() +{ + static $gd_version; + + if($gd_version) + { + return $gd_version; + } + if(!extension_loaded('gd')) + { + return; + } + + if(function_exists("gd_info")) + { + $gd_info = gd_info(); + preg_match('/\d/', $gd_info['GD Version'], $gd); + $gd_version = $gd[0]; + } + else + { + ob_start(); + phpinfo(8); + $info = ob_get_contents(); + ob_end_clean(); + $info = stristr($info, 'gd version'); + preg_match('/\d/', $info, $gd); + $gd_version = $gd[0]; + } + + return $gd_version; +} + +/* + * Validates an UTF-8 string. + * + * @param string The string to be checked + * @param boolean Allow 4 byte UTF-8 characters? + * @param boolean Return the cleaned string? + * @return string/boolean Cleaned string or boolean + */ +function validate_utf8_string($input, $allow_mb4=true, $return=true) +{ + // Valid UTF-8 sequence? + if(!preg_match('##u', $input)) + { + $string = ''; + $len = strlen($input); + for($i = 0; $i < $len; $i++) + { + $c = ord($input[$i]); + if($c > 128) + { + if($c > 247 || $c <= 191) + { + if($return) + { + $string .= '?'; + continue; + } + else + { + return false; + } + } + elseif($c > 239) + { + $bytes = 4; + } + elseif($c > 223) + { + $bytes = 3; + } + elseif($c > 191) + { + $bytes = 2; + } + if(($i + $bytes) > $len) + { + if($return) + { + $string .= '?'; + break; + } + else + { + return false; + } + } + $valid = true; + $multibytes = $input[$i]; + while($bytes > 1) + { + $i++; + $b = ord($input[$i]); + if($b < 128 || $b > 191) + { + if($return) + { + $valid = false; + $string .= '?'; + break; + } + else + { + return false; + } + } + else + { + $multibytes .= $input[$i]; + } + $bytes--; + } + if($valid) + { + $string .= $multibytes; + } + } + else + { + $string .= $input[$i]; + } + } + $input = $string; + } + if($return) + { + if($allow_mb4) + { + return $input; + } + else + { + return preg_replace("#[^\\x00-\\x7F][\\x80-\\xBF]{3,}#", '?', $input); + } + } + else + { + if($allow_mb4) + { + return true; + } + else + { + return !preg_match("#[^\\x00-\\x7F][\\x80-\\xBF]{3,}#", $input); + } + } +} + +/** + * Send a Private Message to a user. + * + * @param array Array containing: 'subject', 'message', 'touid' and 'receivepms' (the latter should reflect the value found in the users table: receivepms and receivefrombuddy) + * @param int Sender UID (0 if you want to use $mybb->user['uid'] or -1 to use MyBB Engine) + * @param bool Whether or not do override user defined options for receiving PMs + * @return bool True if PM sent + */ +function send_pm($pm, $fromid = 0, $admin_override=false) +{ + global $lang, $mybb, $db, $session; + + if($mybb->settings['enablepms'] == 0) + { + return false; + } + + if(!is_array($pm)) + { + return false; + } + + if(isset($pm['language'])) + { + if($pm['language'] != $mybb->user['language'] && $lang->language_exists($pm['language'])) + { + // Load user language + $lang->set_language($pm['language']); + $lang->load($pm['language_file']); + + $revert = true; + } + + foreach(array('subject', 'message') as $key) + { + $lang_string = $pm[$key]; + if(is_array($pm[$key])) + { + $num_args = count($pm[$key]); + + for($i = 1; $i < $num_args; $i++) + { + $lang->{$pm[$key][0]} = str_replace('{'.$i.'}', $pm[$key][$i], $lang->{$pm[$key][0]}); + } + + $lang_string = $pm[$key][0]; + } + + $pm[$key] = $lang->{$lang_string}; + } + + if(isset($revert)) + { + // Revert language + $lang->set_language($mybb->user['language']); + $lang->load($pm['language_file']); + } + } + + if(!$pm['subject'] ||!$pm['message'] || !$pm['touid'] || (!$pm['receivepms'] && !$admin_override)) + { + return false; + } + + $lang->load('messages'); + + require_once MYBB_ROOT."inc/datahandlers/pm.php"; + + $pmhandler = new PMDataHandler(); + + $subject = $pm['subject']; + $message = $pm['message']; + $toid = $pm['touid']; + + // Our recipients + if(is_array($toid)) + { + $recipients_to = $toid; + } + else + { + $recipients_to = array($toid); + } + + $recipients_bcc = array(); + + // Determine user ID + if((int)$fromid == 0) + { + $fromid = (int)$mybb->user['uid']; + } + elseif((int)$fromid < 0) + { + $fromid = 0; + } + + // Build our final PM array + $pm = array( + "subject" => $subject, + "message" => $message, + "icon" => -1, + "fromid" => $fromid, + "toid" => $recipients_to, + "bccid" => $recipients_bcc, + "do" => '', + "pmid" => '' + ); + + if(isset($session)) + { + $pm['ipaddress'] = $session->packedip; + } + + $pm['options'] = array( + "signature" => 0, + "disablesmilies" => 0, + "savecopy" => 0, + "readreceipt" => 0 + ); + + $pm['saveasdraft'] = 0; + + // Admin override + $pmhandler->admin_override = (int)$admin_override; + + $pmhandler->set_data($pm); + + if($pmhandler->validate_pm()) + { + $pmhandler->insert_pm(); + return true; + } + + return false; +} + +/** + * Log a user spam block from StopForumSpam (or other spam service providers...) + * + * @param string $username The username that the user was using. + * @param string $email The email address the user was using. + * @param string $ip_address The IP addres of the user. + * @param array $data An array of extra data to go with the block (eg: confidence rating). + * @return bool Whether the action was logged successfully. + */ +function log_spam_block($username = '', $email = '', $ip_address = '', $data = array()) +{ + global $db, $session; + + if(!is_array($data)) + { + $data = array($data); + } + + if(!$ip_address) + { + $ip_address = get_ip(); + } + + $ip_address = my_inet_pton($ip_address); + + $insert_array = array( + 'username' => $db->escape_string($username), + 'email' => $db->escape_string($email), + 'ipaddress' => $db->escape_binary($ip_address), + 'dateline' => (int)TIME_NOW, + 'data' => $db->escape_string(@serialize($data)), + ); + + return (bool)$db->insert_query('spamlog', $insert_array); +} diff --git a/Upload/inc/functions_archive.php b/Upload/inc/functions_archive.php new file mode 100644 index 0000000..da46c71 --- /dev/null +++ b/Upload/inc/functions_archive.php @@ -0,0 +1,269 @@ +settings['bbname']; + } + else + { + $title = $mybb->settings['bbname']." - ".$title; + } + + // If the language doesn't have a charset, make it UTF-8. + if($lang->settings['charset']) + { + $charset = $lang->settings['charset']; + } + else + { + $charset = "utf-8"; + } + + $dir = ''; + if($lang->settings['rtl'] == 1) + { + $dir = " dir=\"rtl\""; + } + + if($lang->settings['htmllang']) + { + $htmllang = " xml:lang=\"".$lang->settings['htmllang']."\" lang=\"".$lang->settings['htmllang']."\""; + } + else + { + $htmllang = " xml:lang=\"en\" lang=\"en\""; + } +?> + +> + +<?php echo $title; ?> + + + + + + +
    +

    settings['bbname_orig']; ?>

    + +
    archive_fullversion; ?>
    +
    sprintf($lang->archive_note, $fullurl); ?>
    +
    + $navbit) + { + if(!empty($navbits[$key+1])) + { + if(!empty($navbits[$key+2])) + { + $sep = $navsep; + } + else + { + $sep = ""; + } + $nav .= "".$navbit['name']."$sep"; + } + } + } + $navsize = count($navbits); + $navbit = $navbits[$navsize-1]; + if(!empty($nav)) + { + $activesep = $navsep; + } + $nav .= $activesep.$navbit['name']; + + return $nav; +} + +/** + * Output multipage navigation. + * + * @param int The total number of items. + * @param int The items per page. + * @param int The current page. + * @param string The URL base. +*/ +function archive_multipage($count, $perpage, $page, $url) +{ + global $lang; + if($count > $perpage) + { + $pages = $count / $perpage; + $pages = ceil($pages); + + $mppage = null; + for($i = 1; $i <= $pages; ++$i) + { + if($i == $page) + { + $mppage .= "$i "; + } + else + { + $mppage .= "$i "; + } + } + $multipage = "
    ".$lang->archive_pages." $mppage
    "; + echo $multipage; + } +} + +/** + * Output the archive footer. + * + */ +function archive_footer() +{ + global $mybb, $lang, $db, $nav, $maintimer, $fulltitle, $fullurl, $sent_header; + $totaltime = $maintimer->stop(); + if($mybb->settings['showvernum'] == 1) + { + $mybbversion = ' '.$mybb->version; + } + else + { + $mybbversion = ""; + } +?> +
    + +
    + + + +settings['bbname'], $mybb->settings['bburl']."/index.php"); + } +?> +
    +
    error; ?>
    +
    +
    + '1', + "location1" => 0, + "location2" => 0 + ); + + $db->update_query("sessions", $noperm_array, "sid='{$session->sid}'"); + + archive_error($lang->archive_nopermission); +} + +/** + * Check the password given on a certain forum for validity + * + * @param int The forum ID + * @param boolean The Parent ID + */ +function check_forum_password_archive($fid, $pid=0) +{ + global $forum_cache; + + if(!is_array($forum_cache)) + { + $forum_cache = cache_forums(); + if(!$forum_cache) + { + return false; + } + } + + // Loop through each of parent forums to ensure we have a password for them too + $parents = explode(',', $forum_cache[$fid]['parentlist']); + rsort($parents); + if(!empty($parents)) + { + foreach($parents as $parent_id) + { + if($parent_id == $fid || $parent_id == $pid) + { + continue; + } + + if($forum_cache[$parent_id]['password'] != "") + { + check_forum_password_archive($parent_id, $fid); + } + } + } + + $password = $forum_cache[$fid]['password']; + if($password) + { + if(!$mybb->cookies['forumpass'][$fid] || ($mybb->cookies['forumpass'][$fid] && md5($mybb->user['uid'].$password) != $mybb->cookies['forumpass'][$fid])) + { + archive_error_no_permission(); + } + } +} +?> \ No newline at end of file diff --git a/Upload/inc/functions_calendar.php b/Upload/inc/functions_calendar.php new file mode 100644 index 0000000..37603d4 --- /dev/null +++ b/Upload/inc/functions_calendar.php @@ -0,0 +1,1100 @@ + my_date("Y")+5) + { + $year = my_date("Y"); + } + + // Then the month + if($month < 1 || $month > 12) + { + $month = my_date("n"); + } + + $weekdays = fetch_weekday_structure($calendar['startofweek']); + + $calendar_permissions = get_calendar_permissions($calendar['cid']); + + $month_link = get_calendar_link($calendar['cid'], $year, $month); + + $next_month = get_next_month($month, $year); + $prev_month = get_prev_month($month, $year); + + $month_start_weekday = gmdate("w", gmmktime(0, 0, 0, $month, $calendar['startofweek']+1, $year)); + if($month_start_weekday != $weekdays[0] || $calendar['startofweek'] != 0) + { + $day = gmdate("t", gmmktime(0, 0, 0, $prev_month['month'], 1, $prev_month['year'])); + $day -= array_search(($month_start_weekday), $weekdays); + $day += $calendar['startofweek']+1; + $calendar_month = $prev_month['month']; + $calendar_year = $prev_month['year']; + + if($day > 31 && $calendar['startofweek'] == 1 && $prev_month_days == 30) + { + // We need to fix it for these days + $day = 25; + } + } + else + { + $day = $calendar['startofweek']+1; + $calendar_month = $month; + $calendar_year = $year; + } + + $prev_month_days = gmdate("t", gmmktime(0, 0, 0, $prev_month['month'], 1, $prev_month['year'])); + + // So now we fetch events for this month + $start_timestamp = gmmktime(0, 0, 0, $calendar_month, $day, $year); + $num_days = gmdate("t", gmmktime(0, 0, 0, $month, 1, $year)); + $end_timestamp = gmmktime(23, 59, 59, $month, $num_days, $year); + + if(!$events_cache) + { + $events_cache = get_events($calendar, $start_timestamp, $end_timestamp, $calendar_permissions['canmoderateevents']); + } + + $today = my_date("dnY"); + + // Build weekday headers + $weekday_headers = ''; + foreach($weekdays as $weekday) + { + $weekday_name = fetch_weekday_name($weekday, true); + eval("\$weekday_headers .= \"".$templates->get("calendar_mini_weekdayheader")."\";"); + } + + $in_month = 0; + $day_bits = $calendar_rows = ''; + for($row = 0; $row < 6; ++$row) // Iterate weeks (each week gets a row) + { + foreach($weekdays as $weekday_id => $weekday) + { + // Current month always starts on 1st row + if($row == 0 && $day == $calendar['startofweek']+1) + { + $in_month = 1; + $calendar_month = $month; + $calendar_year = $year; + } + else if($calendar_month == $prev_month['month'] && $day > $prev_month_days) + { + $day = 1; + $in_month = 1; + $calendar_month = $month; + $calendar_year = $year; + } + else if($day > $num_days && $calendar_month != $prev_month['month']) + { + $in_month = 0; + $calendar_month = $next_month['month']; + $calendar_year = $next_month['year']; + $day = 1; + if($calendar_month == $month) + { + $in_month = 1; + } + } + + if($weekday_id == 0) + { + $week_stamp = gmmktime(0, 0, 0, $calendar_month, $day, $calendar_year); + $week_link = get_calendar_week_link($calendar['cid'], $week_stamp); + } + + if($weekday_id == 0 && $calendar_month == $next_month['month']) + { + break; + } + + $link_to_day = false; + // Any events on this specific day? + if(@count($events_cache["$day-$calendar_month-$calendar_year"]) > 0) + { + $link_to_day = true; + } + + // Is the current day + if($day.$calendar_month.$year == $today && $month == $calendar_month) + { + $day_class = "trow_sep"; + } + // Not in this month + else if($in_month == 0) + { + $day_class = "trow1"; + } + // Just a normal day in this month + else + { + $day_class = "trow2"; + } + if($link_to_day) + { + $day_link = "{$day}"; + } + else + { + $day_link = $day; + } + eval("\$day_bits .= \"".$templates->get("calendar_mini_weekrow_day")."\";"); + ++$day; + } + if($day_bits) + { + eval("\$calendar_rows .= \"".$templates->get("calendar_mini_weekrow")."\";"); + } + $day_bits = ""; + } + eval("\$mini_calendar = \"".$templates->get("calendar_mini")."\";"); + return $mini_calendar; +} + +/** + * Cache available calendars in to memory or return the cached calendars + * + * @return array Cached calendars + */ +function cache_calendars() +{ + global $db; + static $calendar_cache; + + if(is_array($calendar_cache)) + { + return $calendar_cache; + } + + $query = $db->simple_select("calendars", "*", "", array("order_by" => "disporder", "order_dir" => "asc")); + while($calendar = $db->fetch_array($query)) + { + $calendar_cache[$calendar['cid']] = $calendar; + } + return $calendar_cache; +} + +/** + * Fetch the calendar permissions for the current user for one or more calendars + * + * @param int Optional calendar ID. If none specified, permissions for all calendars are returned + * @return array Array of permissions + */ +function get_calendar_permissions($cid=0) +{ + global $db, $mybb; + static $calendar_permissions; + + $calendars = cache_calendars(); + + $group_permissions = array( + "canviewcalendar" => $mybb->usergroup['canviewcalendar'], + "canaddevents" => $mybb->usergroup['canaddevents'], + "canbypasseventmod" => $mybb->usergroup['canbypasseventmod'], + "canmoderateevents" => $mybb->usergroup['canmoderateevents'] + ); + + if(!is_array($calendars)) + { + return $group_permissions; + } + + $gid = $mybb->user['usergroup']; + + if(isset($mybb->user['additionalgroups'])) + { + $gid .= ",".$mybb->user['additionalgroups']; + } + + if(!is_array($calendar_permissions)) + { + $calendar_permissions = array(); + $query = $db->simple_select("calendarpermissions", "*"); + while($permission = $db->fetch_array($query)) + { + $calendar_permissions[$permission['cid']][$permission['gid']] = $permission; + } + + // Add in our usergroup permissions (if custom ones are set, these aren't added) + if(is_array($calendar_permissions)) + { + foreach($calendar_permissions as $calendar => $permission) + { + if(is_array($calendar_permissions[$calendar][$mybb->user['usergroup']])) + { + // Already has permissions set + continue; + } + + // Use the group permissions! + $calendar_permissions[$calendar][$mybb->user['usergroup']] = $group_permissions; + $calendar_permissions[$calendar][$mybb->user['usergroup']]['cid'] = $calendar; + $calendar_permissions[$calendar][$mybb->user['usergroup']]['gid'] = $mybb->user['usergroup']; + } + } + } + + if($cid > 0) + { + if(isset($calendar_permissions[$cid])) + { + $permissions = fetch_calendar_permissions($cid, $gid, $calendar_permissions[$cid]); + } + if(empty($permissions)) + { + $permissions = $group_permissions; + } + } + else + { + foreach($calendars as $calendar) + { + if(isset($calendar_permissions[$calendar['cid']])) + { + $permissions[$calendar['cid']] = fetch_calendar_permissions($calendar['cid'], $gid, $calendar_permissions[$calendar['cid']]); + } + if(empty($permissions[$calendar['cid']])) + { + $permissions[$calendar['cid']] = $group_permissions; + } + } + } + return $permissions; +} + +/** + * Fetch the calendar permissions + * + * @param int Calendar ID + * @param mixed User group ID + * @return array Array of permissions for this calendar and group + * @return array Array of current permissions + */ +function fetch_calendar_permissions($cid, $gid, $calendar_permissions) +{ + $groups = explode(",", $gid); + + if(!is_array($calendar_permissions)) + { + return; + } + + $current_permissions = array(); + + foreach($groups as $gid) + { + // If this calendar has permissions set for this group + if($calendar_permissions[$gid]) + { + $level_permissions = $calendar_permissions[$gid]; + foreach($level_permissions as $permission => $access) + { + if($access >= $current_permissions[$permission] || ($access == "yes" && $current_permissions[$permission] == "no") || !$current_permissions[$permission]) + { + $current_permissions[$permission] = $access; + } + } + } + } + + if(count($current_permissions) == 0) + { + return; + } + return $current_permissions; +} + +/** + * Build a calendar select list to jump between calendars + * + * @param int The selected calendar ID + * @return string The calendar select + */ +function build_calendar_jump($selected=0) +{ + global $db, $mybb, $templates, $lang, $gobutton; + + $calendar_permissions = get_calendar_permissions(); + + $calendars = cache_calendars(); + + if(!is_array($calendars)) + { + return; + } + + $jump_options = ''; + + foreach($calendars as $calendar) + { + if($calendar_permissions[$calendar['cid']]['canviewcalendar'] == 0) + { + continue; + } + $calendar['name'] = htmlspecialchars_uni($calendar['name']); + $sel = ""; + if($selected == $calendar['cid'] || ($selected == 0 && $calendar['disporder'] == 1)) + { + $sel = "selected=\"selected\""; + } + + eval("\$jump_options .= \"".$templates->get("calendar_jump_option")."\";"); + } + + eval("\$calendar_jump = \"".$templates->get("calendar_jump")."\";"); + return $calendar_jump; +} + +/** + * Fetch the next calendar month from a specified month/year + * + * @param int The month + * @param int The year + * @return array Array of the next month and next year + */ +function get_next_month($month, $year) +{ + global $monthnames; + + if($month == 12) + { + $nextmonth = 1; + $nextyear = $year+1; + } + else + { + $nextmonth = $month+1; + $nextyear = $year; + } + + return array("month" => $nextmonth, "year" => $nextyear, "name" => $monthnames[$nextmonth]); +} + +/** + * Fetch the previous calendar month from a specified month/year + * + * @param int The month + * @param int The year + * @return array Array of the previous month and previous year + */ +function get_prev_month($month, $year) +{ + global $monthnames; + + if($month == 1) + { + $prevmonth = 12; + $prevyear = $year-1; + } + else + { + $prevmonth = $month-1; + $prevyear = $year; + } + + return array("month" => $prevmonth, "year" => $prevyear, "name" => $monthnames[$prevmonth]); +} + +/** + * Fetch the events for a specific calendar and date range + * + * @param int The calendar ID + * @param int Start time stamp + * @param int End time stmap + * @param int 1 to fetch unapproved events too + * @param int The user ID to fetch private events for (0 fetches none) + * @return array Array of events + */ +function get_events($calendar, $start, $end, $unapproved=0, $private=1) +{ + global $db, $mybb; + + // We take in to account timezones here - we add/subtract 12 hours from our GMT time ranges + $start -= 12*3600; + $end += 12*3600; + + $visible_where = ''; + if($unapproved != 1) + { + $visible_where = " AND e.visible='1'"; + } + + $events_cache = array(); + $query = $db->query(" + SELECT u.*, e.* + FROM ".TABLE_PREFIX."events e + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=e.uid) + WHERE e.cid='{$calendar['cid']}' {$visible_where} AND ((e.endtime>={$start} AND e.starttime<={$end}) OR (e.endtime=0 AND e.starttime>={$start} AND e.starttime<={$end})) AND ((e.uid='{$mybb->user['uid']}' AND private='1') OR private!='1') + ORDER BY endtime DESC + "); + while($event = $db->fetch_array($query)) + { + if($event['ignoretimezone'] == 0) + { + $offset = $event['timezone']; + } + else + { + $offset = $mybb->user['timezone']; + } + $event['starttime_user'] = $event['starttime']+($offset*3600); + + // Single day event + if($event['endtime'] == 0) + { + $event_date = gmdate("j-n-Y", $event['starttime_user']); + $events_cache[$event_date][] = $event; + } + // Ranged event + else + { + $event_date = explode("-", gmdate("j-n-Y", $event['starttime_user'])); + $event['endtime_user'] = $event['endtime']+($offset*3600); + $event['weekday_start'] = $calendar['startofweek']; + + $start_day = gmmktime(0, 0, 0, $event_date[1], $event_date[0], $event_date[2]); + + $event['repeats'] = my_unserialize($event['repeats']); + + // Event does not repeat - just goes over a few days + if($event['repeats']['repeats'] == 0) + { + if($start_day < $start) + { + $range_start = gmmktime(0, 0, 0, gmdate("n", $start), gmdate("j", $start), gmdate("Y", $start)); + } + else + { + $range_start = $start_day; + } + } + else + { + $range_start = fetch_next_occurance($event, array("start" => $start, "end" => $end), $start_day, true); + } + $first = ""; + $event_date = explode("-", gmdate("j-n-Y", $range_start)); + + // Get rid of hour/minutes because sometimes they cause the events to stretch into the next day + $range_end = gmmktime(23, 59, 59, gmdate("n", $event['endtime_user']), gmdate("j", $event['endtime_user']), gmdate("Y", $event['endtime_user'])); + while($range_start < $range_end) + { + // Outside the dates we care about, break! (No unnecessary looping here!) + if($range_start > $end || !$range_start) + { + break; + } + if($range_start >= $start) + { + $day_date = gmdate("j-n-Y", $range_start); + if($first && $day_date != "{$first}") + { + $events_cache[$day_date][] = &$events_cache["{$first}"][$count]; + } + else if(!$first) + { + if(!isset($events_cache[$day_date])) + { + $events_cache[$day_date] = array(); + } + $count = count($events_cache[$day_date]); + $first = $day_date; + $events_cache[$day_date][] = $event; + } + } + if($event['repeats']['repeats'] == 0) + { + $range_start += 86400; + } + else + { + $range_start = fetch_next_occurance($event, array("start" => $start, "end" => $end), $range_start); + } + } + } + } + return $events_cache; +} + +/** + * Fetch the birthdays for one or more months or a specific day + * + * @param mixed Integer of the month or array of months + * @param int Day of the specific month (if only one month specified above) + * @return array Array of birthdays + */ +function get_birthdays($months, $day="") +{ + global $db; + + $year = my_date("Y"); + + if(!is_array($months)) + { + $months = array($months); + } + + foreach($months as $month) + { + if($day) + { + $day_where = "{$day}-{$month}"; + } + else + { + $day_where = "%-{$month}"; + } + if($month == 3 && ($day == 1 || !$day) && my_date("L", gmmktime(0, 0, 0, $month, 1, $year)) != 1) + { + $where[] = "birthday LIKE '29-2%' OR birthday='29-2'"; + $feb_fix = 1; + } + $where[] = "birthday LIKE '{$day_where}-%' OR birthday LIKE '{$day_where}'"; + } + + $where = implode(" OR ", $where); + + $bdays = array(); + + $query = $db->simple_select("users", "uid, username, birthday, birthdayprivacy, usergroup, displaygroup", $where); + while($user = $db->fetch_array($query)) + { + $bday = explode("-", $user['birthday']); + if($bday[2] && $bday[2] < $year) + { + $user['age'] = $year - $bday[2]; + } + if($feb_fix == 1 && $bday[0] == 29 && $bday[1] == 2) + { + $bdays["1-3"][] = $user; + } + else + { + $bdays["$bday[0]-$bday[1]"][] = $user; + } + } + if($day) + { + if(!isset($bdays["$day-$month"])) + { + return array(); + } + return $bdays["$day-$month"]; + } + return $bdays; +} + +/** + * Fetch an ordered list of weekdays depended on a specified starting day + * + * @param int The weekday we want to start the week with + * @return array Ordered list of weekdays dependant on start of week + */ +function fetch_weekday_structure($week_start) +{ + switch($week_start) + { + case "1": + $weekdays = array(1,2,3,4,5,6,0); + break; + case "2": + $weekdays = array(2,3,4,5,6,0,1); + break; + case "3": + $weekdays = array(3,4,5,6,0,1,2); + break; + case "4": + $weekdays = array(4,5,6,0,1,2,3); + break; + case "5": + $weekdays = array(5,6,0,1,2,3,4); + break; + case "6": + $weekdays = array(6,0,1,2,3,4,5); + break; + default: + $weekdays = array(0,1,2,3,4,5,6); + break; + } + return $weekdays; +} + +/** + * Fetch a weekday name based on a number + * + * @param int The weekday number + * @param boolean True to fetch the short name ('S'), false to fetch full name + * @return string The weekday name + */ +function fetch_weekday_name($weekday, $short=false) +{ + global $lang; + switch($weekday) + { + case 1: + $weekday_name = $lang->monday; + $short_weekday_name = $lang->short_monday; + break; + case 2: + $weekday_name = $lang->tuesday; + $short_weekday_name = $lang->short_tuesday; + break; + case 3: + $weekday_name = $lang->wednesday; + $short_weekday_name = $lang->short_wednesday; + break; + case 4: + $weekday_name = $lang->thursday; + $short_weekday_name = $lang->short_thursday; + break; + case 5: + $weekday_name = $lang->friday; + $short_weekday_name = $lang->short_friday; + break; + case 6: + $weekday_name = $lang->saturday; + $short_weekday_name = $lang->short_saturday; + break; + case 0: + $weekday_name = $lang->sunday; + $short_weekday_name = $lang->short_sunday; + break; + } + + if($short == true) + { + return $short_weekday_name; + } + else + { + return $weekday_name; + } +} + +/** + * Fetches the next occurance for a repeating event. + * + * @param array The event array + * @param array The range of start/end timestamps + * @param int The last occurance of this event + * @param boolean True if this is our first iteration of this function (Does some special optimised calculations on false) + * @return int The next occurance timestamp + */ +function fetch_next_occurance($event, $range, $last_occurance, $first=false) +{ + $new_time = $last_occurance; + + $repeats = $event['repeats']; + + $start_day = explode("-", gmdate("j-n-Y", $event['starttime_user'])); + $start_date = gmmktime(0, 0, 0, $start_day[1], $start_day[0], $start_day[2]); + + if($repeats['repeats'] == 0) + { + $new_time += 86400; + } + // Repeats daily + else if($repeats['repeats'] == 1) + { + // If this isn't the first time we've called this function then we can just tack on the time since $last_occurance + if($first == false) + { + $new_time += 86400*$repeats['days']; + } + else + { + // Need to count it out + if($range['start'] > $event['starttime']) + { + $days_since = ceil(($range['start']-$start_date)/86400); + $occurances = floor($days_since/$repeats['days']); + $next_date = $occurances*$repeats['days']; + $new_time = $event['starttime']+(86400*$next_date); + } + else + { + $new_time = $start_date; + } + } + } + // Repeats on weekdays only + else if($repeats['repeats'] == 2) + { + if($first == false) + { + $last_dow = gmdate("w", $last_occurance); + // Last day of week = friday, +3 gives monday + if($last_dow == 5) + { + $new_time += 86400*3; + } + // Still in week, add a day + else + { + $new_time += 86400; + } + } + // First loop with start date + else + { + if($range['start'] < $event['starttime']) + { + $start = $event['starttime']; + } + else + { + $start = $range['start']; + } + $first_dow = gmdate("w", $start); + if($first_dow == 6) + { + $new_time = $start + (86400*2); + } + else if($first_dow == 0) + { + $new_time = $start + 86400; + } + else + { + $new_time = $start; + } + } + } + // Repeats weekly + else if($repeats['repeats'] == 3) + { + $weekdays = fetch_weekday_structure($event['weekday_start']); + $last_dow = gmdate("w", $last_occurance); + if($first == true) + { + $last_dow = -1; + $start_day = gmdate('w', $last_occurance); + if(in_array($start_day, $weekdays)) + { + $next_dow = 0; + } + } + else + { + foreach($repeats['days'] as $weekday) + { + if($weekday > $last_dow) + { + $next_dow = $weekday; + break; + } + } + } + if(!isset($next_dow)) + { + // Fetch first weekday + $first = $repeats['days'][0]*86400; + $new_time += $first; + // Increase x weeks + $new_time += (7-$last_dow)*86400; + $new_time += (($repeats['weeks']-1)*604800); + } + else + { + // Next day of week exists + if($last_dow > 0) + { + $day_diff = $next_dow-$last_dow; + } + else + { + $day_diff = $next_dow; + } + $new_time += $day_diff*86400; + } + } + // Repeats monthly + else if($repeats['repeats'] == 4) + { + $last_month = gmdate("n", $last_occurance); + $last_year = gmdate("Y", $last_occurance); + $last_day = gmdate("j", $last_occurance); + $last_num_days = gmdate("t", $last_occurance); + + // X of every Y months + if($repeats['day']) + { + if($first == true) + { + if($last_day <= $repeats['day']) + { + $new_time = gmmktime(0, 0, 0, $last_month, $repeats['day'], $last_year); + } + else + { + $new_time = gmmktime(0, 0, 0, $last_month+1, $repeats['day'], $last_year); + if($new_time > $event['endtime']) + { + return false; + } + } + } + else + { + $new_time = gmmktime(0, 0, 0, $last_month+$repeats['months'], $repeats['day'], $last_year); + } + } + // The 1st/etc (weekday) of every X months + else + { + if($first == true) + { + $new_time = fetch_weekday_monthly_repetition($repeats, $last_month, $last_year); + if($new_time < $last_occurance) + { + $new_time = fetch_weekday_monthly_repetition($repeats, $last_month+1, $last_year); + } + } + else + { + $new_time = fetch_weekday_monthly_repetition($repeats, $last_month+$repeats['months'], $last_year); + } + } + } + // Repeats yearly + else if($repeats['repeats'] == 5) + { + $last_year = gmdate("Y", $last_occurance); + + // Repeats on (day) of (month) every (years) + if($repeats['day']) + { + if($first == true) + { + $new_time = gmmktime(0, 0, 0, $repeats['month'], $repeats['day'], $last_year); + if($new_time < $last_occurance) + { + $new_time = gmmktime(0, 0, 0, $repeats['month'], $repeats['day'], $last_year+1); + } + } + else + { + $new_time = gmmktime(0, 0, 0, $repeats['month'], $repeats['day'], $last_year+$repeats['years']); + } + } + // The 1st/etc (weekday) of (month) every (years) + else + { + if($first == true) + { + $new_time = fetch_weekday_monthly_repetition($repeats, $repeats['month'], $last_year); + if($new_time < $last_occurance) + { + $new_time = fetch_weekday_monthly_repetition($repeats, $repeats['month'], $last_year+1); + } + } + else + { + $new_time = fetch_weekday_monthly_repetition($repeats, $repeats['month'], $last_year+$repeats['years']); + } + } + } + return $new_time; +} + +/** + * Fetch a friendly repetition value for a specific event (Repeats every x months etc) + * + * @param array The array of the event + * @return string The friendly repetition string + */ +function fetch_friendly_repetition($event) +{ + global $lang; + + $monthnames = array( + "offset", + $lang->month_1, + $lang->month_2, + $lang->month_3, + $lang->month_4, + $lang->month_5, + $lang->month_6, + $lang->month_7, + $lang->month_8, + $lang->month_9, + $lang->month_10, + $lang->month_11, + $lang->month_12 + ); + + if(!is_array($event['repeats'])) + { + $event['repeats'] = my_unserialize($event['repeats']); + if(!is_array($event['repeats'])) + { + return false; + } + } + + $repeats = $event['repeats']; + + switch($repeats) + { + case 1: + if($repeats['days'] <= 1) + { + return $lang->repeats_every_day; + } + return $lang->sprintf($lang->repeats_every_x_days, $event['repeats']['days']); + break; + case 2: + return $lang->repeats_on_weekdays; + break; + case 3: + if($event['repeats']['days'] || count($event['repeats']['days']) == 7) + { + $weekdays = null; + foreach($event['repeats']['days'] as $id => $weekday) + { + $weekday_name = fetch_weekday_name($weekday); + if($event['repeats']['days'][$id+1] && $weekday) + { + $weekdays .= $lang->comma; + } + else if(!$event['repeats']['days'][$id+1] && $weekday) + { + $weekdays .= " {$lang->and} "; + } + $weekdays .= $weekday_name; + } + } + if($event['repeats']['weeks'] == 1) + { + if($weekdays) + { + return $lang->sprintf($lang->every_week_on_days, $weekdays); + } + else + { + return $lang->sprintf($lang->every_week); + } + } + else + { + if($weekdays) + { + return $lang->sprintf($lang->every_x_weeks_on_days, $event['repeats']['weeks'], $weekdays); + } + else + { + return $lang->sprintf($lang->every_x_weeks, $event['repeats']['weeks']); + } + } + break; + case 4: + if($event['repeats']['day']) + { + if($event['repeats']['months'] == 1) + { + return $lang->sprintf($lang->every_month_on_day, $event['repeats']['day']); + } + else + { + return $lang->sprintf($lang->every_x_months_on_day, $event['repeats']['day'], $event['repeats']['months']); + } + } + else + { + $weekday_name = fetch_weekday_name($event['repeats']['weekday']); + $occurance = "weekday_occurance_".$event['repeats']['occurance']; + $occurance = $lang->$occurance; + if($event['repeats']['months'] == 1) + { + return $lang->sprintf($lang->every_month_on_weekday, $occurance, $weekday_name); + } + else + { + return $lang->sprintf($lang->every_x_months_on_weekday, $occurance, $weekday_name, $event['repeats']['months']); + } + } + break; + case 5: + $month = $monthnames[$event['repeats']['month']]; + if($event['repeats']['day']) + { + if($event['repeats']['years'] == 1) + { + return $lang->sprintf($lang->every_year_on_day, $event['repeats']['day'], $month); + } + else + { + return $lang->sprintf($lang->every_x_years_on_day, $event['repeats']['day'], $month, $event['repeats']['years']); + } + } + else + { + $weekday_name = fetch_weekday_name($event['repeats']['weekday']); + $occurance = "weekday_occurance_".$event['repeats']['occurance']; + $occurance = $lang->$occurance; + if($event['repeats']['years'] == 1) + { + return $lang->sprintf($lang->every_year_on_weekday, $occurance, $weekday_name, $month); + } + else + { + return $lang->sprintf($lang->every_x_year_on_weekday, $occurance, $weekday_name, $month, $event['repeats']['years']); + } + } + break; + } +} + +/** + * Fetch a timestamp for "the first/second etc weekday" for a month. + * + * @param array The repetition array from the event + * @param int The month of the year + * @param int The year + * @return int The UNIX timestamp + */ +function fetch_weekday_monthly_repetition($repeats, $month, $year) +{ + $first_last = gmmktime(0, 0, 0, $month, 1, $year); + $first_dow = gmdate("w", $first_last); + $day = 1+($repeats['weekday']-$first_dow); + if($day < 1) + { + $day += 7; + } + if($repeats['occurance'] != "last") + { + $day += ($repeats['occurance']-1)*7; + } + else + { + $last_dow = gmdate("w", gmmktime(0, 0, 0, $month, gmdate("t", $first_last), $year)); + $day = (gmdate("t", $first_last)-$last_dow)+$repeats['weekday']; + if($day > gmdate("t", $first_dow)) + { + $day -= 7; + } + } + return gmmktime(0, 0, 0, $month, $day, $year); +} diff --git a/Upload/inc/functions_forumlist.php b/Upload/inc/functions_forumlist.php new file mode 100644 index 0000000..7d84e14 --- /dev/null +++ b/Upload/inc/functions_forumlist.php @@ -0,0 +1,588 @@ + 0 + ); + $forum_viewers_text = ''; + $forum_viewers_text_plain = ''; + + // Get the permissions for this forum + $permissions = $forumpermissions[$forum['fid']]; + + // If this user doesnt have permission to view this forum and we're hiding private forums, skip this forum + if($permissions['canview'] != 1 && $mybb->settings['hideprivateforums'] == 1) + { + continue; + } + + $forum = $plugins->run_hooks("build_forumbits_forum", $forum); + + // Build the link to this forum + $forum_url = get_forum_link($forum['fid']); + + // This forum has a password, and the user isn't authenticated with it - hide post information + $hideinfo = $hidecounters = false; + $hidelastpostinfo = false; + $showlockicon = 0; + if(isset($permissions['canviewthreads']) && $permissions['canviewthreads'] != 1) + { + $hideinfo = true; + } + + if(isset($permissions['canonlyviewownthreads']) && $permissions['canonlyviewownthreads'] == 1) + { + $hidecounters = true; + + // If we only see our own threads, find out if there's a new post in one of them so the lightbulb shows + if(!is_array($private_forums)) + { + $private_forums = $fids = array(); + foreach($fcache as $fcache_p) + { + foreach($fcache_p as $parent_p) + { + foreach($parent_p as $forum_p) + { + if($forumpermissions[$forum_p['fid']]['canonlyviewownthreads']) + { + $fids[] = $forum_p['fid']; + } + } + } + } + + if(!empty($fids)) + { + $fids = implode(',', $fids); + $query = $db->simple_select("threads", "tid, fid, subject, lastpost, lastposter, lastposteruid", "uid = '{$mybb->user['uid']}' AND fid IN ({$fids}) AND visible != '-2'", array("order_by" => "lastpost", "order_dir" => "desc")); + + while($thread = $db->fetch_array($query)) + { + if(!$private_forums[$thread['fid']]) + { + $private_forums[$thread['fid']] = $thread; + } + } + } + } + + if($private_forums[$forum['fid']]['lastpost']) + { + $forum['lastpost'] = $private_forums[$forum['fid']]['lastpost']; + + $lastpost_data = array( + "lastpost" => $private_forums[$forum['fid']]['lastpost'], + "lastpostsubject" => $private_forums[$forum['fid']]['subject'], + "lastposter" => $private_forums[$forum['fid']]['lastposter'], + "lastposttid" => $private_forums[$forum['fid']]['tid'], + "lastposteruid" => $private_forums[$forum['fid']]['lastposteruid'] + ); + } + } + else + { + $lastpost_data = array( + "lastpost" => $forum['lastpost'], + "lastpostsubject" => $forum['lastpostsubject'], + "lastposter" => $forum['lastposter'], + "lastposttid" => $forum['lastposttid'], + "lastposteruid" => $forum['lastposteruid'] + ); + } + + if($forum['password'] != '' && $mybb->cookies['forumpass'][$forum['fid']] != md5($mybb->user['uid'].$forum['password'])) + { + $hideinfo = true; + $showlockicon = 1; + } + + // Fetch subforums of this forum + if(isset($fcache[$forum['fid']])) + { + $forum_info = build_forumbits($forum['fid'], $depth+1); + + // Increment forum counters with counters from child forums + $forum['threads'] += $forum_info['counters']['threads']; + $forum['posts'] += $forum_info['counters']['posts']; + $forum['unapprovedthreads'] += $forum_info['counters']['unapprovedthreads']; + $forum['unapprovedposts'] += $forum_info['counters']['unapprovedposts']; + + if(!empty($forum_info['counters']['viewing'])) + { + $forum['viewers'] += $forum_info['counters']['viewing']; + } + + // If the child forums' lastpost is greater than the one for this forum, set it as the child forums greatest. + if($forum_info['lastpost']['lastpost'] > $lastpost_data['lastpost']) + { + $lastpost_data = $forum_info['lastpost']; + + /* + // If our subforum is unread, then so must be our parents. Force our parents to unread as well + if(strstr($forum_info['lightbulb']['folder'], "on") !== false) + { + $forum['lastread'] = 0; + } + // Otherwise, if we have an explicit record in the db, we must make sure that it is explicitly set + else + { + $lastpost_data['lastpost'] = $forum['lastpost']; + }*/ + } + + $sub_forums = $forum_info['forum_list']; + } + + // If we are hiding information (lastpost) because we aren't authenticated against the password for this forum, remove them + if($hidelastpostinfo == true) + { + $lastpost_data = array( + 'lastpost' => 0, + 'lastposter' => '' + ); + } + + // If the current forums lastpost is greater than other child forums of the current parent, overwrite it + if(!isset($parent_lastpost) || $lastpost_data['lastpost'] > $parent_lastpost['lastpost']) + { + $parent_lastpost = $lastpost_data; + } + + if(is_array($forum_viewers) && isset($forum_viewers[$forum['fid']]) && $forum_viewers[$forum['fid']] > 0) + { + $forum['viewers'] = $forum_viewers[$forum['fid']]; + } + + // Increment the counters for the parent forum (returned later) + if($hideinfo != true && $hidecounters != true) + { + $parent_counters['threads'] += $forum['threads']; + $parent_counters['posts'] += $forum['posts']; + $parent_counters['unapprovedposts'] += $forum['unapprovedposts']; + $parent_counters['unapprovedthreads'] += $forum['unapprovedthreads']; + + if(!empty($forum['viewers'])) + { + $parent_counters['viewers'] += $forum['viewers']; + } + } + + // Done with our math, lets talk about displaying - only display forums which are under a certain depth + if($depth > $showdepth) + { + continue; + } + + // Get the lightbulb status indicator for this forum based on the lastpost + $lightbulb = get_forum_lightbulb($forum, $lastpost_data, $showlockicon); + + // Fetch the number of unapproved threads and posts for this forum + $unapproved = get_forum_unapproved($forum); + + if($hideinfo == true) + { + unset($unapproved); + } + + // Sanitize name and description of forum. + $forum['name'] = preg_replace("#&(?!\#[0-9]+;)#si", "&", $forum['name']); // Fix & but allow unicode + $forum['description'] = preg_replace("#&(?!\#[0-9]+;)#si", "&", $forum['description']); // Fix & but allow unicode + $forum['name'] = preg_replace("#&([^\#])(?![a-z1-4]{1,10};)#i", "&$1", $forum['name']); + $forum['description'] = preg_replace("#&([^\#])(?![a-z1-4]{1,10};)#i", "&$1", $forum['description']); + + // If this is a forum and we've got subforums of it, load the subforums list template + if($depth == 2 && $sub_forums) + { + eval("\$subforums = \"".$templates->get("forumbit_subforums")."\";"); + } + // A depth of three indicates a comma separated list of forums within a forum + else if($depth == 3) + { + if($donecount < $mybb->settings['subforumsindex']) + { + $statusicon = ''; + + // Showing mini status icons for this forum + if($mybb->settings['subforumsstatusicons'] == 1) + { + $lightbulb['folder'] = "mini".$lightbulb['folder']; + eval("\$statusicon = \"".$templates->get("forumbit_depth3_statusicon", 1, 0)."\";"); + } + + // Fetch the template and append it to the list + eval("\$forum_list .= \"".$templates->get("forumbit_depth3", 1, 0)."\";"); + $comma = $lang->comma; + } + + // Have we reached our max visible subforums? put a nice message and break out of the loop + ++$donecount; + if($donecount == $mybb->settings['subforumsindex']) + { + if(subforums_count($fcache[$pid]) > $donecount) + { + $forum_list .= $comma.$lang->sprintf($lang->more_subforums, (subforums_count($fcache[$pid]) - $donecount)); + } + } + continue; + } + + // Forum is a category, set template type + if($forum['type'] == 'c') + { + $forumcat = '_cat'; + } + // Forum is a standard forum, set template type + else + { + $forumcat = '_forum'; + } + + if($forum['linkto'] == '') + { + // No posts have been made in this forum - show never text + if(($lastpost_data['lastpost'] == 0 || $lastpost_data['lastposter'] == '') && $hideinfo != true) + { + eval("\$lastpost = \"".$templates->get("forumbit_depth2_forum_lastpost_never")."\";"); + } + elseif($hideinfo != true) + { + // Format lastpost date and time + $lastpost_date = my_date('relative', $lastpost_data['lastpost']); + + // Set up the last poster, last post thread id, last post subject and format appropriately + $lastpost_profilelink = build_profile_link($lastpost_data['lastposter'], $lastpost_data['lastposteruid']); + $lastpost_link = get_thread_link($lastpost_data['lastposttid'], 0, "lastpost"); + $lastpost_subject = $full_lastpost_subject = $parser->parse_badwords($lastpost_data['lastpostsubject']); + if(my_strlen($lastpost_subject) > 25) + { + $lastpost_subject = my_substr($lastpost_subject, 0, 25)."..."; + } + $lastpost_subject = htmlspecialchars_uni($lastpost_subject); + $full_lastpost_subject = htmlspecialchars_uni($full_lastpost_subject); + + // Call lastpost template + if($depth != 1) + { + eval("\$lastpost = \"".$templates->get("forumbit_depth{$depth}_forum_lastpost")."\";"); + } + } + + if($mybb->settings['showforumviewing'] != 0 && $forum['viewers'] > 0) + { + if($forum['viewers'] == 1) + { + $forum_viewers_text = $lang->viewing_one; + } + else + { + $forum_viewers_text = $lang->sprintf($lang->viewing_multiple, $forum['viewers']); + } + $forum_viewers_text_plain = $forum_viewers_text; + eval("\$forum_viewers_text = \"".$templates->get("forumbit_depth2_forum_viewers")."\";"); + } + } + // If this forum is a link or is password protected and the user isn't authenticated, set counters to "-" + if($forum['linkto'] != '' || $hideinfo == true || $hidecounters == true) + { + $posts = "-"; + $threads = "-"; + } + // Otherwise, format thread and post counts + else + { + $posts = my_number_format($forum['posts']); + $threads = my_number_format($forum['threads']); + } + + // If this forum is a link or is password protected and the user isn't authenticated, set lastpost to "-" + if($forum['linkto'] != '' || $hideinfo == true || $hidelastpostinfo == true) + { + eval("\$lastpost = \"".$templates->get("forumbit_depth2_forum_lastpost_hidden")."\";"); + } + + // Moderator column is not off + if($mybb->settings['modlist'] != 0) + { + $done_moderators = array( + "users" => array(), + "groups" => array() + ); + $moderators = ''; + // Fetch list of moderators from this forum and its parents + $parentlistexploded = explode(',', $forum['parentlist']); + foreach($parentlistexploded as $mfid) + { + // This forum has moderators + if(isset($moderatorcache[$mfid]) && is_array($moderatorcache[$mfid])) + { + // Fetch each moderator from the cache and format it, appending it to the list + foreach($moderatorcache[$mfid] as $modtype) + { + foreach($modtype as $moderator) + { + if($moderator['isgroup']) + { + if(in_array($moderator['id'], $done_moderators['groups'])) + { + continue; + } + + $moderator['title'] = htmlspecialchars_uni($moderator['title']); + + eval("\$moderators .= \"".$templates->get("forumbit_moderators_group", 1, 0)."\";"); + $done_moderators['groups'][] = $moderator['id']; + } + else + { + if(in_array($moderator['id'], $done_moderators['users'])) + { + continue; + } + + $moderator['profilelink'] = get_profile_link($moderator['id']); + $moderator['username'] = htmlspecialchars_uni($moderator['username']); + + eval("\$moderators .= \"".$templates->get("forumbit_moderators_user", 1, 0)."\";"); + $done_moderators['users'][] = $moderator['id']; + } + $comma = $lang->comma; + } + } + } + } + $comma = ''; + + // If we have a moderators list, load the template + if($moderators) + { + eval("\$modlist = \"".$templates->get("forumbit_moderators")."\";"); + } + else + { + $modlist = ''; + } + } + + // Descriptions aren't being shown - blank them + if($mybb->settings['showdescriptions'] == 0) + { + $forum['description'] = ''; + } + + // Check if this category is either expanded or collapsed and hide it as necessary. + $expdisplay = ''; + $collapsed_name = "cat_{$forum['fid']}_c"; + if(isset($collapsed[$collapsed_name]) && $collapsed[$collapsed_name] == "display: show;") + { + $expcolimage = "collapse_collapsed.png"; + $expdisplay = "display: none;"; + $expthead = " thead_collapsed"; + $expaltext = "[+]"; + } + else + { + $expcolimage = "collapse.png"; + $expthead = ""; + $expaltext = "[-]"; + } + + // Swap over the alternate backgrounds + $bgcolor = alt_trow(); + + // Add the forum to the list + eval("\$forum_list .= \"".$templates->get("forumbit_depth$depth$forumcat")."\";"); + } + } + + if(!isset($parent_lastpost)) + { + $parent_lastpost = 0; + } + + if(!isset($lightbulb)) + { + $lightbulb = ''; + } + + // Return an array of information to the parent forum including child forums list, counters and lastpost information + return array( + "forum_list" => $forum_list, + "counters" => $parent_counters, + "lastpost" => $parent_lastpost, + "lightbulb" => $lightbulb, + ); +} + +/** + * Fetch the status indicator for a forum based on its last post and the read date + * + * @param array Array of information about the forum + * @param array Array of information about the lastpost date + * @param int Whether or not this forum is locked or not + * @return array Array of the folder image to be shown and the alt text + */ +function get_forum_lightbulb($forum, $lastpost, $locked=0) +{ + global $mybb, $lang, $db, $unread_forums; + + // This forum is a redirect, so override the folder icon with the "offlink" icon. + if($forum['linkto'] != '') + { + $folder = "offlink"; + $altonoff = $lang->forum_redirect; + } + // This forum is closed, so override the folder icon with the "offlock" icon. + elseif($forum['open'] == 0 || $locked) + { + $folder = "offlock"; + $altonoff = $lang->forum_locked; + } + else + { + // Fetch the last read date for this forum + if(!empty($forum['lastread'])) + { + $forum_read = $forum['lastread']; + } + elseif(!empty($mybb->cookies['mybb']['readallforums'])) + { + // We've hit the read all forums as a guest, so use the lastvisit of the user + $forum_read = $mybb->cookies['mybb']['lastvisit']; + } + else + { + $forum_read = 0; + $threadcut = TIME_NOW - 60*60*24*$mybb->settings['threadreadcut']; + + // If the user is a guest, do they have a forumsread cookie? + if(!$mybb->user['uid'] && isset($mybb->cookies['mybb']['forumread'])) + { + // If they've visited us before, then they'll have this cookie - otherwise everything is unread... + $forum_read = my_get_array_cookie("forumread", $forum['fid']); + } + else if($mybb->user['uid'] && $mybb->settings['threadreadcut'] > 0 && $threadcut > $lastpost['lastpost']) + { + // We have a user, the forum's unread and we're over our threadreadcut limit for the lastpost - we mark these as read + $forum_read = $lastpost['lastpost'] + 1; + } + } + + //if(!$forum_read) + //{ + //$forum_read = $mybb->user['lastvisit']; + //} + + // If the lastpost is greater than the last visit and is greater than the forum read date, we have a new post + if($lastpost['lastpost'] > $forum_read && $lastpost['lastpost'] != 0) + { + $unread_forums++; + $folder = "on"; + $altonoff = $lang->new_posts; + } + // Otherwise, no new posts + else + { + $folder = "off"; + $altonoff = $lang->no_new_posts; + } + } + + return array( + "folder" => $folder, + "altonoff" => $altonoff + ); +} + +/** + * Fetch the number of unapproved posts, formatted, from a forum + * + * @param array Array of information about the forum + * @return array Array containing formatted string for posts and string for threads + */ +function get_forum_unapproved($forum) +{ + global $lang, $templates; + + $unapproved_threads = $unapproved_posts = ''; + + // If the user is a moderator we need to fetch the count + if(is_moderator($forum['fid'], "canviewunapprove")) + { + // Forum has one or more unaproved posts, format language string accordingly + if($forum['unapprovedposts']) + { + if($forum['unapprovedposts'] > 1) + { + $unapproved_posts_count = $lang->sprintf($lang->forum_unapproved_posts_count, $forum['unapprovedposts']); + } + else + { + $unapproved_posts_count = $lang->sprintf($lang->forum_unapproved_post_count, 1); + } + + $forum['unapprovedposts'] = my_number_format($forum['unapprovedposts']); + eval("\$unapproved_posts = \"".$templates->get("forumbit_depth2_forum_unapproved_posts")."\";"); + } + // Forum has one or more unapproved threads, format language string accordingly + if($forum['unapprovedthreads']) + { + if($forum['unapprovedthreads'] > 1) + { + $unapproved_threads_count = $lang->sprintf($lang->forum_unapproved_threads_count, $forum['unapprovedthreads']); + } + else + { + $unapproved_threads_count = $lang->sprintf($lang->forum_unapproved_thread_count, 1); + } + + $forum['unapprovedthreads'] = my_number_format($forum['unapprovedthreads']); + eval("\$unapproved_threads = \"".$templates->get("forumbit_depth2_forum_unapproved_threads")."\";"); + } + } + return array( + "unapproved_posts" => $unapproved_posts, + "unapproved_threads" => $unapproved_threads + ); +} diff --git a/Upload/inc/functions_image.php b/Upload/inc/functions_image.php new file mode 100644 index 0000000..e5f1d06 --- /dev/null +++ b/Upload/inc/functions_image.php @@ -0,0 +1,257 @@ += $maxwidth) || ($imgheight >= $maxheight)) + { + check_thumbnail_memory($imgwidth, $imgheight, $imgtype, $imgbits, $imgchan); + + if($imgtype == 3) + { + if(@function_exists("imagecreatefrompng")) + { + $im = @imagecreatefrompng($file); + } + } + elseif($imgtype == 2) + { + if(@function_exists("imagecreatefromjpeg")) + { + $im = @imagecreatefromjpeg($file); + } + } + elseif($imgtype == 1) + { + if(@function_exists("imagecreatefromgif")) + { + $im = @imagecreatefromgif($file); + } + } + else + { + $thumb['code'] = 3; + return $thumb; + } + if(!$im) + { + $thumb['code'] = 3; + return $thumb; + } + $scale = scale_image($imgwidth, $imgheight, $maxwidth, $maxheight); + $thumbwidth = $scale['width']; + $thumbheight = $scale['height']; + $thumbim = @imagecreatetruecolor($thumbwidth, $thumbheight); + + if(!$thumbim) + { + $thumbim = @imagecreate($thumbwidth, $thumbheight); + $resized = true; + } + + // Attempt to preserve the transparency if there is any + if($imgtype == 3) + { + // A PNG! + imagealphablending($thumbim, false); + imagefill($thumbim, 0, 0, imagecolorallocatealpha($thumbim, 0, 0, 0, 127)); + + // Save Alpha... + imagesavealpha($thumbim, true); + } + elseif($imgtype == 1) + { + // Transparent GIF? + $trans_color = imagecolortransparent($im); + if($trans_color >= 0 && $trans_color < imagecolorstotal($im)) + { + $trans = imagecolorsforindex($im, $trans_color); + $new_trans_color = imagecolorallocate($thumbim, $trans['red'], $trans['blue'], $trans['green']); + imagefill($thumbim, 0, 0, $new_trans_color); + imagecolortransparent($thumbim, $new_trans_color); + } + } + + if(!isset($resized)) + { + @imagecopyresampled($thumbim, $im, 0, 0, 0, 0, $thumbwidth, $thumbheight, $imgwidth, $imgheight); + } + else + { + @imagecopyresized($thumbim, $im, 0, 0, 0, 0, $thumbwidth, $thumbheight, $imgwidth, $imgheight); + } + @imagedestroy($im); + if(!function_exists("imagegif") && $imgtype == 1) + { + $filename = str_replace(".gif", ".jpg", $filename); + } + switch($imgtype) + { + case 1: + if(function_exists("imagegif")) + { + @imagegif($thumbim, $path."/".$filename); + } + else + { + @imagejpeg($thumbim, $path."/".$filename); + } + break; + case 2: + @imagejpeg($thumbim, $path."/".$filename); + break; + case 3: + @imagepng($thumbim, $path."/".$filename); + break; + } + @my_chmod($path."/".$filename, '0644'); + @imagedestroy($thumbim); + $thumb['code'] = 1; + $thumb['filename'] = $filename; + return $thumb; + } + else + { + return array("code" => 4); + } +} + +/** + * Attempts to allocate enough memory to generate the thumbnail + * + * @param integer hight dimension + * @param integer width dimension + * @param string one of the IMAGETYPE_XXX constants indicating the type of the image + * @param string the bits area the number of bits for each color + * @param string the channels - 3 for RGB pictures and 4 for CMYK pictures + */ +function check_thumbnail_memory($width, $height, $type, $bitdepth, $channels) +{ + if(!function_exists("memory_get_usage")) + { + return false; + } + + $memory_limit = @ini_get("memory_limit"); + if(!$memory_limit || $memory_limit == -1) + { + return false; + } + + $limit = preg_match("#^([0-9]+)\s?([kmg])b?$#i", trim(my_strtolower($memory_limit)), $matches); + $memory_limit = 0; + if($matches[1] && $matches[2]) + { + switch($matches[2]) + { + case "k": + $memory_limit = $matches[1] * 1024; + break; + case "m": + $memory_limit = $matches[1] * 1048576; + break; + case "g": + $memory_limit = $matches[1] * 1073741824; + } + } + $current_usage = memory_get_usage(); + $free_memory = $memory_limit - $current_usage; + + $thumbnail_memory = round(($width * $height * $bitdepth * $channels / 8) * 5); + $thumbnail_memory += 2097152; + + if($thumbnail_memory > $free_memory) + { + if($matches[1] && $matches[2]) + { + switch($matches[2]) + { + case "k": + $memory_limit = ceil((($memory_limit+$thumbnail_memory) / 1024))."K"; + break; + case "m": + $memory_limit = ceil((($memory_limit+$thumbnail_memory) / 1048576))."M"; + break; + case "g": + $memory_limit = ceil((($memory_limit+$thumbnail_memory) / 1073741824))."G"; + } + } + + @ini_set("memory_limit", $memory_limit); + } +} + +/** + * Figures out the correct dimensions to use + * + * @param integer current hight dimension + * @param integer current width dimension + * @param integer max hight dimension + * @param integer max width dimension + * @return array correct height & width + */ +function scale_image($width, $height, $maxwidth, $maxheight) +{ + $width = (int)$width; + $height = (int)$height; + + if(!$width) $width = $maxwidth; + if(!$height) $height = $maxheight; + + $newwidth = $width; + $newheight = $height; + + if($width > $maxwidth) + { + $newwidth = $maxwidth; + $newheight = ceil(($height*(($maxwidth*100)/$width))/100); + $height = $newheight; + $width = $newwidth; + } + if($height > $maxheight) + { + $newheight = $maxheight; + $newwidth = ceil(($width*(($maxheight*100)/$height))/100); + } + $ret['width'] = $newwidth; + $ret['height'] = $newheight; + return $ret; +} diff --git a/Upload/inc/functions_indicators.php b/Upload/inc/functions_indicators.php new file mode 100644 index 0000000..35e680e --- /dev/null +++ b/Upload/inc/functions_indicators.php @@ -0,0 +1,326 @@ +settings['threadreadcut'] > 0 && $mybb->user['uid']) + { + // For registered users, store the information in the database. + switch($db->type) + { + case "pgsql": + case "sqlite": + $db->replace_query("threadsread", array('tid' => $tid, 'uid' => $mybb->user['uid'], 'dateline' => TIME_NOW), array("tid", "uid")); + break; + default: + $db->write_query(" + REPLACE INTO ".TABLE_PREFIX."threadsread (tid, uid, dateline) + VALUES('$tid', '{$mybb->user['uid']}', '".TIME_NOW."') + "); + } + } + // Default back to cookie marking + else + { + my_set_array_cookie("threadread", $tid, TIME_NOW, -1); + } + + $unread_count = fetch_unread_count($fid); + if($unread_count == 0) + { + mark_forum_read($fid); + } +} + +/** + * Fetches the number of unread threads for the current user in a particular forum. + * + * @param string The forums (CSV list) + * @return int The number of unread threads + */ +function fetch_unread_count($fid) +{ + global $cache, $db, $mybb; + + $onlyview = $onlyview2 = ''; + $permissions = forum_permissions($fid); + $cutoff = TIME_NOW-$mybb->settings['threadreadcut']*60*60*24; + + if(!empty($permissions['canonlyviewownthreads'])) + { + $onlyview = " AND uid = '{$mybb->user['uid']}'"; + $onlyview2 = " AND t.uid = '{$mybb->user['uid']}'"; + } + + if($mybb->user['uid'] == 0) + { + $comma = ''; + $tids = ''; + $threadsread = $forumsread = array(); + + if(isset($mybb->cookies['mybb']['threadread'])) + { + $threadsread = my_unserialize($mybb->cookies['mybb']['threadread']); + } + if(isset($mybb->cookies['mybb']['forumread'])) + { + $forumsread = my_unserialize($mybb->cookies['mybb']['forumread']); + } + + if(!empty($threadsread)) + { + foreach($threadsread as $key => $value) + { + $tids .= $comma.(int)$key; + $comma = ','; + } + } + + if(!empty($tids)) + { + $count = 0; + + // We've read at least some threads, are they here? + $query = $db->simple_select("threads", "lastpost, tid, fid", "visible=1 AND closed NOT LIKE 'moved|%' AND fid IN ({$fid}) AND lastpost > '{$cutoff}'{$onlyview}", array("limit" => 100)); + + while($thread = $db->fetch_array($query)) + { + if(isset($threadsread[$thread['tid']]) && $thread['lastpost'] > (int)$threadsread[$thread['tid']] && isset($forumsread[$thread['fid']]) && $thread['lastpost'] > (int)$forumsread[$thread['fid']]) + { + ++$count; + } + } + + return $count; + } + + // Not read any threads? + return false; + } + else + { + switch($db->type) + { + case "pgsql": + $query = $db->query(" + SELECT COUNT(t.tid) AS unread_count + FROM ".TABLE_PREFIX."threads t + LEFT JOIN ".TABLE_PREFIX."threadsread tr ON (tr.tid=t.tid AND tr.uid='{$mybb->user['uid']}') + LEFT JOIN ".TABLE_PREFIX."forumsread fr ON (fr.fid=t.fid AND fr.uid='{$mybb->user['uid']}') + WHERE t.visible=1 AND t.closed NOT LIKE 'moved|%' AND t.fid IN ($fid) AND t.lastpost > COALESCE(tr.dateline,$cutoff) AND t.lastpost > COALESCE(fr.dateline,$cutoff) AND t.lastpost>$cutoff{$onlyview2} + "); + break; + default: + $query = $db->query(" + SELECT COUNT(t.tid) AS unread_count + FROM ".TABLE_PREFIX."threads t + LEFT JOIN ".TABLE_PREFIX."threadsread tr ON (tr.tid=t.tid AND tr.uid='{$mybb->user['uid']}') + LEFT JOIN ".TABLE_PREFIX."forumsread fr ON (fr.fid=t.fid AND fr.uid='{$mybb->user['uid']}') + WHERE t.visible=1 AND t.closed NOT LIKE 'moved|%' AND t.fid IN ($fid) AND t.lastpost > IFNULL(tr.dateline,$cutoff) AND t.lastpost > IFNULL(fr.dateline,$cutoff) AND t.lastpost>$cutoff{$onlyview2} + "); + } + return $db->fetch_field($query, "unread_count"); + } +} + +/** + * Mark a particular forum as read. + * + * @param int The forum ID + */ +function mark_forum_read($fid) +{ + global $mybb, $db; + + // Can only do "true" tracking for registered users + if($mybb->settings['threadreadcut'] > 0 && $mybb->user['uid']) + { + // Experimental setting to mark parent forums as read + $forums_to_read = array(); + + if($mybb->settings['readparentforums']) + { + $ignored_forums = array(); + $forums = array_reverse(explode(",", get_parent_list($fid))); + + unset($forums[0]); + if(!empty($forums)) + { + $ignored_forums[] = $fid; + + foreach($forums as $forum) + { + $fids = array($forum); + $ignored_forums[] = $forum; + + $children = explode(",", get_parent_list($forum)); + foreach($children as $child) + { + if(in_array($child, $ignored_forums)) + { + continue; + } + + $fids[] = $child; + $ignored_forums[] = $child; + } + + if(fetch_unread_count(implode(",", $fids)) == 0) + { + $forums_to_read[] = $forum; + } + } + } + } + + switch($db->type) + { + case "pgsql": + case "sqlite": + add_shutdown(array($db, "replace_query"), array("forumsread", array('fid' => $fid, 'uid' => $mybb->user['uid'], 'dateline' => TIME_NOW), array("fid", "uid"))); + + if(!empty($forums_to_read)) + { + foreach($forums_to_read as $forum) + { + add_shutdown(array($db, "replace_query"), array("forumsread", array('fid' => $forum, 'uid' => $mybb->user['uid'], 'dateline' => TIME_NOW), array('fid', 'uid'))); + } + } + break; + default: + $child_sql = ''; + if(!empty($forums_to_read)) + { + foreach($forums_to_read as $forum) + { + $child_sql .= ", ('{$forum}', '{$mybb->user['uid']}', '".TIME_NOW."')"; + } + } + + $db->shutdown_query(" + REPLACE INTO ".TABLE_PREFIX."forumsread (fid, uid, dateline) + VALUES('{$fid}', '{$mybb->user['uid']}', '".TIME_NOW."'){$child_sql} + "); + } + } + // Mark in a cookie + else + { + my_set_array_cookie("forumread", $fid, TIME_NOW, -1); + } +} + +/** + * Marks all forums as read. + * + */ +function mark_all_forums_read() +{ + global $mybb, $db, $cache; + + // Can only do "true" tracking for registered users + if($mybb->user['uid'] > 0) + { + $db->update_query("users", array('lastvisit' => TIME_NOW), "uid='".$mybb->user['uid']."'"); + require_once MYBB_ROOT."inc/functions_user.php"; + update_pm_count('', 2); + + if($mybb->settings['threadreadcut'] > 0) + { + // Need to loop through all forums and mark them as read + $forums = $cache->read('forums'); + + $update_count = ceil(count($forums)/20); + + if($update_count < 15) + { + $update_count = 15; + } + + $mark_query = ''; + $done = 0; + foreach(array_keys($forums) as $fid) + { + switch($db->type) + { + case "pgsql": + case "sqlite": + $mark_query[] = array('fid' => $fid, 'uid' => $mybb->user['uid'], 'dateline' => TIME_NOW); + break; + default: + if($mark_query != '') + { + $mark_query .= ','; + } + $mark_query .= "('{$fid}', '{$mybb->user['uid']}', '".TIME_NOW."')"; + } + ++$done; + + // Only do this in loops of $update_count, save query time + if($done % $update_count) + { + switch($db->type) + { + case "pgsql": + case "sqlite": + foreach($mark_query as $replace_query) + { + add_shutdown(array($db, "replace_query"), array("forumsread", $replace_query, array("fid", "uid"))); + } + $mark_query = array(); + break; + default: + $db->shutdown_query(" + REPLACE INTO ".TABLE_PREFIX."forumsread (fid, uid, dateline) + VALUES {$mark_query} + "); + $mark_query = ''; + } + } + } + + if($mark_query != '') + { + switch($db->type) + { + case "pgsql": + case "sqlite": + foreach($mark_query as $replace_query) + { + add_shutdown(array($db, "replace_query"), array("forumsread", $replace_query, array("fid", "uid"))); + } + break; + default: + $db->shutdown_query(" + REPLACE INTO ".TABLE_PREFIX."forumsread (fid, uid, dateline) + VALUES {$mark_query} + "); + } + } + } + } + else + { + my_setcookie("mybb[readallforums]", 1); + my_setcookie("mybb[lastvisit]", TIME_NOW); + + my_unsetcookie("mybb[threadread]"); + my_unsetcookie("mybb[forumread]"); + } +} diff --git a/Upload/inc/functions_massmail.php b/Upload/inc/functions_massmail.php new file mode 100644 index 0000000..b264d00 --- /dev/null +++ b/Upload/inc/functions_massmail.php @@ -0,0 +1,221 @@ +escape_string_like($conditions[$search_field])."%'"; + } + } + + // LESS THAN or GREATER THAN + $direction_fields = array("postnum"); + foreach($direction_fields as $search_field) + { + $direction_field = $search_field."_dir"; + if(!empty($conditions[$search_field]) && $conditions[$direction_field]) + { + switch($conditions[$direction_field]) + { + case "greater_than": + $direction = ">"; + break; + case "less_than": + $direction = "<"; + break; + default: + $direction = "="; + } + $search_sql .= " AND u.{$search_field}{$direction}'".(int)$conditions[$search_field]."'"; + } + } + + // Time-based search fields + $time_fields = array("regdate", "lastactive"); + foreach($time_fields as $search_field) + { + $time_field = $search_field."_date"; + $direction_field = $search_field."_dir"; + if(!empty($conditions[$search_field]) && $conditions[$time_field] && $conditions[$direction_field]) + { + switch($conditions[$time_field]) + { + case "hours": + $date = $conditions[$search_field]*60*60; + break; + case "days": + $date = $conditions[$search_field]*60*60*24; + break; + case "weeks": + $date = $conditions[$search_field]*60*60*24*7; + break; + case "months": + $date = $conditions[$search_field]*60*60*24*30; + break; + case "years": + $date = $conditions[$search_field]*60*60*24*365; + break; + default: + $date = $conditions[$search_field]*60*60*24; + } + + switch($conditions[$direction_field]) + { + case "less_than": + $direction = ">"; + break; + case "more_than": + $direction = "<"; + break; + default: + $direction = "<"; + } + $search_sql .= " AND u.{$search_field}{$direction}'".(TIME_NOW-$date)."'"; + } + } + + // Usergroup based searching + if($conditions['usergroup']) + { + if(!is_array($conditions['usergroup'])) + { + $conditions['usergroup'] = array($conditions['usergroup']); + } + + $conditions['usergroup'] = array_map('intval', $conditions['usergroup']); + + foreach($conditions['usergroup'] as $usergroup) + { + switch($db->type) + { + case "pgsql": + case "sqlite": + $additional_sql .= " OR ','||additionalgroups||',' LIKE '%,{$usergroup},%'"; + break; + default: + $additional_sql .= " OR CONCAT(',',additionalgroups,',') LIKE '%,{$usergroup},%'"; + } + } + $search_sql .= " AND (u.usergroup IN (".implode(",", $conditions['usergroup']).") {$additional_sql})"; + } + + return $search_sql; +} + +/** + * Create a text based version of a HTML mass email. + * + * @param string The HTML version. + * @return string The generated text based version. + */ +function create_text_message($message) +{ + // Cut out all current line breaks + // Makes links CONTENT (link) + $message = make_pretty_links($message); + $message = str_replace(array("\r\n", "\n"), "\n", $message); + $message = preg_replace("#

    #i", "\n\n", $message); + $message = preg_replace("##i", "\n", $message); + $message = preg_replace("#]*?>#i", "", $message); + $message = preg_replace("#]*?>\s*#i", "-----------\n", $message); + $message = html_entity_decode($message); + $message = str_replace("\t", "", $message); + do + { + $message = str_replace(" ", " ", $message); + } + while(strpos($message, " ") !== false); + + $search = array('@]*?>.*?@si', // Strip out javascript + '@]*?>.*?@siU', // Strip style tags properly + '@]*?>.*?@siU', // Strip title tags + '@<[\/\!]*?[^<>]*?>@si', // Strip out HTML tags + '@@' // Strip multi-line comments including CDATA + ); + $message = preg_replace($search, '', $message); + $message = preg_replace("#\n\n+#", "\n\n", $message); + $message = preg_replace("#^\s+#is", "", $message); + return $message; +} + +/** + * Generates friendly links for a text based version of a mass email from the HTML version. + * + * @param string The HTML version. + * @return string The version with the friendly links and all tags stripped. + */ +function make_pretty_links($message_html) +{ + do + { + $start = stripos($message_html, "", $start); + if($end === false) + { + break; + } + + $a_href = substr($message_html, $start, ($end-$start)); + + preg_match("#href=\"?([^\"> ]+)\"?#i", $a_href, $href_matches); + if(!$href_matches[1]) + { + continue; + } + $link = $href_matches[1]; + + $contents = strip_tags($a_href); + if(!$contents) + { + preg_match("#alt=\"?([^\">]+)\"?#i", $a_href, $matches2); + if($matches2[1]) + { + $contents = $matches2[1]; + } + if(!$contents) + { + preg_match("#title=\"?([^\">]+)\"?#i", $a_href, $matches2); + if($matches2[1]) + { + $contents = $matches2[1]; + } + } + } + + $replaced_link = $contents." ({$link}) "; + + $message_html = substr_replace($message_html, $replaced_link, $start, ($end-$start)); + } while(true); + return $message_html; +} diff --git a/Upload/inc/functions_modcp.php b/Upload/inc/functions_modcp.php new file mode 100644 index 0000000..bdf9fb1 --- /dev/null +++ b/Upload/inc/functions_modcp.php @@ -0,0 +1,284 @@ +usergroup['issupermod'] == 0 && ($user_permissions['issupermod'] == 1 || $user_permissions['cancp'] == 1)) + { + return false; + } + // Current user is a super mod or is an administrator + else if($user_permissions['cancp'] == 1 && ($mybb->usergroup['cancp'] != 1 || (is_super_admin($uid) && !is_super_admin($mybb->user['uid'])))) + { + return false; + } + return true; +} + +/** + * Fetch forums the moderator can manage announcements to + * + * @param int (Optional) The parent forum ID + * @param int (Optional) The depth from parent forum the moderator can manage to + */ +function fetch_forum_announcements($pid=0, $depth=1) +{ + global $mybb, $db, $lang, $theme, $announcements, $templates, $announcements_forum, $moderated_forums, $unviewableforums; + static $forums_by_parent, $forum_cache, $parent_forums; + + if(!is_array($forum_cache)) + { + $forum_cache = cache_forums(); + } + if(!is_array($parent_forums) && $mybb->usergroup['issupermod'] != 1) + { + // Get a list of parentforums to show for normal moderators + $parent_forums = array(); + foreach($moderated_forums as $mfid) + { + $parent_forums = array_merge($parent_forums, explode(',', $forum_cache[$mfid]['parentlist'])); + } + } + if(!is_array($forums_by_parent)) + { + foreach($forum_cache as $forum) + { + $forums_by_parent[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum; + } + } + + if(!is_array($forums_by_parent[$pid])) + { + return; + } + + foreach($forums_by_parent[$pid] as $children) + { + foreach($children as $forum) + { + if($forum['linkto'] || (is_array($unviewableforums) && in_array($forum['fid'], $unviewableforums))) + { + continue; + } + + if($forum['active'] == 0 || !is_moderator($forum['fid'], "canmanageannouncements")) + { + // Check if this forum is a parent of a moderated forum + if(is_array($parent_forums) && in_array($forum['fid'], $parent_forums)) + { + // A child is moderated, so print out this forum's title. RECURSE! + $trow = alt_trow(); + eval("\$announcements_forum .= \"".$templates->get("modcp_announcements_forum_nomod")."\";"); + } + else + { + // No subforum is moderated by this mod, so safely continue + continue; + } + } + else + { + // This forum is moderated by the user, so print out the forum's title, and its announcements + $trow = alt_trow(); + + $padding = 40*($depth-1); + + eval("\$announcements_forum .= \"".$templates->get("modcp_announcements_forum")."\";"); + + if(isset($announcements[$forum['fid']])) + { + foreach($announcements[$forum['fid']] as $aid => $announcement) + { + $trow = alt_trow(); + + if($announcement['enddate'] < TIME_NOW && $announcement['enddate'] != 0) + { + eval("\$icon = \"".$templates->get("modcp_announcements_announcement_expired")."\";"); + } + else + { + eval("\$icon = \"".$templates->get("modcp_announcements_announcement_active")."\";"); + } + + $subject = htmlspecialchars_uni($announcement['subject']); + + eval("\$announcements_forum .= \"".$templates->get("modcp_announcements_announcement")."\";"); + } + } + } + + // Build the list for any sub forums of this forum + if(isset($forums_by_parent[$forum['fid']])) + { + fetch_forum_announcements($forum['fid'], $depth+1); + } + } + } +} + +/** + * Send reported content to moderators + * + * @param array Array of reported content + * @return bool True if PM sent + */ +function send_report($report) +{ + global $db, $lang, $forum, $mybb, $post, $thread; + + $query = $db->query(" + SELECT DISTINCT u.username, u.email, u.receivepms, u.uid + FROM ".TABLE_PREFIX."moderators m + LEFT JOIN ".TABLE_PREFIX."users u ON (u.uid=m.id) + WHERE m.fid IN (".$forum['parentlist'].") AND m.isgroup = '0' + "); + + $nummods = $db->num_rows($query); + + if(!$nummods) + { + unset($query); + switch($db->type) + { + case "pgsql": + case "sqlite": + $query = $db->query(" + SELECT u.username, u.email, u.receivepms, u.uid + FROM ".TABLE_PREFIX."users u + LEFT JOIN ".TABLE_PREFIX."usergroups g ON (((','|| u.additionalgroups|| ',' LIKE '%,'|| g.gid|| ',%') OR u.usergroup = g.gid)) + WHERE (g.cancp=1 OR g.issupermod=1) + "); + break; + default: + $query = $db->query(" + SELECT u.username, u.email, u.receivepms, u.uid + FROM ".TABLE_PREFIX."users u + LEFT JOIN ".TABLE_PREFIX."usergroups g ON (((CONCAT(',', u.additionalgroups, ',') LIKE CONCAT('%,', g.gid, ',%')) OR u.usergroup = g.gid)) + WHERE (g.cancp=1 OR g.issupermod=1) + "); + } + } + + while($mod = $db->fetch_array($query)) + { + $emailsubject = $lang->sprintf($lang->emailsubject_reportpost, $mybb->settings['bbname']); + $emailmessage = $lang->sprintf($lang->email_reportpost, $mybb->user['username'], $mybb->settings['bbname'], $post['subject'], $mybb->settings['bburl'], str_replace('&', '&', get_post_link($post['pid'], $thread['tid'])."#pid".$post['pid']), $thread['subject'], $report['reason']); + + if($mybb->settings['reportmethod'] == "pms" && $mod['receivepms'] != 0 && $mybb->settings['enablepms'] != 0) + { + $pm_recipients[] = $mod['uid']; + } + else + { + my_mail($mod['email'], $emailsubject, $emailmessage); + } + } + + if(count($pm_recipients) > 0) + { + $emailsubject = $lang->sprintf($lang->emailsubject_reportpost, $mybb->settings['bbname']); + $emailmessage = $lang->sprintf($lang->email_reportpost, $mybb->user['username'], $mybb->settings['bbname'], $post['subject'], $mybb->settings['bburl'], str_replace('&', '&', get_post_link($post['pid'], $thread['tid'])."#pid".$post['pid']), $thread['subject'], $report['reason']); + + require_once MYBB_ROOT."inc/datahandlers/pm.php"; + $pmhandler = new PMDataHandler(); + + $pm = array( + "subject" => $emailsubject, + "message" => $emailmessage, + "icon" => 0, + "fromid" => $mybb->user['uid'], + "toid" => $pm_recipients, + "ipaddress" => $session->packedip + ); + + $pmhandler->admin_override = true; + $pmhandler->set_data($pm); + + // Now let the pm handler do all the hard work. + if(!$pmhandler->validate_pm()) + { + // Force it to valid to just get it out of here + $pmhandler->is_validated = true; + $pmhandler->errors = array(); + } + + $pminfo = $pmhandler->insert_pm(); + return $pminfo; + } + + return false; +} + +/** + * Add a report + * + * @param array Array of reported content + * @param string Type of content being reported + * @return int Report ID + */ +function add_report($report, $type = 'post') +{ + global $cache, $db, $mybb; + + $insert_array = array( + 'id' => (int)$report['id'], + 'id2' => (int)$report['id2'], + 'id3' => (int)$report['id3'], + 'uid' => (int)$report['uid'], + 'reportstatus' => 0, + 'reason' => $db->escape_string($report['reason']), + 'type' => $db->escape_string($type), + 'reports' => 1, + 'dateline' => TIME_NOW, + 'lastreport' => TIME_NOW, + 'reporters' => $db->escape_string(serialize(array($report['uid']))) + ); + + if($mybb->settings['reportmethod'] == "email" || $mybb->settings['reportmethod'] == "pms") + { + return send_report($report); + } + + $rid = $db->insert_query("reportedcontent", $insert_array); + $cache->update_reportedcontent(); + + return $rid; +} + +/** + * Update an existing report + * + * @param array Array of reported content + * @return bool + */ +function update_report($report) +{ + global $db; + + $update_array = array( + 'reports' => ++$report['reports'], + 'lastreport' => TIME_NOW, + 'reporters' => $db->escape_string(serialize($report['reporters'])) + ); + + $db->update_query("reportedcontent", $update_array, "rid = '{$report['rid']}'"); + return true; +} diff --git a/Upload/inc/functions_online.php b/Upload/inc/functions_online.php new file mode 100644 index 0000000..09a8909 --- /dev/null +++ b/Upload/inc/functions_online.php @@ -0,0 +1,1186 @@ + 0) + { + $ann_list[$parameters['aid']] = $parameters['aid']; + } + $user_activity['activity'] = "announcements"; + $user_activity['ann'] = $parameters['aid']; + break; + case "attachment": + if(!isset($parameters['aid'])) + { + $parameters['aid'] = 0; + } + $parameters['aid'] = (int)$parameters['aid']; + if($parameters['aid'] > 0) + { + $aid_list[] = $parameters['aid']; + } + $user_activity['activity'] = "attachment"; + $user_activity['aid'] = $parameters['aid']; + break; + case "calendar": + if(!isset($parameters['action'])) + { + $parameters['action'] = ''; + } + if($parameters['action'] == "event") + { + if(!isset($parameters['eid'])) + { + $parameters['eid'] = 0; + } + $parameters['eid'] = (int)$parameters['eid']; + if($parameters['eid'] > 0) + { + $eid_list[$parameters['eid']] = $parameters['eid']; + } + $user_activity['activity'] = "calendar_event"; + $user_activity['eid'] = $parameters['eid']; + } + elseif($parameters['action'] == "addevent" || $parameters['action'] == "do_addevent") + { + $user_activity['activity'] = "calendar_addevent"; + } + elseif($parameters['action'] == "editevent" || $parameters['action'] == "do_editevent") + { + $user_activity['activity'] = "calendar_editevent"; + } + else + { + $user_activity['activity'] = "calendar"; + } + break; + case "contact": + $user_activity['activity'] = "contact"; + break; + case "editpost": + $user_activity['activity'] = "editpost"; + break; + case "forumdisplay": + if(!isset($parameters['fid'])) + { + $parameters['fid'] = 0; + } + $parameters['fid'] = (int)$parameters['fid']; + if($parameters['fid'] > 0) + { + $fid_list[$parameters['fid']] = $parameters['fid']; + } + $user_activity['activity'] = "forumdisplay"; + $user_activity['fid'] = $parameters['fid']; + break; + case "index": + case '': + $user_activity['activity'] = "index"; + break; + case "managegroup": + $user_activity['activity'] = "managegroup"; + break; + case "member": + if(!isset($parameters['action'])) + { + $parameters['action'] = ''; + } + if($parameters['action'] == "activate") + { + $user_activity['activity'] = "member_activate"; + } + elseif($parameters['action'] == "register" || $parameters['action'] == "do_register") + { + $user_activity['activity'] = "member_register"; + } + elseif($parameters['action'] == "login" || $parameters['action'] == "do_login") + { + $user_activity['activity'] = "member_login"; + } + elseif($parameters['action'] == "logout") + { + $user_activity['activity'] = "member_logout"; + } + elseif($parameters['action'] == "profile") + { + $user_activity['activity'] = "member_profile"; + if(!isset($parameters['uid'])) + { + $parameters['uid'] = 0; + } + $parameters['uid'] = (int)$parameters['uid']; + if($parameters['uid'] > 0) + { + $uid_list[$parameters['uid']] = $parameters['uid']; + } + $user_activity['uid'] = $parameters['uid']; + } + elseif($parameters['action'] == "emailuser" || $parameters['action'] == "do_emailuser") + { + $user_activity['activity'] = "member_emailuser"; + } + elseif($parameters['action'] == "rate" || $parameters['action'] == "do_rate") + { + $user_activity['activity'] = "member_rate"; + } + elseif($parameters['action'] == "resendactivation" || $parameters['action'] == "do_resendactivation") + { + $user_activity['activity'] = "member_resendactivation"; + } + elseif($parameters['action'] == "lostpw" || $parameters['action'] == "do_lostpw" || $parameters['action'] == "resetpassword") + { + $user_activity['activity'] = "member_lostpw"; + } + else + { + $user_activity['activity'] = "member"; + } + break; + case "memberlist": + $user_activity['activity'] = "memberlist"; + break; + case "misc": + if(!isset($parameters['action'])) + { + $parameters['action'] = ''; + } + $accepted_parameters = array("markread", "help", "buddypopup", "smilies", "syndication", "imcenter", "dstswitch"); + if($parameters['action'] == "whoposted") + { + if(!isset($parameters['tid'])) + { + $parameters['tid'] = 0; + } + $parameters['tid'] = (int)$parameters['tid']; + if($parameters['tid'] > 0) + { + $tid_list[$parameters['tid']] = $parameters['tid']; + } + $user_activity['activity'] = "misc_whoposted"; + $user_activity['tid'] = $parameters['tid']; + } + elseif(in_array($parameters['action'], $accepted_parameters)) + { + $user_activity['activity'] = "misc_".$parameters['action']; + } + else + { + $user_activity['activity'] = "misc"; + } + break; + case "modcp": + if(!isset($parameters['action'])) + { + $parameters['action'] = 0; + } + + $accepted_parameters = array("modlogs", "announcements", "finduser", "warninglogs", "ipsearch"); + + foreach($accepted_parameters as $action) + { + if($parameters['action'] == $action) + { + $user_activity['activity'] = "modcp_".$action; + break; + } + } + + $accepted_parameters = array(); + $accepted_parameters['report'] = array("do_reports", "reports", "allreports"); + $accepted_parameters['new_announcement'] = array("do_new_announcement", "new_announcement"); + $accepted_parameters['delete_announcement'] = array("do_delete_announcement", "delete_announcement"); + $accepted_parameters['edit_announcement'] = array("do_edit_announcement", "edit_announcement"); + $accepted_parameters['mod_queue'] = array("do_modqueue", "modqueue"); + $accepted_parameters['editprofile'] = array("do_editprofile", "editprofile"); + $accepted_parameters['banning'] = array("do_banuser", "banning", "liftban", "banuser"); + + foreach($accepted_parameters as $name => $actions) + { + if(in_array($parameters['action'], $actions)) + { + $user_activity['activity'] = "modcp_".$name; + break; + } + } + + if(empty($user_activity['activity'])) + { + $user_activity['activity'] = "modcp"; + } + break; + case "moderation": + $user_activity['activity'] = "moderation"; + break; + case "newreply": + if(!isset($parameters['tid'])) + { + $parameters['tid'] = 0; + } + $parameters['tid'] = (int)$parameters['tid']; + if($parameters['tid'] > 0) + { + $tid_list[$parameters['tid']] = $parameters['tid']; + } + $user_activity['activity'] = "newreply"; + $user_activity['tid'] = $parameters['tid']; + break; + case "newthread": + if(!isset($parameters['fid'])) + { + $parameters['fid'] = 0; + } + $parameters['fid'] = (int)$parameters['fid']; + if($parameters['fid'] > 0) + { + $fid_list[$parameters['fid']] = $parameters['fid']; + } + $user_activity['activity'] = "newthread"; + $user_activity['fid'] = $parameters['fid']; + break; + case "online": + if(!isset($parameters['action'])) + { + $parameters['action'] = ''; + } + if($parameters['action'] == "today") + { + $user_activity['activity'] = "woltoday"; + } + else + { + $user_activity['activity'] = "wol"; + } + break; + case "polls": + if(!isset($parameters['action'])) + { + $parameters['action'] = ''; + } + // Make the "do" parts the same as the other one. + if($parameters['action'] == "do_newpoll") + { + $user_activity['activity'] = "newpoll"; + } + elseif($parameters['action'] == "do_editpoll") + { + $user_activity['activity'] = "editpoll"; + } + else + { + $accepted_parameters = array("do_editpoll", "editpoll", "newpoll", "do_newpoll", "showresults", "vote"); + + foreach($accepted_parameters as $action) + { + if($parameters['action'] == $action) + { + $user_activity['activity'] = $action; + break; + } + } + + if(!$user_activity['activity']) + { + $user_activity['activity'] = "showresults"; + } + } + break; + case "printthread": + if(!isset($parameters['tid'])) + { + $parameters['tid'] = 0; + } + $parameters['tid'] = (int)$parameters['tid']; + if($parameters['tid'] > 0) + { + $tid_list[$parameters['tid']] = $parameters['tid']; + } + $user_activity['activity'] = "printthread"; + $user_activity['tid'] = $parameters['tid']; + break; + case "private": + if(!isset($parameters['action'])) + { + $parameters['action'] = ''; + } + if($parameters['action'] == "send" || $parameters['action'] == "do_send") + { + $user_activity['activity'] = "private_send"; + } + elseif($parameters['action'] == "read") + { + $user_activity['activity'] = "private_read"; + } + elseif($parameters['action'] == "folders" || $parameters['action'] == "do_folders") + { + $user_activity['activity'] = "private_folders"; + } + else + { + $user_activity['activity'] = "private"; + } + break; + case "ratethread": + $user_activity['activity'] = "ratethread"; + break; + case "report": + $user_activity['activity'] = "report"; + break; + case "reputation": + if(!isset($parameters['uid'])) + { + $parameters['uid'] = 0; + } + $parameters['uid'] = (int)$parameters['uid']; + if($parameters['uid'] > 0) + { + $uid_list[$parameters['uid']] = $parameters['uid']; + } + $user_activity['uid'] = $parameters['uid']; + + if($parameters['action'] == "add") + { + $user_activity['activity'] = "reputation"; + } + else + { + $user_activity['activity'] = "reputation_report"; + } + break; + case "search": + $user_activity['activity'] = "search"; + break; + case "sendthread": + if(!isset($parameters['tid'])) + { + $parameters['tid'] = 0; + } + $parameters['tid'] = (int)$parameters['tid']; + if($parameters['tid'] > 0) + { + $tid_list[$parameters['tid']] = $parameters['tid']; + } + $user_activity['activity'] = "sendthread"; + $user_activity['tid'] = $parameters['tid']; + break; + case "showteam": + $user_activity['activity'] = "showteam"; + break; + case "showthread": + if(!isset($parameters['action'])) + { + $parameters['action'] = 0; + } + if(!isset($parameters['pid'])) + { + $parameters['pid'] = 0; + } + $parameters['pid'] = (int)$parameters['pid']; + if($parameters['pid'] > 0 && $parameters['action'] == "showpost") + { + $pid_list[$parameters['pid']] = $parameters['pid']; + $user_activity['activity'] = "showpost"; + $user_activity['pid'] = $parameters['pid']; + } + else + { + if(!isset($parameters['page'])) + { + $parameters['page'] = 0; + } + $parameters['page'] = (int)$parameters['page']; + $user_activity['page'] = $parameters['page']; + if(!isset($parameters['tid'])) + { + $parameters['tid'] = 0; + } + $parameters['tid'] = (int)$parameters['tid']; + if($parameters['tid'] > 0) + { + $tid_list[$parameters['tid']] = $parameters['tid']; + } + $user_activity['activity'] = "showthread"; + $user_activity['tid'] = $parameters['tid']; + } + break; + case "stats": + $user_activity['activity'] = "stats"; + break; + case "usercp": + if(!isset($parameters['action'])) + { + $parameters['action'] = ''; + } + if($parameters['action'] == "profile" || $parameters['action'] == "do_profile") + { + $user_activity['activity'] = "usercp_profile"; + } + elseif($parameters['action'] == "options" || $parameters['action'] == "do_options") + { + $user_activity['activity'] = "usercp_options"; + } + elseif($parameters['action'] == "password" || $parameters['action'] == "do_password") + { + $user_activity['activity'] = "usercp_password"; + } + elseif($parameters['action'] == "editsig" || $parameters['action'] == "do_editsig") + { + $user_activity['activity'] = "usercp_editsig"; + } + elseif($parameters['action'] == "avatar" || $parameters['action'] == "do_avatar") + { + $user_activity['activity'] = "usercp_avatar"; + } + elseif($parameters['action'] == "editlists" || $parameters['action'] == "do_editlists") + { + $user_activity['activity'] = "usercp_editlists"; + } + elseif($parameters['action'] == "favorites") + { + $user_activity['activity'] = "usercp_favorites"; + } + elseif($parameters['action'] == "subscriptions") + { + $user_activity['activity'] = "usercp_subscriptions"; + } + elseif($parameters['action'] == "notepad" || $parameters['action'] == "do_notepad") + { + $user_activity['activity'] = "usercp_notepad"; + } + else + { + $user_activity['activity'] = "usercp"; + } + break; + case "usercp2": + if(!isset($parameters['action'])) + { + $parameters['action'] = ''; + } + if($parameters['action'] == "addfavorite" || $parameters['action'] == "removefavorite" || $parameters['action'] == "removefavorites") + { + $user_activity['activity'] = "usercp2_favorites"; + } + else if($parameters['action'] == "addsubscription" || $parameters['action'] == "do_addsubscription" || $parameters['action'] == "removesubscription" || $parameters['action'] == "removesubscriptions") + { + $user_activity['activity'] = "usercp2_subscriptions"; + } + break; + case "portal": + $user_activity['activity'] = "portal"; + break; + case "warnings": + if(!isset($parameters['action'])) + { + $parameters['action'] = ''; + } + if($parameters['action'] == "warn" || $parameters['action'] == "do_warn") + { + $user_activity['activity'] = "warnings_warn"; + } + elseif($parameters['action'] == "do_revoke") + { + $user_activity['activity'] = "warnings_revoke"; + } + elseif($parameters['action'] == "view") + { + $user_activity['activity'] = "warnings_view"; + } + else + { + $user_activity['activity'] = "warnings"; + } + break; + case "nopermission": + $user_activity['activity'] = "nopermission"; + $user_activity['nopermission'] = 1; + break; + default: + $user_activity['activity'] = "unknown"; + break; + } + + // Expects $location to be passed through already sanitized + $user_activity['location'] = $location; + + $user_activity = $plugins->run_hooks("fetch_wol_activity_end", $user_activity); + + return $user_activity; +} + +/** + * Builds a friendly named Who's Online location from an "activity" and array of user data. Assumes fetch_wol_activity has already been called. + * + * @param array Array containing activity and essential IDs. + * @return string Location name for the activity being performed. + */ +function build_friendly_wol_location($user_activity) +{ + global $db, $lang, $uid_list, $aid_list, $pid_list, $tid_list, $fid_list, $ann_list, $eid_list, $plugins, $parser, $mybb; + global $threads, $forums, $forums_linkto, $forum_cache, $posts, $announcements, $events, $usernames, $attachments; + + // Fetch forum permissions for this user + $unviewableforums = get_unviewable_forums(); + $inactiveforums = get_inactive_forums(); + $fidnot = ''; + if($unviewableforums) + { + $fidnot = " AND fid NOT IN ($unviewableforums)"; + } + if($inactiveforums) + { + $fidnot .= " AND fid NOT IN ($inactiveforums)"; + } + + // Fetch any users + if(!is_array($usernames) && count($uid_list) > 0) + { + $uid_sql = implode(",", $uid_list); + if($uid_sql != $mybb->user['uid']) + { + $query = $db->simple_select("users", "uid,username", "uid IN ($uid_sql)"); + while($user = $db->fetch_array($query)) + { + $usernames[$user['uid']] = $user['username']; + } + } + else + { + $usernames[$mybb->user['uid']] = $mybb->user['username']; + } + } + + // Fetch any attachments + if(!is_array($attachments) && count($aid_list) > 0) + { + $aid_sql = implode(",", $aid_list); + $query = $db->simple_select("attachments", "aid,pid", "aid IN ($aid_sql)"); + while($attachment = $db->fetch_array($query)) + { + $attachments[$attachment['aid']] = $attachment['pid']; + $pid_list[] = $attachment['pid']; + } + } + + // Fetch any announcements + if(!is_array($announcements) && count($ann_list) > 0) + { + $aid_sql = implode(",", $ann_list); + $query = $db->simple_select("announcements", "aid,subject", "aid IN ({$aid_sql}) {$fidnot}"); + while($announcement = $db->fetch_array($query)) + { + $announcement_title = htmlspecialchars_uni($parser->parse_badwords($announcement['subject'])); + $announcements[$announcement['aid']] = $announcement_title; + } + } + + // Fetch any posts + if(!is_array($posts) && count($pid_list) > 0) + { + $pid_sql = implode(",", $pid_list); + $query = $db->simple_select("posts", "pid,tid", "pid IN ({$pid_sql}) {$fidnot}"); + while($post = $db->fetch_array($query)) + { + $posts[$post['pid']] = $post['tid']; + $tid_list[] = $post['tid']; + } + } + + // Fetch any threads + if(!is_array($threads) && count($tid_list) > 0) + { + $perms = array(); + $tid_sql = implode(",", $tid_list); + $query = $db->simple_select('threads', 'uid, fid, tid, subject, visible, prefix', "tid IN({$tid_sql}) {$fidnot}"); + + $threadprefixes = build_prefixes(); + + while($thread = $db->fetch_array($query)) + { + $thread['threadprefix'] = ''; + if($thread['prefix'] && !empty($threadprefixes[$thread['prefix']])) + { + $thread['threadprefix'] = $threadprefixes[$thread['prefix']]['displaystyle']; + } + if(empty($perms[$thread['fid']])) + { + $perms[$thread['fid']] = forum_permissions($thread['fid']); + } + + if(isset($perms[$thread['fid']]['canonlyviewownthreads']) && $perms[$thread['fid']]['canonlyviewownthreads'] == 1 && $thread['uid'] != $mybb->user['uid'] && !is_moderator($thread['fid'])) + { + continue; + } + + if(is_moderator($thread['fid']) || $thread['visible'] == 1) + { + $thread_title = ''; + if($thread['threadprefix']) + { + $thread_title = $thread['threadprefix'].' '; + } + + $thread_title .= htmlspecialchars_uni($parser->parse_badwords($thread['subject'])); + + $threads[$thread['tid']] = $thread_title; + $fid_list[] = $thread['fid']; + } + } + } + + // Fetch any forums + if(!is_array($forums) && count($fid_list) > 0) + { + if($fidnot) + { + $fidnot = explode(',', str_replace('\'', '', (string)$unviewableforums).$inactiveforums); + } + + foreach($forum_cache as $fid => $forum) + { + if(in_array($fid, $fid_list) && (!$fidnot || is_array($fidnot) && !in_array($fid, $fidnot))) + { + $forums[$fid] = $forum['name']; + $forums_linkto[$fid] = $forum['linkto']; + } + } + } + + // And finaly any events + if(!is_array($events) && count($eid_list) > 0) + { + $eid_sql = implode(",", $eid_list); + $query = $db->simple_select("events", "eid,name", "eid IN ($eid_sql)"); + while($event = $db->fetch_array($query)) + { + $events[$event['eid']] = htmlspecialchars_uni($parser->parse_badwords($event['name'])); + } + } + + // Now we've got everything we need we can put a name to the location + switch($user_activity['activity']) + { + // announcement.php functions + case "announcements": + if(!empty($announcements[$user_activity['ann']])) + { + $location_name = $lang->sprintf($lang->viewing_announcements, get_announcement_link($user_activity['ann']), $announcements[$user_activity['ann']]); + } + else + { + $location_name = $lang->viewing_announcements2; + } + break; + // attachment.php actions + case "attachment": + $pid = $attachments[$user_activity['aid']]; + $tid = $posts[$pid]; + if(!empty($threads[$tid])) + { + $location_name = $lang->sprintf($lang->viewing_attachment2, $user_activity['aid'], $threads[$tid], get_thread_link($tid)); + } + else + { + $location_name = $lang->viewing_attachment; + } + break; + // calendar.php functions + case "calendar": + $location_name = $lang->viewing_calendar; + break; + case "calendar_event": + if(!empty($events[$user_activity['eid']])) + { + $location_name = $lang->sprintf($lang->viewing_event2, get_event_link($user_activity['eid']), $events[$user_activity['eid']]); + } + else + { + $location_name = $lang->viewing_event; + } + break; + case "calendar_addevent": + $location_name = $lang->adding_event; + break; + case "calendar_editevent": + $location_name = $lang->editing_event; + break; + case "contact": + $location_name = $lang->viewing_contact_us; + break; + // editpost.php functions + case "editpost": + $location_name = $lang->editing_post; + break; + // forumdisplay.php functions + case "forumdisplay": + if(!empty($forums[$user_activity['fid']])) + { + if($forums_linkto[$user_activity['fid']]) + { + $location_name = $lang->sprintf($lang->forum_redirect_to, get_forum_link($user_activity['fid']), $forums[$user_activity['fid']]); + } + else + { + $location_name = $lang->sprintf($lang->viewing_forum2, get_forum_link($user_activity['fid']), $forums[$user_activity['fid']]); + } + } + else + { + $location_name = $lang->viewing_forum; + } + break; + // index.php functions + case "index": + $location_name = $lang->sprintf($lang->viewing_index, $mybb->settings['bbname']); + break; + // managegroup.php functions + case "managegroup": + $location_name = $lang->managing_group; + break; + // member.php functions + case "member_activate": + $location_name = $lang->activating_account; + break; + case "member_profile": + if(!empty($usernames[$user_activity['uid']])) + { + $location_name = $lang->sprintf($lang->viewing_profile2, get_profile_link($user_activity['uid']), $usernames[$user_activity['uid']]); + } + else + { + $location_name = $lang->viewing_profile; + } + break; + case "member_register": + $location_name = $lang->registering; + break; + case "member": + case "member_login": + // Guest or member? + if($mybb->user['uid'] == 0) + { + $location_name = $lang->logging_in; + } + else + { + $location_name = $lang->logging_in_plain; + } + break; + case "member_logout": + $location_name = $lang->logging_out; + break; + case "member_emailuser": + $location_name = $lang->emailing_user; + break; + case "member_rate": + $location_name = $lang->rating_user; + break; + case "member_resendactivation": + $location_name = $lang->member_resendactivation; + break; + case "member_lostpw": + $location_name = $lang->member_lostpw; + break; + // memberlist.php functions + case "memberlist": + $location_name = $lang->viewing_memberlist; + break; + // misc.php functions + case "misc_dstswitch": + $location_name = $lang->changing_dst; + break; + case "misc_whoposted": + if(!empty($threads[$user_activity['tid']])) + { + $location_name = $lang->sprintf($lang->viewing_whoposted2, get_thread_link($user_activity['tid']), $threads[$user_activity['tid']]); + } + else + { + $location_name = $lang->viewing_whoposted; + } + break; + case "misc_markread": + $location_name = $lang->sprintf($lang->marking_read, $mybb->post_code); + break; + case "misc_help": + $location_name = $lang->viewing_helpdocs; + break; + case "misc_buddypopup": + $location_name = $lang->viewing_buddylist; + break; + case "misc_smilies": + $location_name = $lang->viewing_smilies; + break; + case "misc_syndication": + $location_name = $lang->viewing_syndication; + break; + case "misc_imcenter": + $location_name = $lang->viewing_imcenter; + break; + // modcp.php functions + case "modcp_modlogs": + $location_name = $lang->viewing_modlogs; + break; + case "modcp_announcements": + $location_name = $lang->managing_announcements; + break; + case "modcp_finduser": + $location_name = $lang->search_for_user; + break; + case "modcp_warninglogs": + $location_name = $lang->managing_warninglogs; + break; + case "modcp_ipsearch": + $location_name = $lang->searching_ips; + break; + case "modcp_report": + $location_name = $lang->viewing_reports; + break; + case "modcp_new_announcement": + $location_name = $lang->adding_announcement; + break; + case "modcp_delete_announcement": + $location_name = $lang->deleting_announcement; + break; + case "modcp_edit_announcement": + $location_name = $lang->editing_announcement; + break; + case "modcp_mod_queue": + $location_name = $lang->managing_modqueue; + break; + case "modcp_editprofile": + $location_name = $lang->editing_user_profiles; + break; + case "modcp_banning": + $location_name = $lang->managing_bans; + break; + case "modcp": + $location_name = $lang->viewing_modcp; + break; + // moderation.php functions + case "moderation": + $location_name = $lang->using_modtools; + break; + // newreply.php functions + case "newreply": + if(!empty($threads[$user_activity['tid']])) + { + $location_name = $lang->sprintf($lang->replying_thread2, get_thread_link($user_activity['tid']), $threads[$user_activity['tid']]); + } + else + { + $location_name = $lang->replying_thread; + } + break; + // newthread.php functions + case "newthread": + if(!empty($forums[$user_activity['fid']])) + { + $location_name = $lang->sprintf($lang->posting_thread2, get_forum_link($user_activity['fid']), $forums[$user_activity['fid']]); + } + else + { + $location_name = $lang->posting_thread; + } + break; + // online.php functions + case "wol": + $location_name = $lang->viewing_wol; + break; + case "woltoday": + $location_name = $lang->viewing_woltoday; + break; + // polls.php functions + case "newpoll": + $location_name = $lang->creating_poll; + break; + case "editpoll": + $location_name = $lang->editing_poll; + break; + case "showresults": + $location_name = $lang->viewing_pollresults; + break; + case "vote": + $location_name = $lang->voting_poll; + break; + // printthread.php functions + case "printthread": + if(!empty($threads[$user_activity['tid']])) + { + $location_name = $lang->sprintf($lang->printing_thread2, get_thread_link($user_activity['tid']), $threads[$user_activity['tid']]); + } + else + { + $location_name = $lang->printing_thread; + } + break; + // private.php functions + case "private_send": + $location_name = $lang->sending_pm; + break; + case "private_read": + $location_name = $lang->reading_pm; + break; + case "private_folders": + $location_name = $lang->editing_pmfolders; + break; + case "private": + $location_name = $lang->using_pmsystem; + break; + /* Ratethread functions */ + case "ratethread": + $location_name = $lang->rating_thread; + break; + // report.php functions + case "report": + $location_name = $lang->reporting_post; + break; + // reputation.php functions + case "reputation": + $location_name = $lang->sprintf($lang->giving_reputation, get_profile_link($user_activity['uid']), $usernames[$user_activity['uid']]); + break; + case "reputation_report": + if(!empty($usernames[$user_activity['uid']])) + { + $location_name = $lang->sprintf($lang->viewing_reputation_report, "reputation.php?uid={$user_activity['uid']}", $usernames[$user_activity['uid']]); + } + else + { + $location_name = $lang->sprintf($lang->viewing_reputation_report2); + } + break; + // search.php functions + case "search": + $location_name = $lang->sprintf($lang->searching_forum, $mybb->settings['bbname']); + break; + // showthread.php functions + case "showthread": + if(!empty($threads[$user_activity['tid']])) + { + $pagenote = ''; + $location_name = $lang->sprintf($lang->reading_thread2, get_thread_link($user_activity['tid']), $threads[$user_activity['tid']], $pagenote); + } + else + { + $location_name = $lang->reading_thread; + } + break; + case "showpost": + if(!empty($posts[$user_activity['pid']]) && !empty($threads[$posts[$user_activity['pid']]])) + { + $pagenote = ''; + $location_name = $lang->sprintf($lang->reading_thread2, get_thread_link($posts[$user_activity['pid']]), $threads[$posts[$user_activity['pid']]], $pagenote); + } + else + { + $location_name = $lang->reading_thread; + } + break; + // showteam.php functions + case "showteam": + $location_name = $lang->viewing_team; + break; + // stats.php functions + case "stats": + $location_name = $lang->viewing_stats; + break; + // usercp.php functions + case "usercp_profile": + $location_name = $lang->updating_profile; + break; + case "usercp_editlists": + $location_name = $lang->managing_buddyignorelist; + break; + case "usercp_options": + $location_name = $lang->updating_options; + break; + case "usercp_editsig": + $location_name = $lang->editing_signature; + break; + case "usercp_avatar": + $location_name = $lang->changing_avatar; + break; + case "usercp_subscriptions": + $location_name = $lang->viewing_subscriptions; + break; + case "usercp_favorites": + $location_name = $lang->viewing_favorites; + break; + case "usercp_notepad": + $location_name = $lang->editing_pad; + break; + case "usercp_password": + $location_name = $lang->editing_password; + break; + case "usercp": + $location_name = $lang->user_cp; + break; + case "usercp2_favorites": + $location_name = $lang->managing_favorites; + break; + case "usercp2_subscriptions": + $location_name = $lang->managing_subscriptions; + break; + case "portal": + $location_name = $lang->viewing_portal; + break; + // sendthread.php functions + case "sendthread": + $location_name = $lang->sending_thread; + break; + // warnings.php functions + case "warnings_revoke": + $location_name = $lang->revoking_warning; + break; + case "warnings_warn": + $location_name = $lang->warning_user; + break; + case "warnings_view": + $location_name = $lang->viewing_warning; + break; + case "warnings": + $location_name = $lang->managing_warnings; + break; + } + + $plugin_array = array('user_activity' => &$user_activity, 'location_name' => &$location_name); + $plugins->run_hooks("build_friendly_wol_location_end", $plugin_array); + + if(isset($user_activity['nopermission']) && $user_activity['nopermission'] == 1) + { + $location_name = $lang->viewing_noperms; + } + + if(!$location_name) + { + $location_name = $lang->sprintf($lang->unknown_location, $user_activity['location']); + } + + return $location_name; +} + +/** + * Build a Who's Online row for a specific user + * + * @param array Array of user information including activity information + * @return string Formatted online row + */ +function build_wol_row($user) +{ + global $mybb, $lang, $templates, $theme, $session, $db; + + // We have a registered user + if($user['uid'] > 0) + { + // Only those with "canviewwolinvis" permissions can view invisible users + if($user['invisible'] != 1 || $mybb->usergroup['canviewwolinvis'] == 1 || $user['uid'] == $mybb->user['uid']) + { + // Append an invisible mark if the user is invisible + if($user['invisible'] == 1) + { + $invisible_mark = "*"; + } + else + { + $invisible_mark = ''; + } + + $user['username'] = format_name($user['username'], $user['usergroup'], $user['displaygroup']); + $online_name = build_profile_link($user['username'], $user['uid']).$invisible_mark; + } + } + // We have a bot + elseif(!empty($user['bot'])) + { + $online_name = format_name($user['bot'], $user['usergroup']); + } + // Otherwise we've got a plain old guest + else + { + $online_name = format_name($lang->guest, 1); + } + + $online_time = my_date($mybb->settings['timeformat'], $user['time']); + + // Fetch the location name for this users activity + $location = build_friendly_wol_location($user['activity']); + + // Can view IPs, then fetch the IP template + if($mybb->usergroup['canviewonlineips'] == 1) + { + $user['ip'] = my_inet_ntop($db->unescape_binary($user['ip'])); + + if($mybb->usergroup['canmodcp'] == 1 && $mybb->usergroup['canuseipsearch'] == 1) + { + eval("\$lookup = \"".$templates->get("online_row_ip_lookup")."\";"); + } + + eval("\$user_ip = \"".$templates->get("online_row_ip")."\";"); + } + else + { + $user_ip = $lookup = $user['ip'] = ''; + } + + // And finally if we have permission to view this user, return the completed online row + if($user['invisible'] != 1 || $mybb->usergroup['canviewwolinvis'] == 1 || $user['uid'] == $mybb->user['uid']) + { + eval("\$online_row = \"".$templates->get("online_row")."\";"); + } + return $online_row; +} \ No newline at end of file diff --git a/Upload/inc/functions_post.php b/Upload/inc/functions_post.php new file mode 100644 index 0000000..3d1b506 --- /dev/null +++ b/Upload/inc/functions_post.php @@ -0,0 +1,928 @@ +settings['pmsallowhtml']; + $parser_options['allow_mycode'] = $mybb->settings['pmsallowmycode']; + $parser_options['allow_smilies'] = $mybb->settings['pmsallowsmilies']; + $parser_options['allow_imgcode'] = $mybb->settings['pmsallowimgcode']; + $parser_options['allow_videocode'] = $mybb->settings['pmsallowvideocode']; + $parser_options['me_username'] = $post['username']; + $parser_options['filter_badwords'] = 1; + $id = $pmid; + break; + case 3: // Announcement + global $announcementarray, $message; + $parser_options['allow_html'] = $announcementarray['allowhtml']; + $parser_options['allow_mycode'] = $announcementarray['allowmycode']; + $parser_options['allow_smilies'] = $announcementarray['allowsmilies']; + $parser_options['allow_imgcode'] = 1; + $parser_options['allow_videocode'] = 1; + $parser_options['me_username'] = $post['username']; + $parser_options['filter_badwords'] = 1; + $id = $announcementarray['aid']; + break; + default: // Regular post + global $forum, $thread, $tid; + $oldforum = $forum; + $id = (int)$post['pid']; + $idtype = 'pid'; + $parser_options['allow_html'] = $forum['allowhtml']; + $parser_options['allow_mycode'] = $forum['allowmycode']; + $parser_options['allow_smilies'] = $forum['allowsmilies']; + $parser_options['allow_imgcode'] = $forum['allowimgcode']; + $parser_options['allow_videocode'] = $forum['allowvideocode']; + $parser_options['filter_badwords'] = 1; + + if(!$post['username']) + { + $post['username'] = $lang->guest; + } + + if($post['userusername']) + { + $parser_options['me_username'] = $post['userusername']; + } + else + { + $parser_options['me_username'] = $post['username']; + } + break; + } + + if(!$postcounter) + { // Used to show the # of the post + if($page > 1) + { + if(!$mybb->settings['postsperpage'] || (int)$mybb->settings['postsperpage'] < 1) + { + $mybb->settings['postsperpage'] = 20; + } + + $postcounter = $mybb->settings['postsperpage']*($page-1); + } + else + { + $postcounter = 0; + } + $post_extra_style = "border-top-width: 0;"; + } + elseif($mybb->input['mode'] == "threaded") + { + $post_extra_style = "border-top-width: 0;"; + } + else + { + $post_extra_style = "margin-top: 5px;"; + } + + if(!$altbg) + { // Define the alternate background colour if this is the first post + $altbg = "trow1"; + } + $postcounter++; + + // Format the post date and time using my_date + $post['postdate'] = my_date('relative', $post['dateline']); + + // Dont want any little 'nasties' in the subject + $post['subject'] = $parser->parse_badwords($post['subject']); + + // Pm's have been htmlspecialchars_uni()'ed already. + if($post_type != 2) + { + $post['subject'] = htmlspecialchars_uni($post['subject']); + } + + if(empty($post['subject'])) + { + $post['subject'] = ' '; + } + + $post['author'] = $post['uid']; + $post['subject_title'] = $post['subject']; + + // Get the usergroup + if($post['userusername']) + { + if(!$post['displaygroup']) + { + $post['displaygroup'] = $post['usergroup']; + } + $usergroup = $groupscache[$post['displaygroup']]; + } + else + { + $usergroup = $groupscache[1]; + } + + if(!is_array($titlescache)) + { + $cached_titles = $cache->read("usertitles"); + if(!empty($cached_titles)) + { + foreach($cached_titles as $usertitle) + { + $titlescache[$usertitle['posts']] = $usertitle; + } + } + + if(is_array($titlescache)) + { + krsort($titlescache); + } + unset($usertitle, $cached_titles); + } + + // Work out the usergroup/title stuff + $post['groupimage'] = ''; + if(!empty($usergroup['image'])) + { + $language = $mybb->settings['bblanguage']; + if(!empty($mybb->user['language'])) + { + $language = $mybb->user['language']; + } + + $usergroup['image'] = str_replace("{lang}", $language, $usergroup['image']); + $usergroup['image'] = str_replace("{theme}", $theme['imgdir'], $usergroup['image']); + eval("\$post['groupimage'] = \"".$templates->get("postbit_groupimage")."\";"); + + if($mybb->settings['postlayout'] == "classic") + { + $post['groupimage'] .= "
    "; + } + } + + if($post['userusername']) + { + // This post was made by a registered user + $post['username'] = $post['userusername']; + $post['profilelink_plain'] = get_profile_link($post['uid']); + $post['username_formatted'] = format_name($post['username'], $post['usergroup'], $post['displaygroup']); + $post['profilelink'] = build_profile_link($post['username_formatted'], $post['uid']); + + if(trim($post['usertitle']) != "") + { + $hascustomtitle = 1; + } + + if($usergroup['usertitle'] != "" && !$hascustomtitle) + { + $post['usertitle'] = $usergroup['usertitle']; + } + elseif(is_array($titlescache) && !$usergroup['usertitle']) + { + reset($titlescache); + foreach($titlescache as $key => $titleinfo) + { + if($post['postnum'] >= $key) + { + if(!$hascustomtitle) + { + $post['usertitle'] = $titleinfo['title']; + } + $post['stars'] = $titleinfo['stars']; + $post['starimage'] = $titleinfo['starimage']; + break; + } + } + } + + $post['usertitle'] = htmlspecialchars_uni($post['usertitle']); + + if($usergroup['stars']) + { + $post['stars'] = $usergroup['stars']; + } + + if(empty($post['starimage'])) + { + $post['starimage'] = $usergroup['starimage']; + } + + if($post['starimage'] && $post['stars']) + { + // Only display stars if we have an image to use... + $post['starimage'] = str_replace("{theme}", $theme['imgdir'], $post['starimage']); + + $post['userstars'] = ''; + for($i = 0; $i < $post['stars']; ++$i) + { + eval("\$post['userstars'] .= \"".$templates->get("postbit_userstar", 1, 0)."\";"); + } + + $post['userstars'] .= "
    "; + } + + $postnum = $post['postnum']; + $post['postnum'] = my_number_format($post['postnum']); + $post['threadnum'] = my_number_format($post['threadnum']); + + // Determine the status to show for the user (Online/Offline/Away) + $timecut = TIME_NOW - $mybb->settings['wolcutoff']; + if($post['lastactive'] > $timecut && ($post['invisible'] != 1 || $mybb->usergroup['canviewwolinvis'] == 1) && $post['lastvisit'] != $post['lastactive']) + { + eval("\$post['onlinestatus'] = \"".$templates->get("postbit_online")."\";"); + } + else + { + if($post['away'] == 1 && $mybb->settings['allowaway'] != 0) + { + eval("\$post['onlinestatus'] = \"".$templates->get("postbit_away")."\";"); + } + else + { + eval("\$post['onlinestatus'] = \"".$templates->get("postbit_offline")."\";"); + } + } + + $post['useravatar'] = ''; + if(isset($mybb->user['showavatars']) && $mybb->user['showavatars'] != 0 || $mybb->user['uid'] == 0) + { + $useravatar = format_avatar(htmlspecialchars_uni($post['avatar']), $post['avatardimensions'], $mybb->settings['postmaxavatarsize']); + eval("\$post['useravatar'] = \"".$templates->get("postbit_avatar")."\";"); + } + else + { + $post['useravatar'] = ''; + } + + eval("\$post['button_find'] = \"".$templates->get("postbit_find")."\";"); + + if($mybb->settings['enablepms'] == 1 && $post['receivepms'] != 0 && $mybb->usergroup['cansendpms'] == 1 && my_strpos(",".$post['ignorelist'].",", ",".$mybb->user['uid'].",") === false) + { + eval("\$post['button_pm'] = \"".$templates->get("postbit_pm")."\";"); + } + + $post['button_rep'] = ''; + if($post_type != 3 && $mybb->settings['enablereputation'] == 1 && $mybb->settings['postrep'] == 1 && $mybb->usergroup['cangivereputations'] == 1 && $usergroup['usereputationsystem'] == 1 && ($mybb->settings['posrep'] || $mybb->settings['neurep'] || $mybb->settings['negrep']) && $post['uid'] != $mybb->user['uid']) + { + if(!$post['pid']) + { + $post['pid'] = 0; + } + + eval("\$post['button_rep'] = \"".$templates->get("postbit_rep_button")."\";"); + } + + if($post['website'] != "" && $mybb->settings['hidewebsite'] != -1 && !is_member($mybb->settings['hidewebsite']) && $usergroup['canchangewebsite'] == 1) + { + $post['website'] = htmlspecialchars_uni($post['website']); + eval("\$post['button_www'] = \"".$templates->get("postbit_www")."\";"); + } + else + { + $post['button_www'] = ""; + } + + if($post['hideemail'] != 1 && $mybb->usergroup['cansendemail'] == 1) + { + eval("\$post['button_email'] = \"".$templates->get("postbit_email")."\";"); + } + else + { + $post['button_email'] = ""; + } + + $post['userregdate'] = my_date($mybb->settings['regdateformat'], $post['regdate']); + + // Work out the reputation this user has (only show if not announcement) + if($post_type != 3 && $usergroup['usereputationsystem'] != 0 && $mybb->settings['enablereputation'] == 1) + { + $post['userreputation'] = get_reputation($post['reputation'], $post['uid']); + eval("\$post['replink'] = \"".$templates->get("postbit_reputation")."\";"); + } + + // Showing the warning level? (only show if not announcement) + if($post_type != 3 && $mybb->settings['enablewarningsystem'] != 0 && $usergroup['canreceivewarnings'] != 0 && ($mybb->usergroup['canwarnusers'] != 0 || ($mybb->user['uid'] == $post['uid'] && $mybb->settings['canviewownwarning'] != 0))) + { + $warning_level = round($post['warningpoints']/$mybb->settings['maxwarningpoints']*100); + if($warning_level > 100) + { + $warning_level = 100; + } + $warning_level = get_colored_warning_level($warning_level); + + // If we can warn them, it's not the same person, and we're in a PM or a post. + if($mybb->usergroup['canwarnusers'] != 0 && $post['uid'] != $mybb->user['uid'] && ($post_type == 0 || $post_type == 2)) + { + eval("\$post['button_warn'] = \"".$templates->get("postbit_warn")."\";"); + $warning_link = "warnings.php?uid={$post['uid']}"; + } + else + { + $post['button_warn'] = ''; + $warning_link = "usercp.php"; + } + eval("\$post['warninglevel'] = \"".$templates->get("postbit_warninglevel")."\";"); + } + + if($post_type != 3 && $post_type != 1 && purgespammer_show($post['postnum'], $post['usergroup'], $post['uid'])) + { + eval("\$post['button_purgespammer'] = \"".$templates->get('postbit_purgespammer')."\";"); + } + + // Display profile fields on posts - only if field is filled in + if(is_array($profile_fields)) + { + foreach($profile_fields as $field) + { + $fieldfid = "fid{$field['fid']}"; + if(!empty($post[$fieldfid])) + { + $post['fieldvalue'] = ''; + $post['fieldname'] = htmlspecialchars_uni($field['name']); + + $thing = explode("\n", $field['type'], "2"); + $type = trim($thing[0]); + $useropts = explode("\n", $post[$fieldfid]); + + if(is_array($useropts) && ($type == "multiselect" || $type == "checkbox")) + { + foreach($useropts as $val) + { + if($val != '') + { + eval("\$post['fieldvalue_option'] .= \"".$templates->get("postbit_profilefield_multiselect_value")."\";"); + } + } + if($post['fieldvalue_option'] != '') + { + eval("\$post['fieldvalue'] .= \"".$templates->get("postbit_profilefield_multiselect")."\";"); + } + } + else + { + $field_parser_options = array( + "allow_html" => $field['allowhtml'], + "allow_mycode" => $field['allowmycode'], + "allow_smilies" => $field['allowsmilies'], + "allow_imgcode" => $field['allowimgcode'], + "allow_videocode" => $field['allowvideocode'], + #"nofollow_on" => 1, + "filter_badwords" => 1 + ); + + if($customfield['type'] == "textarea") + { + $field_parser_options['me_username'] = $post['username']; + } + else + { + $field_parser_options['nl2br'] = 0; + } + + if($mybb->user['showimages'] != 1 && $mybb->user['uid'] != 0 || $mybb->settings['guestimages'] != 1 && $mybb->user['uid'] == 0) + { + $field_parser_options['allow_imgcode'] = 0; + } + + $post['fieldvalue'] = $parser->parse_message($post[$fieldfid], $field_parser_options); + } + + eval("\$post['profilefield'] .= \"".$templates->get("postbit_profilefield")."\";"); + } + } + } + + eval("\$post['user_details'] = \"".$templates->get("postbit_author_user")."\";"); + } + else + { // Message was posted by a guest or an unknown user + $post['profilelink'] = format_name($post['username'], 1); + + if($usergroup['usertitle']) + { + $post['usertitle'] = $usergroup['usertitle']; + } + else + { + $post['usertitle'] = $lang->guest; + } + + $post['usertitle'] = htmlspecialchars_uni($post['usertitle']); + + $usergroup['title'] = $lang->na; + + $post['userregdate'] = $lang->na; + $post['postnum'] = $lang->na; + $post['button_profile'] = ''; + $post['button_email'] = ''; + $post['button_www'] = ''; + $post['signature'] = ''; + $post['button_pm'] = ''; + $post['button_find'] = ''; + $post['onlinestatus'] = ''; + $post['replink'] = ''; + eval("\$post['user_details'] = \"".$templates->get("postbit_author_guest")."\";"); + } + + $post['button_edit'] = ''; + $post['button_quickdelete'] = ''; + $post['button_quickrestore'] = ''; + $post['button_quote'] = ''; + $post['button_quickquote'] = ''; + $post['button_report'] = ''; + $post['button_reply_pm'] = ''; + $post['button_replyall_pm'] = ''; + $post['button_forward_pm'] = ''; + $post['button_delete_pm'] = ''; + + // For private messages, fetch the reply/forward/delete icons + if($post_type == 2 && $post['pmid']) + { + global $replyall; + + eval("\$post['button_reply_pm'] = \"".$templates->get("postbit_reply_pm")."\";"); + eval("\$post['button_forward_pm'] = \"".$templates->get("postbit_forward_pm")."\";"); + eval("\$post['button_delete_pm'] = \"".$templates->get("postbit_delete_pm")."\";"); + + if($replyall == true) + { + eval("\$post['button_replyall_pm'] = \"".$templates->get("postbit_replyall_pm")."\";"); + } + } + + $post['editedmsg'] = ''; + if(!$post_type) + { + // Figure out if we need to show an "edited by" message + if($post['edituid'] != 0 && $post['edittime'] != 0 && $post['editusername'] != "" && (($mybb->settings['showeditedby'] != 0 && $usergroup['cancp'] == 0) || ($mybb->settings['showeditedbyadmin'] != 0 && $usergroup['cancp'] == 1))) + { + $post['editdate'] = my_date('relative', $post['edittime']); + $post['editnote'] = $lang->sprintf($lang->postbit_edited, $post['editdate']); + $post['editedprofilelink'] = build_profile_link($post['editusername'], $post['edituid']); + $editreason = ""; + if($post['editreason'] != "") + { + $post['editreason'] = $parser->parse_badwords($post['editreason']); + $post['editreason'] = htmlspecialchars_uni($post['editreason']); + eval("\$editreason = \"".$templates->get("postbit_editedby_editreason")."\";"); + } + eval("\$post['editedmsg'] = \"".$templates->get("postbit_editedby")."\";"); + } + + if((is_moderator($fid, "caneditposts") || ($forumpermissions['caneditposts'] == 1 && $mybb->user['uid'] == $post['uid'] && $thread['closed'] != 1)) && $mybb->user['uid'] != 0) + { + eval("\$post['button_edit'] = \"".$templates->get("postbit_edit")."\";"); + } + + // Quick Delete button + $can_delete_thread = $can_delete_post = 0; + if($mybb->user['uid'] == $post['uid'] && $thread['closed'] == 0) + { + if($forumpermissions['candeletethreads'] == 1 && $postcounter == 1) + { + $can_delete_thread = 1; + } + else if($forumpermissions['candeleteposts'] == 1 && $postcounter != 1) + { + $can_delete_post = 1; + } + } + + $postbit_qdelete = ''; + if($mybb->user['uid'] != 0) + { + if((is_moderator($fid, "candeleteposts") || $can_delete_post == 1) && $postcounter != 1) + { + $postbit_qdelete = $lang->postbit_qdelete_post; + $display = ""; + if($post['visible'] == -1) + { + $display = "none"; + } + eval("\$post['button_quickdelete'] = \"".$templates->get("postbit_quickdelete")."\";"); + + // Restore Post + if(is_moderator($fid, "canrestoreposts")) + { + $display = "none"; + if($post['visible'] == -1) + { + $display = ""; + } + $postbit_qrestore = $lang->postbit_qrestore_post; + eval("\$post['button_quickrestore'] = \"".$templates->get("postbit_quickrestore")."\";"); + } + } + else if((is_moderator($fid, "candeletethreads") || $can_delete_thread == 1) && $postcounter == 1) + { + $postbit_qdelete = $lang->postbit_qdelete_thread; + $display = ""; + if($post['visible'] == -1) + { + $display = "none"; + } + $postbit_qrestore = $lang->postbit_qrestore_thread; + eval("\$post['button_quickdelete'] = \"".$templates->get("postbit_quickdelete")."\";"); + + // Restore Post + if(is_moderator($fid, "canrestoreposts")) + { + $display = "none"; + if($post['visible'] == -1) + { + $display = ""; + } + eval("\$post['button_quickrestore'] = \"".$templates->get("postbit_quickrestore")."\";"); + } + } + } + + // Inline moderation stuff + if($ismod) + { + if(isset($mybb->cookies[$inlinecookie]) && my_strpos($mybb->cookies[$inlinecookie], "|".$post['pid']."|")) + { + $inlinecheck = "checked=\"checked\""; + $inlinecount++; + } + else + { + $inlinecheck = ""; + } + + eval("\$post['inlinecheck'] = \"".$templates->get("postbit_inlinecheck")."\";"); + + if($post['visible'] == 0) + { + $invisiblepost = 1; + } + } + else + { + $post['inlinecheck'] = ""; + } + $post['postlink'] = get_post_link($post['pid'], $post['tid']); + $post_number = my_number_format($postcounter); + eval("\$post['posturl'] = \"".$templates->get("postbit_posturl")."\";"); + global $forum, $thread; + + if($forum['open'] != 0 && ($thread['closed'] != 1 || is_moderator($forum['fid'], "canpostclosedthreads")) && ($thread['uid'] == $mybb->user['uid'] || $forumpermissions['canonlyreplyownthreads'] != 1)) + { + eval("\$post['button_quote'] = \"".$templates->get("postbit_quote")."\";"); + } + + if($forumpermissions['canpostreplys'] != 0 && ($thread['uid'] == $mybb->user['uid'] || $forumpermissions['canonlyreplyownthreads'] != 1) && ($thread['closed'] != 1 || is_moderator($fid, "canpostclosedthreads")) && $mybb->settings['multiquote'] != 0 && $forum['open'] != 0 && !$post_type) + { + eval("\$post['button_multiquote'] = \"".$templates->get("postbit_multiquote")."\";"); + } + + if($mybb->user['uid'] != "0") + { + eval("\$post['button_report'] = \"".$templates->get("postbit_report")."\";"); + } + } + elseif($post_type == 3) // announcement + { + if($mybb->usergroup['canmodcp'] == 1 && $mybb->usergroup['canmanageannounce'] == 1 && is_moderator($fid, "canmanageannouncements")) + { + eval("\$post['button_edit'] = \"".$templates->get("announcement_edit")."\";"); + eval("\$post['button_quickdelete'] = \"".$templates->get("announcement_quickdelete")."\";"); + } + } + + $post['iplogged'] = ''; + $show_ips = $mybb->settings['logip']; + $ipaddress = my_inet_ntop($db->unescape_binary($post['ipaddress'])); + + // Show post IP addresses... PMs now can have IP addresses too as of 1.8! + if($post_type == 2) + { + $show_ips = $mybb->settings['showpmip']; + } + if(!$post_type || $post_type == 2) + { + if($show_ips != "no" && !empty($post['ipaddress'])) + { + if($show_ips == "show") + { + eval("\$post['iplogged'] = \"".$templates->get("postbit_iplogged_show")."\";"); + } + else if($show_ips == "hide" && (is_moderator($fid, "canviewips") || $mybb->usergroup['issupermod'])) + { + $action = 'getip'; + if($post_type == 2) + { + $action = 'getpmip'; + } + eval("\$post['iplogged'] = \"".$templates->get("postbit_iplogged_hiden")."\";"); + } + } + } + + if(isset($post['smilieoff']) && $post['smilieoff'] == 1) + { + $parser_options['allow_smilies'] = 0; + } + + if($mybb->user['showimages'] != 1 && $mybb->user['uid'] != 0 || $mybb->settings['guestimages'] != 1 && $mybb->user['uid'] == 0) + { + $parser_options['allow_imgcode'] = 0; + } + + if($mybb->user['showvideos'] != 1 && $mybb->user['uid'] != 0 || $mybb->settings['guestvideos'] != 1 && $mybb->user['uid'] == 0) + { + $parser_options['allow_videocode'] = 0; + } + + // If we have incoming search terms to highlight - get it done. + if(!empty($mybb->input['highlight'])) + { + $parser_options['highlight'] = $mybb->input['highlight']; + $post['subject'] = $parser->highlight_message($post['subject'], $parser_options['highlight']); + } + + $post['message'] = $parser->parse_message($post['message'], $parser_options); + + $post['attachments'] = ''; + if($mybb->settings['enableattachments'] != 0) + { + get_post_attachments($id, $post); + } + + if(isset($post['includesig']) && $post['includesig'] != 0 && $post['username'] && $post['signature'] != "" && ($mybb->user['uid'] == 0 || $mybb->user['showsigs'] != 0) && ($post['suspendsignature'] == 0 || $post['suspendsignature'] == 1 && $post['suspendsigtime'] != 0 && $post['suspendsigtime'] < TIME_NOW) && $usergroup['canusesig'] == 1 && ($usergroup['canusesigxposts'] == 0 || $usergroup['canusesigxposts'] > 0 && $postnum > $usergroup['canusesigxposts']) && $mybb->settings['hidesignatures'] != -1 && !is_member($mybb->settings['hidesignatures'])) + { + $sig_parser = array( + "allow_html" => $mybb->settings['sightml'], + "allow_mycode" => $mybb->settings['sigmycode'], + "allow_smilies" => $mybb->settings['sigsmilies'], + "allow_imgcode" => $mybb->settings['sigimgcode'], + "me_username" => $post['username'], + "filter_badwords" => 1 + ); + + if($usergroup['signofollow']) + { + $sig_parser['nofollow_on'] = 1; + } + + if($mybb->user['showimages'] != 1 && $mybb->user['uid'] != 0 || $mybb->settings['guestimages'] != 1 && $mybb->user['uid'] == 0) + { + $sig_parser['allow_imgcode'] = 0; + } + + $post['signature'] = $parser->parse_message($post['signature'], $sig_parser); + eval("\$post['signature'] = \"".$templates->get("postbit_signature")."\";"); + } + else + { + $post['signature'] = ""; + } + + $icon_cache = $cache->read("posticons"); + + if(isset($post['icon']) && $post['icon'] > 0 && $icon_cache[$post['icon']]) + { + $icon = $icon_cache[$post['icon']]; + + $icon['path'] = htmlspecialchars_uni($icon['path']); + $icon['path'] = str_replace("{theme}", $theme['imgdir'], $icon['path']); + $icon['name'] = htmlspecialchars_uni($icon['name']); + eval("\$post['icon'] = \"".$templates->get("postbit_icon")."\";"); + } + else + { + $post['icon'] = ""; + } + + $post_visibility = $ignore_bit = ''; + switch($post_type) + { + case 1: // Message preview + $post = $plugins->run_hooks("postbit_prev", $post); + break; + case 2: // Private message + $post = $plugins->run_hooks("postbit_pm", $post); + break; + case 3: // Announcement + $post = $plugins->run_hooks("postbit_announcement", $post); + break; + default: // Regular post + $post = $plugins->run_hooks("postbit", $post); + + // Is this author on the ignore list of the current user? Hide this post + if(is_array($ignored_users) && $post['uid'] != 0 && isset($ignored_users[$post['uid']]) && $ignored_users[$post['uid']] == 1) + { + $ignored_message = $lang->sprintf($lang->postbit_currently_ignoring_user, $post['username']); + eval("\$ignore_bit = \"".$templates->get("postbit_ignored")."\";"); + $post_visibility = "display: none;"; + } + break; + } + + if($mybb->settings['postlayout'] == "classic") + { + eval("\$postbit = \"".$templates->get("postbit_classic")."\";"); + } + else + { + eval("\$postbit = \"".$templates->get("postbit")."\";"); + } + $GLOBALS['post'] = ""; + + return $postbit; +} + +/** + * Fetch the attachments for a specific post and parse inline [attachment=id] code. + * Note: assumes you have $attachcache, an array of attachments set up. + * + * @param int The ID of the item. + * @param array The post or item passed by reference. + */ +function get_post_attachments($id, &$post) +{ + global $attachcache, $mybb, $theme, $templates, $forumpermissions, $lang; + + $validationcount = 0; + $tcount = 0; + $post['attachmentlist'] = $post['thumblist'] = $post['imagelist'] = ''; + if(isset($attachcache[$id]) && is_array($attachcache[$id])) + { // This post has 1 or more attachments + foreach($attachcache[$id] as $aid => $attachment) + { + if($attachment['visible']) + { // There is an attachment thats visible! + $attachment['filename'] = htmlspecialchars_uni($attachment['filename']); + $attachment['filesize'] = get_friendly_size($attachment['filesize']); + $ext = get_extension($attachment['filename']); + if($ext == "jpeg" || $ext == "gif" || $ext == "bmp" || $ext == "png" || $ext == "jpg") + { + $isimage = true; + } + else + { + $isimage = false; + } + $attachment['icon'] = get_attachment_icon($ext); + $attachment['downloads'] = my_number_format($attachment['downloads']); + + if(!$attachment['dateuploaded']) + { + $attachment['dateuploaded'] = $attachment['dateline']; + } + $attachdate = my_date('relative', $attachment['dateuploaded']); + // Support for [attachment=id] code + if(stripos($post['message'], "[attachment=".$attachment['aid']."]") !== false) + { + // Show as thumbnail IF image is big && thumbnail exists && setting=='thumb' + // Show as full size image IF setting=='fullsize' || (image is small && permissions allow) + // Show as download for all other cases + if($attachment['thumbnail'] != "SMALL" && $attachment['thumbnail'] != "" && $mybb->settings['attachthumbnails'] == "yes") + { + eval("\$attbit = \"".$templates->get("postbit_attachments_thumbnails_thumbnail")."\";"); + } + elseif((($attachment['thumbnail'] == "SMALL" && $forumpermissions['candlattachments'] == 1) || $mybb->settings['attachthumbnails'] == "no") && $isimage) + { + eval("\$attbit = \"".$templates->get("postbit_attachments_images_image")."\";"); + } + else + { + eval("\$attbit = \"".$templates->get("postbit_attachments_attachment")."\";"); + } + $post['message'] = preg_replace("#\[attachment=".$attachment['aid']."]#si", $attbit, $post['message']); + } + else + { + // Show as thumbnail IF image is big && thumbnail exists && setting=='thumb' + // Show as full size image IF setting=='fullsize' || (image is small && permissions allow) + // Show as download for all other cases + if($attachment['thumbnail'] != "SMALL" && $attachment['thumbnail'] != "" && $mybb->settings['attachthumbnails'] == "yes") + { + eval("\$post['thumblist'] .= \"".$templates->get("postbit_attachments_thumbnails_thumbnail")."\";"); + if($tcount == 5) + { + $thumblist .= "
    "; + $tcount = 0; + } + ++$tcount; + } + elseif((($attachment['thumbnail'] == "SMALL" && $forumpermissions['candlattachments'] == 1) || $mybb->settings['attachthumbnails'] == "no") && $isimage) + { + eval("\$post['imagelist'] .= \"".$templates->get("postbit_attachments_images_image")."\";"); + } + else + { + eval("\$post['attachmentlist'] .= \"".$templates->get("postbit_attachments_attachment")."\";"); + } + } + } + else + { + $validationcount++; + } + } + if($validationcount > 0 && is_moderator($post['fid'], "canviewunapprove")) + { + if($validationcount == 1) + { + $postbit_unapproved_attachments = $lang->postbit_unapproved_attachment; + } + else + { + $postbit_unapproved_attachments = $lang->sprintf($lang->postbit_unapproved_attachments, $validationcount); + } + eval("\$post['attachmentlist'] .= \"".$templates->get("postbit_attachments_attachment_unapproved")."\";"); + } + if($post['thumblist']) + { + eval("\$post['attachedthumbs'] = \"".$templates->get("postbit_attachments_thumbnails")."\";"); + } + else + { + $post['attachedthumbs'] = ''; + } + if($post['imagelist']) + { + eval("\$post['attachedimages'] = \"".$templates->get("postbit_attachments_images")."\";"); + } + else + { + $post['attachedimages'] = ''; + } + if($post['attachmentlist'] || $post['thumblist'] || $post['imagelist']) + { + eval("\$post['attachments'] = \"".$templates->get("postbit_attachments")."\";"); + } + } +} diff --git a/Upload/inc/functions_posting.php b/Upload/inc/functions_posting.php new file mode 100644 index 0000000..32b36ba --- /dev/null +++ b/Upload/inc/functions_posting.php @@ -0,0 +1,219 @@ +settings['maxquotedepth']; + } + $rmdepth = (int)$rmdepth; + + // find all tokens + // note, at various places, we use the prefix "s" to denote "start" (ie [quote]) and "e" to denote "end" (ie [/quote]) + preg_match_all("#\[quote(=(?:"|\"|')?.*?(?:"|\"|')?)?\]#si", $text, $smatches, PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER); + preg_match_all("#\[/quote\]#i", $text, $ematches, PREG_OFFSET_CAPTURE | PREG_PATTERN_ORDER); + + if(empty($smatches) || empty($ematches)) + { + return $text; + } + + // make things easier by only keeping offsets + $soffsets = $eoffsets = array(); + foreach($smatches[0] as $id => $match) + { + $soffsets[] = $match[1]; + } + // whilst we loop, also remove unnecessary end tokens at the start of string + $first_token = $soffsets[0]; + foreach($ematches[0] as $id => $match) + { + if($match[1] > $first_token) + { + $eoffsets[] = $match[1]; + } + } + unset($smatches, $ematches); + + + // elmininate malformed quotes by parsing like the parser does (preg_replace in a while loop) + // NOTE: this is slightly inaccurate because the parser considers [quote] and [quote=...] to be different things + $good_offsets = array(); + while(!empty($soffsets) && !empty($eoffsets)) // don't rely on this condition - an end offset before the start offset will cause this to loop indefinitely + { + $last_offset = 0; + foreach($soffsets as $sk => &$soffset) + { + if($soffset >= $last_offset) + { + // search for corresponding eoffset + foreach($eoffsets as $ek => &$eoffset) // use foreach instead of for to get around indexing issues with unset + { + if($eoffset > $soffset) + { + // we've found a pair + $good_offsets[$soffset] = 1; + $good_offsets[$eoffset] = -1; + $last_offset = $eoffset; + + unset($soffsets[$sk], $eoffsets[$ek]); + break; + } + } + } + } + + // remove any end offsets occurring before start offsets + $first_start = reset($soffsets); + foreach($eoffsets as $ek => &$eoffset) + { + if($eoffset < $first_start) + { + unset($eoffsets[$ek]); + } + else + { + break; + } + } + // we don't need to remove start offsets after the last end offset, because the loop will deplete something before that + } + + if(empty($good_offsets)) + { + return $text; + } + ksort($good_offsets); + + + // we now have a list of all the ordered tokens, ready to go through + $depth = 0; + $remove_regions = array(); + $tmp_start = 0; + foreach($good_offsets as $offset => $dincr) + { + if($depth == $rmdepth && $dincr == 1) + { + $tmp_start = $offset; + } + $depth += $dincr; + if($depth == $rmdepth && $dincr == -1) + { + $remove_regions[] = array($tmp_start, $offset); + } + } + + if(empty($remove_regions)) + { + return $text; + } + + // finally, remove the quotes from the string + $newtext = ''; + $cpy_start = 0; + foreach($remove_regions as &$region) + { + $newtext .= substr($text, $cpy_start, $region[0]-$cpy_start); + $cpy_start = $region[1]+8; // 8 = strlen('[/quote]') + // clean up newlines + $next_char = $text{$region[1]+8}; + if($next_char == "\r" || $next_char == "\n") + { + ++$cpy_start; + if($next_char == "\r" && $text{$region[1]+9} == "\n") + { + ++$cpy_start; + } + } + } + // append remaining end text + if(strlen($text) != $cpy_start) + { + $newtext .= substr($text, $cpy_start); + } + + // we're done + return $newtext; +} + +/** + * Performs cleanup of a quoted message, such as replacing /me commands, before presenting quoted post to the user. + * + * @param array quoted post info, taken from the DB (requires the 'message', 'username', 'pid' and 'dateline' entries to be set; will use 'userusername' if present. requires 'quote_is_pm' if quote message is from a private message) + * @param boolean whether to call remove_message_quotes() on the quoted message + * @return string the cleaned up message, wrapped in a quote tag + */ + +function parse_quoted_message(&$quoted_post, $remove_message_quotes=true) +{ + global $parser, $lang, $plugins; + if(!isset($parser)) + { + require_once MYBB_ROOT."inc/class_parser.php"; + $parser = new postParser; + } + + // Swap username over if we have a registered user + if($quoted_post['userusername']) + { + $quoted_post['username'] = $quoted_post['userusername']; + } + // Clean up the message + $quoted_post['message'] = preg_replace(array( + '#(^|\r|\n)/me ([^\r\n<]*)#i', + '#(^|\r|\n)/slap ([^\r\n<]*)#i', + '#\[attachment=([0-9]+?)\]#i' + ), array( + "\\1* {$quoted_post['username']} \\2", + "\\1* {$quoted_post['username']} {$lang->slaps} \\2 {$lang->with_trout}", + "", + ), $quoted_post['message']); + $quoted_post['message'] = $parser->parse_badwords($quoted_post['message']); + + if($remove_message_quotes) + { + global $mybb; + $max_quote_depth = (int)$mybb->settings['maxquotedepth']; + if($max_quote_depth) + { + $quoted_post['message'] = remove_message_quotes($quoted_post['message'], $max_quote_depth-1); // we're wrapping the message in a [quote] tag, so take away one quote depth level + } + } + + $quoted_post = $plugins->run_hooks("parse_quoted_message", $quoted_post); + + $extra = ''; + if(empty($quoted_post['quote_is_pm'])) + { + $extra = " pid='{$quoted_post['pid']}' dateline='{$quoted_post['dateline']}'"; + } + + return "[quote='{$quoted_post['username']}'{$extra}]\n{$quoted_post['message']}\n[/quote]\n\n"; +} + diff --git a/Upload/inc/functions_rebuild.php b/Upload/inc/functions_rebuild.php new file mode 100644 index 0000000..a1a8940 --- /dev/null +++ b/Upload/inc/functions_rebuild.php @@ -0,0 +1,134 @@ +simple_select("forums", "SUM(threads) AS numthreads, SUM(posts) AS numposts, SUM(unapprovedthreads) AS numunapprovedthreads, SUM(unapprovedposts) AS numunapprovedposts, SUM(deletedthreads) AS numdeletedthreads, SUM(deletedposts) AS numdeletedposts"); + $stats = $db->fetch_array($query); + + $query = $db->simple_select("users", "COUNT(uid) AS users"); + $stats['numusers'] = $db->fetch_field($query, 'users'); + + update_stats($stats, true); +} + +/** + * Completely rebuild the counters for a particular forum (useful if they become out of sync) + * + * @param int The forum ID + */ +function rebuild_forum_counters($fid) +{ + global $db; + + // Fetch the number of threads and replies in this forum (Approved only) + $query = $db->simple_select('threads', 'COUNT(tid) AS threads, SUM(replies) AS replies, SUM(unapprovedposts) AS unapprovedposts, SUM(deletedposts) AS deletedposts', "fid='$fid' AND visible='1'"); + $count = $db->fetch_array($query); + $count['posts'] = $count['threads'] + $count['replies']; + + // Fetch the number of threads and replies in this forum (Unapproved only) + $query = $db->simple_select('threads', 'COUNT(tid) AS threads, SUM(replies)+SUM(unapprovedposts)+SUM(deletedposts) AS impliedunapproved', "fid='$fid' AND visible='0'"); + $count2 = $db->fetch_array($query); + $count['unapprovedthreads'] = $count2['threads']; + $count['unapprovedposts'] += $count2['impliedunapproved']+$count2['threads']; + + // Fetch the number of threads and replies in this forum (Soft deleted only) + $query = $db->simple_select('threads', 'COUNT(tid) AS threads, SUM(replies)+SUM(unapprovedposts)+SUM(deletedposts) AS implieddeleted', "fid='$fid' AND visible='-1'"); + $count3 = $db->fetch_array($query); + $count['deletedthreads'] = $count3['threads']; + $count['deletedposts'] += $count3['implieddeleted']+$count3['threads']; + + update_forum_counters($fid, $count); + update_forum_lastpost($fid); +} + +/** + * Completely rebuild the counters for a particular thread (useful if they become out of sync) + * + * @param int The thread ID + */ +function rebuild_thread_counters($tid) +{ + global $db; + + $thread = get_thread($tid); + $count = array(); + + $query = $db->simple_select("posts", "COUNT(pid) AS replies", "tid='{$tid}' AND pid!='{$thread['firstpost']}' AND visible='1'"); + $count['replies'] = $db->fetch_field($query, "replies"); + + // Unapproved posts + $query = $db->simple_select("posts", "COUNT(pid) AS unapprovedposts", "tid='{$tid}' AND pid != '{$thread['firstpost']}' AND visible='0'"); + $count['unapprovedposts'] = $db->fetch_field($query, "unapprovedposts"); + + // Soft deleted posts + $query = $db->simple_select("posts", "COUNT(pid) AS deletedposts", "tid='{$tid}' AND pid != '{$thread['firstpost']}' AND visible='-1'"); + $count['deletedposts'] = $db->fetch_field($query, "deletedposts"); + + // Attachment count + $query = $db->query(" + SELECT COUNT(aid) AS attachment_count + FROM ".TABLE_PREFIX."attachments a + LEFT JOIN ".TABLE_PREFIX."posts p ON (a.pid=p.pid) + WHERE p.tid='$tid' AND a.visible=1 + "); + $count['attachmentcount'] = $db->fetch_field($query, "attachment_count"); + + update_thread_counters($tid, $count); + update_thread_data($tid); +} + +/** + * Completely rebuild poll counters for a particular poll (useful if they become out of sync) + * + * @param int The poll ID + */ +function rebuild_poll_counters($pid) +{ + global $db; + + $query = $db->simple_select("polls", "pid, numoptions", "pid='".(int)$pid."'"); + $poll = $db->fetch_array($query); + + $votes = array(); + $query = $db->simple_select("pollvotes", "voteoption, COUNT(vid) AS vote_count", "pid='{$poll['pid']}'", array('group_by' => 'voteoption')); + while($vote = $db->fetch_array($query)) + { + $votes[$vote['voteoption']] = $vote['vote_count']; + } + + $voteslist = ''; + $numvotes = ''; + for($i = 1; $i <= $poll['numoptions']; ++$i) + { + if(trim($voteslist != '')) + { + $voteslist .= "||~|~||"; + } + + if(!isset($votes[$i]) || (int)$votes[$i] <= 0) + { + $votes[$i] = "0"; + } + $voteslist .= $votes[$i]; + $numvotes = $numvotes + $votes[$i]; + } + + $updatedpoll = array( + "votes" => $db->escape_string($voteslist), + "numvotes" => (int)$numvotes + ); + $db->update_query("polls", $updatedpoll, "pid='{$poll['pid']}'"); +} diff --git a/Upload/inc/functions_search.php b/Upload/inc/functions_search.php new file mode 100644 index 0000000..b5f19e2 --- /dev/null +++ b/Upload/inc/functions_search.php @@ -0,0 +1,1740 @@ +simple_select("forums", "pid,disporder,fid,password,name", "linkto='' AND active!=0", array('order_by' => "pid, disporder")); + while($forum = $db->fetch_array($query)) + { + $pforumcache[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum; + } + } + if(!is_array($permissioncache)) + { + $permissioncache = forum_permissions(); + } + if(is_array($pforumcache[$pid])) + { + foreach($pforumcache[$pid] as $key => $main) + { + foreach($main as $key => $forum) + { + $perms = $permissioncache[$forum['fid']]; + if(($perms['canview'] == 1 || $mybb->settings['hideprivateforums'] == 0) && $perms['cansearch'] != 0) + { + if($selitem == $forum['fid']) + { + $optionselected = "selected"; + $selecteddone = "1"; + } + else + { + $optionselected = ''; + $selecteddone = "0"; + } + if($forum['password'] != '') + { + if($mybb->cookies['forumpass'][$forum['fid']] == md5($mybb->user['uid'].$forum['password'])) + { + $pwverified = 1; + } + else + { + $pwverified = 0; + } + } + if(empty($forum['password']) || $pwverified == 1) + { + eval("\$forumlistbits .= \"".$templates->get("search_forumlist_forum")."\";"); + } + if(!empty($pforumcache[$forum['fid']])) + { + $newdepth = $depth."    "; + $forumlistbits .= make_searchable_forums($forum['fid'], $selitem, 0, $newdepth); + } + } + } + } + } + if($addselect) + { + eval("\$forumlist = \"".$templates->get("search_forumlist")."\";"); + } + return $forumlist; +} + +/** + * Build a comma separated list of the forums this user cannot search + * + * @param int The parent ID to build from + * @param int First rotation or not (leave at default) + * @return return a CSV list of forums the user cannot search + */ +function get_unsearchable_forums($pid="0", $first=1) +{ + global $db, $forum_cache, $permissioncache, $mybb, $unsearchableforums, $unsearchable, $templates, $forumpass; + + $pid = (int)$pid; + + if(!is_array($forum_cache)) + { + // Get Forums + $query = $db->simple_select("forums", "fid,parentlist,password,active", '', array('order_by' => 'pid, disporder')); + while($forum = $db->fetch_array($query)) + { + $forum_cache[$forum['fid']] = $forum; + } + } + if(!is_array($permissioncache)) + { + $permissioncache = forum_permissions(); + } + foreach($forum_cache as $fid => $forum) + { + if($permissioncache[$forum['fid']]) + { + $perms = $permissioncache[$forum['fid']]; + } + else + { + $perms = $mybb->usergroup; + } + + $pwverified = 1; + if($forum['password'] != '') + { + if($mybb->cookies['forumpass'][$forum['fid']] != md5($mybb->user['uid'].$forum['password'])) + { + $pwverified = 0; + } + } + + $parents = explode(",", $forum['parentlist']); + if(is_array($parents)) + { + foreach($parents as $parent) + { + if($forum_cache[$parent]['active'] == 0) + { + $forum['active'] = 0; + } + } + } + + if($perms['canview'] != 1 || $perms['cansearch'] != 1 || $pwverified == 0 || $forum['active'] == 0) + { + if($unsearchableforums) + { + $unsearchableforums .= ","; + } + $unsearchableforums .= "'{$forum['fid']}'"; + } + } + $unsearchable = $unsearchableforums; + + // Get our unsearchable password protected forums + $pass_protected_forums = get_password_protected_forums(); + + if($unsearchable && $pass_protected_forums) + { + $unsearchable .= ","; + } + + if($pass_protected_forums) + { + $unsearchable .= implode(",", $pass_protected_forums); + } + + return $unsearchable; +} + +/** + * Build a array list of the forums this user cannot search due to password protection + * + * @param int the fids to check (leave null to check all forums) + * @return return a array list of password protected forums the user cannot search + */ +function get_password_protected_forums($fids=array()) +{ + global $forum_cache, $mybb; + + if(!is_array($fids)) + { + return false; + } + + if(!is_array($forum_cache)) + { + $forum_cache = cache_forums(); + if(!$forum_cache) + { + return false; + } + } + + if(empty($fids)) + { + $fids = array_keys($forum_cache); + } + + $pass_fids = array(); + foreach($fids as $fid) + { + if(empty($forum_cache[$fid]['password'])) + { + continue; + } + + if(md5($mybb->user['uid'].$forum_cache[$fid]['password']) != $mybb->cookies['forumpass'][$fid]) + { + $pass_fids[] = $fid; + $child_list = get_child_list($fid); + } + + if(is_array($child_list)) + { + $pass_fids = array_merge($pass_fids, $child_list); + } + } + return array_unique($pass_fids); +} + +/** + * Clean search keywords and make them safe for querying + * + * @param string The keywords to be cleaned + * @return string The cleaned keywords + */ +function clean_keywords($keywords) +{ + $keywords = my_strtolower($keywords); + $keywords = str_replace("%", "\\%", $keywords); + $keywords = preg_replace("#\*{2,}#s", "*", $keywords); + $keywords = str_replace("*", "%", $keywords); + $keywords = preg_replace("#([\[\]\|\.\,:'])#s", " ", $keywords); + $keywords = preg_replace("#\s+#s", " ", $keywords); + + // Search for "and" or "or" and remove if it's at the beginning + $keywords = trim($keywords); + if(my_strpos($keywords, "or") === 0) + { + $keywords = substr_replace($keywords, "", 0, 2); + } + + if(my_strpos($keywords, "and") === 0) + { + $keywords = substr_replace($keywords, "", 0, 3); + } + + return $keywords; +} + +/** + * Clean search keywords for fulltext searching, making them safe for querying + * + * @param string The keywords to be cleaned + * @return string The cleaned keywords + */ +function clean_keywords_ft($keywords) +{ + if(!$keywords) + { + return false; + } + $keywords = my_strtolower($keywords); + $keywords = str_replace("%", "\\%", $keywords); + $keywords = preg_replace("#\*{2,}#s", "*", $keywords); + $keywords = preg_replace("#([\[\]\|\.\,:])#s", " ", $keywords); + // Separate braces for further processing + $keywords = preg_replace("#((\+|-|<|>|~)?\(|\))#s", " $1 ", $keywords); + $keywords = preg_replace("#\s+#s", " ", $keywords); + + $words = array(array()); + + // Fulltext search syntax validation: http://dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html + // Search for phrases + $keywords = explode("\"", $keywords); + $boolean = array('+'); + // Brace depth + $depth = 0; + $phrase_operator = '+'; + foreach($keywords as $phrase) + { + $phrase = trim($phrase); + if($phrase != '') + { + if($inquote) + { + if($phrase_operator) + { + $boolean[$depth] = $phrase_operator; + } + // Phrases do not need further processing + $words[$depth][] = "{$boolean[$depth]}\"{$phrase}\""; + $boolean[$depth] = $phrase_operator = '+'; + } + else + { + // Split words + $split_words = preg_split("#\s{1,}#", $phrase, -1); + if(!is_array($split_words)) + { + continue; + } + if(!$inquote) + { + // Save possible operator in front of phrase + $last_char = substr($phrase, -1); + if($last_char == '+' || $last_char == '-' || $last_char == '<' || $last_char == '>' || $last_char == '~') + { + $phrase_operator = $last_char; + } + } + foreach($split_words as $word) + { + $word = trim($word); + if($word == "or") + { + $boolean[$depth] = ''; + // Remove "and" operator from previous element + $last = array_pop($words[$depth]); + if($last) + { + if(substr($last, 0, 1) == '+') + { + $last = substr($last, 1); + } + $words[$depth][] = $last; + } + } + elseif($word == "and") + { + $boolean[$depth] = "+"; + } + elseif($word == "not") + { + $boolean[$depth] = "-"; + } + // Closing braces + elseif($word == ")") + { + // Ignore when no brace was opened + if($depth > 0) + { + $words[$depth-1][] = $boolean[$depth-1].'('.implode(' ', $words[$depth]).')'; + --$depth; + } + } + // Valid operators for opening braces + elseif($word == '+(' || $word == '-(' || $word == '<(' || $word == '>(' || $word == '~(' || $word == '(') + { + if(strlen($word) == 2) + { + $boolean[$depth] = substr($word, 0, 1); + } + $words[++$depth] = array(); + $boolean[$depth] = '+'; + } + else + { + $operator = substr($word, 0, 1); + switch($operator) + { + // Allowed operators + case '-': + case '+': + case '>': + case '<': + case '~': + $word = substr($word, 1); + break; + default: + $operator = $boolean[$depth]; + break; + } + // Removed operators that are only allowed at the beginning + $word = preg_replace("#(-|\+|<|>|~|@)#s", '', $word); + // Removing wildcards at the beginning http://bugs.mysql.com/bug.php?id=72605 + $word = preg_replace("#^\*#s", '', $word); + $word = $operator.$word; + if(strlen($word) <= 1) + { + continue; + } + $words[$depth][] = $word; + $boolean[$depth] = '+'; + } + } + } + } + $inquote = !$inquote; + } + + // Close mismatching braces + while($depth > 0) + { + $words[$depth-1][] = $boolean[$depth-1].'('.implode(' ', $words[$depth]).')'; + --$depth; + } + + $keywords = implode(' ', $words[0]); + return $keywords; +} + +/* Database engine specific search functions */ + +/** + * Perform a thread and post search under MySQL or MySQLi + * + * @param array Array of search data + * @return array Array of search data with results mixed in + */ +function privatemessage_perform_search_mysql($search) +{ + global $mybb, $db, $lang; + + $keywords = clean_keywords($search['keywords']); + if(!$keywords && !$search['sender']) + { + error($lang->error_nosearchterms); + } + + if($mybb->settings['minsearchword'] < 1) + { + $mybb->settings['minsearchword'] = 3; + } + + $subject_lookin = ""; + $message_lookin = ""; + $searchsql = "uid='{$mybb->user['uid']}'"; + + if($keywords) + { + // Complex search + $keywords = " {$keywords} "; + if(preg_match("#\s(and|or)\s#", $keywords)) + { + $string = "AND"; + if($search['subject'] == 1) + { + $string = "OR"; + $subject_lookin = " AND ("; + } + + if($search['message'] == 1) + { + $message_lookin = " {$string} ("; + } + + // Expand the string by double quotes + $keywords_exp = explode("\"", $keywords); + $inquote = false; + $boolean = ''; + + foreach($keywords_exp as $phrase) + { + // If we're not in a double quoted section + if(!$inquote) + { + // Expand out based on search operators (and, or) + $matches = preg_split("#\s{1,}(and|or)\s{1,}#", $phrase, -1, PREG_SPLIT_DELIM_CAPTURE); + $count_matches = count($matches); + + for($i=0; $i < $count_matches; ++$i) + { + $word = trim($matches[$i]); + if(empty($word)) + { + continue; + } + // If this word is a search operator set the boolean + if($i % 2 && ($word == "and" || $word == "or")) + { + if($i <= 1) + { + if($search['subject'] && $search['message'] && $subject_lookin == " AND (") + { + // We're looking for anything, check for a subject lookin + continue; + } + elseif($search['subject'] && !$search['message'] && $subject_lookin == " AND (") + { + // Just in a subject? + continue; + } + elseif(!$search['subject'] && $search['message'] && $message_lookin == " {$string} (") + { + // Just in a message? + continue; + } + } + + $boolean = $word; + } + // Otherwise check the length of the word as it is a normal search term + else + { + $word = trim($word); + // Word is too short - show error message + if(my_strlen($word) < $mybb->settings['minsearchword']) + { + $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']); + error($lang->error_minsearchlength); + } + // Add terms to search query + if($search['subject'] == 1) + { + $subject_lookin .= " $boolean LOWER(subject) LIKE '%{$word}%'"; + } + if($search['message'] == 1) + { + $message_lookin .= " $boolean LOWER(message) LIKE '%{$word}%'"; + } + $boolean = 'AND'; + } + } + } + // In the middle of a quote (phrase) + else + { + $phrase = str_replace(array("+", "-", "*"), '', trim($phrase)); + if(my_strlen($phrase) < $mybb->settings['minsearchword']) + { + $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']); + error($lang->error_minsearchlength); + } + // Add phrase to search query + $subject_lookin .= " $boolean LOWER(subject) LIKE '%{$phrase}%'"; + if($search['message'] == 1) + { + $message_lookin .= " $boolean LOWER(message) LIKE '%{$phrase}%'"; + } + $boolean = 'AND'; + } + + // Check to see if we have any search terms and not a malformed SQL string + $error = false; + if($search['subject'] && $search['message'] && $subject_lookin == " AND (") + { + // We're looking for anything, check for a subject lookin + $error = true; + } + elseif($search['subject'] && !$search['message'] && $subject_lookin == " AND (") + { + // Just in a subject? + $error = true; + } + elseif(!$search['subject'] && $search['message'] && $message_lookin == " {$string} (") + { + // Just in a message? + $error = true; + } + + if($error == true) + { + // There are no search keywords to look for + $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']); + error($lang->error_minsearchlength); + } + + $inquote = !$inquote; + } + + if($search['subject'] == 1) + { + $subject_lookin .= ")"; + } + + if($search['message'] == 1) + { + $message_lookin .= ")"; + } + + $searchsql .= "{$subject_lookin} {$message_lookin}"; + } + else + { + $keywords = str_replace("\"", '', trim($keywords)); + if(my_strlen($keywords) < $mybb->settings['minsearchword']) + { + $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']); + error($lang->error_minsearchlength); + } + + // If we're looking in both, then find matches in either the subject or the message + if($search['subject'] == 1 && $search['message'] == 1) + { + $searchsql .= " AND (LOWER(subject) LIKE '%{$keywords}%' OR LOWER(message) LIKE '%{$keywords}%')"; + } + else + { + if($search['subject'] == 1) + { + $searchsql .= " AND LOWER(subject) LIKE '%{$keywords}%'"; + } + + if($search['message'] == 1) + { + $searchsql .= " AND LOWER(message) LIKE '%{$keywords}%'"; + } + } + } + } + + if($search['sender']) + { + $userids = array(); + $search['sender'] = my_strtolower($search['sender']); + + $query = $db->simple_select("users", "uid", "LOWER(username) LIKE '%".$db->escape_string_like($search['sender'])."%'"); + while($user = $db->fetch_array($query)) + { + $userids[] = $user['uid']; + } + + if(count($userids) < 1) + { + error($lang->error_nosearchresults); + } + else + { + $userids = implode(',', $userids); + $searchsql .= " AND fromid IN (".$userids.")"; + } + } + + if(!is_array($search['folder'])) + { + $search['folder'] = array($search['folder']); + } + + if(!empty($search['folder'])) + { + $folderids = array(); + + $search['folder'] = array_map("intval", $search['folder']); + + $folderids = implode(',', $search['folder']); + + if($folderids) + { + $searchsql .= " AND folder IN (".$folderids.")"; + } + } + + if($search['status']) + { + $searchsql .= " AND ("; + if($search['status']['new']) + { + $statussql[] = " status='0' "; + } + if($search['status']['replied']) + { + $statussql[] = " status='3' "; + } + if($search['status']['forwarded']) + { + $statussql[] = " status='4' "; + } + if($search['status']['read']) + { + $statussql[] = " (status != '0' AND readtime > '0') "; + } + // Sent Folder + if(in_array(2, $search['folder'])) + { + $statussql[] = " status='1' "; + } + $statussql = implode("OR", $statussql); + $searchsql .= $statussql.")"; + } + + // Run the search + $pms = array(); + $query = $db->simple_select("privatemessages", "pmid", $searchsql); + while($pm = $db->fetch_array($query)) + { + $pms[$pm['pmid']] = $pm['pmid']; + } + + if(count($pms) < 1) + { + error($lang->error_nosearchresults); + } + $pms = implode(',', $pms); + + return array( + "querycache" => $pms + ); +} + +/** + * Perform a help document search under MySQL or MySQLi + * + * @param array Array of search data + * @return array Array of search data with results mixed in + */ +function helpdocument_perform_search_mysql($search) +{ + global $mybb, $db, $lang; + + $keywords = clean_keywords($search['keywords']); + if(!$keywords && !$search['sender']) + { + error($lang->error_nosearchterms); + } + + if($mybb->settings['minsearchword'] < 1) + { + $mybb->settings['minsearchword'] = 3; + } + + $name_lookin = ""; + $document_lookin = ""; + $searchsql = "enabled='1'"; + + if($keywords) + { + // Complex search + $keywords = " {$keywords} "; + if(preg_match("#\s(and|or)\s#", $keywords)) + { + $string = "AND"; + if($search['name'] == 1) + { + $string = "OR"; + $name_lookin = " AND ("; + } + + if($search['document'] == 1) + { + $document_lookin = " {$string} ("; + } + + // Expand the string by double quotes + $keywords_exp = explode("\"", $keywords); + $inquote = false; + + foreach($keywords_exp as $phrase) + { + // If we're not in a double quoted section + if(!$inquote) + { + // Expand out based on search operators (and, or) + $matches = preg_split("#\s{1,}(and|or)\s{1,}#", $phrase, -1, PREG_SPLIT_DELIM_CAPTURE); + $count_matches = count($matches); + + for($i=0; $i < $count_matches; ++$i) + { + $word = trim($matches[$i]); + if(empty($word)) + { + continue; + } + // If this word is a search operator set the boolean + if($i % 2 && ($word == "and" || $word == "or")) + { + if($i <= 1) + { + if($search['name'] && $search['document'] && $name_lookin == " AND (") + { + // We're looking for anything, check for a name lookin + continue; + } + elseif($search['name'] && !$search['document'] && $name_lookin == " AND (") + { + // Just in a name? + continue; + } + elseif(!$search['name'] && $search['document'] && $document_lookin == " {$string} (") + { + // Just in a document? + continue; + } + } + + $boolean = $word; + } + // Otherwise check the length of the word as it is a normal search term + else + { + $word = trim($word); + // Word is too short - show error message + if(my_strlen($word) < $mybb->settings['minsearchword']) + { + $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']); + error($lang->error_minsearchlength); + } + // Add terms to search query + if($search['name'] == 1) + { + $name_lookin .= " $boolean LOWER(name) LIKE '%{$word}%'"; + } + if($search['document'] == 1) + { + $document_lookin .= " $boolean LOWER(document) LIKE '%{$word}%'"; + } + } + } + } + // In the middle of a quote (phrase) + else + { + $phrase = str_replace(array("+", "-", "*"), '', trim($phrase)); + if(my_strlen($phrase) < $mybb->settings['minsearchword']) + { + $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']); + error($lang->error_minsearchlength); + } + // Add phrase to search query + $name_lookin .= " $boolean LOWER(name) LIKE '%{$phrase}%'"; + if($search['document'] == 1) + { + $document_lookin .= " $boolean LOWER(document) LIKE '%{$phrase}%'"; + } + } + + // Check to see if we have any search terms and not a malformed SQL string + $error = false; + if($search['name'] && $search['document'] && $name_lookin == " AND (") + { + // We're looking for anything, check for a name lookin + $error = true; + } + elseif($search['name'] && !$search['document'] && $name_lookin == " AND (") + { + // Just in a name? + $error = true; + } + elseif(!$search['name'] && $search['document'] && $document_lookin == " {$string} (") + { + // Just in a document? + $error = true; + } + + if($error == true) + { + // There are no search keywords to look for + $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']); + error($lang->error_minsearchlength); + } + + $inquote = !$inquote; + } + + if($search['name'] == 1) + { + $name_lookin .= ")"; + } + + if($search['document'] == 1) + { + $document_lookin .= ")"; + } + + $searchsql .= "{$name_lookin} {$document_lookin}"; + } + else + { + $keywords = str_replace("\"", '', trim($keywords)); + if(my_strlen($keywords) < $mybb->settings['minsearchword']) + { + $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']); + error($lang->error_minsearchlength); + } + + // If we're looking in both, then find matches in either the name or the document + if($search['name'] == 1 && $search['document'] == 1) + { + $searchsql .= " AND (LOWER(name) LIKE '%{$keywords}%' OR LOWER(document) LIKE '%{$keywords}%')"; + } + else + { + if($search['name'] == 1) + { + $searchsql .= " AND LOWER(name) LIKE '%{$keywords}%'"; + } + + if($search['document'] == 1) + { + $searchsql .= " AND LOWER(document) LIKE '%{$keywords}%'"; + } + } + } + } + + // Run the search + $helpdocs = array(); + $query = $db->simple_select("helpdocs", "hid", $searchsql); + while($help = $db->fetch_array($query)) + { + $helpdocs[$help['hid']] = $help['hid']; + } + + if(count($helpdocs) < 1) + { + error($lang->error_nosearchresults); + } + $helpdocs = implode(',', $helpdocs); + + return array( + "querycache" => $helpdocs + ); +} + +/** + * Perform a thread and post search under MySQL or MySQLi + * + * @param array Array of search data + * @return array Array of search data with results mixed in + */ +function perform_search_mysql($search) +{ + global $mybb, $db, $lang, $cache; + + $keywords = clean_keywords($search['keywords']); + if(!$keywords && !$search['author']) + { + error($lang->error_nosearchterms); + } + + if($mybb->settings['minsearchword'] < 1) + { + $mybb->settings['minsearchword'] = 3; + } + + $subject_lookin = $message_lookin = ''; + if($keywords) + { + // Complex search + $keywords = " {$keywords} "; + if(preg_match("#\s(and|or)\s#", $keywords)) + { + $subject_lookin = " AND ("; + $message_lookin = " AND ("; + + // Expand the string by double quotes + $keywords_exp = explode("\"", $keywords); + $inquote = false; + $boolean = ''; + + foreach($keywords_exp as $phrase) + { + // If we're not in a double quoted section + if(!$inquote) + { + // Expand out based on search operators (and, or) + $matches = preg_split("#\s{1,}(and|or)\s{1,}#", $phrase, -1, PREG_SPLIT_DELIM_CAPTURE); + $count_matches = count($matches); + + for($i=0; $i < $count_matches; ++$i) + { + $word = trim($matches[$i]); + if(empty($word)) + { + continue; + } + // If this word is a search operator set the boolean + if($i % 2 && ($word == "and" || $word == "or")) + { + if($i <= 1 && $subject_lookin == " AND (") + { + continue; + } + + $boolean = $word; + } + // Otherwise check the length of the word as it is a normal search term + else + { + $word = trim($word); + // Word is too short - show error message + if(my_strlen($word) < $mybb->settings['minsearchword']) + { + $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']); + error($lang->error_minsearchlength); + } + // Add terms to search query + $subject_lookin .= " $boolean LOWER(t.subject) LIKE '%{$word}%'"; + if($search['postthread'] == 1) + { + $message_lookin .= " $boolean LOWER(p.message) LIKE '%{$word}%'"; + } + $boolean = 'AND'; + } + } + } + // In the middle of a quote (phrase) + else + { + $phrase = str_replace(array("+", "-", "*"), '', trim($phrase)); + if(my_strlen($phrase) < $mybb->settings['minsearchword']) + { + $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']); + error($lang->error_minsearchlength); + } + // Add phrase to search query + $subject_lookin .= " $boolean LOWER(t.subject) LIKE '%{$phrase}%'"; + if($search['postthread'] == 1) + { + $message_lookin .= " $boolean LOWER(p.message) LIKE '%{$phrase}%'"; + } + $boolean = 'AND'; + } + + if($subject_lookin == " AND (") + { + // There are no search keywords to look for + $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']); + error($lang->error_minsearchlength); + } + + $inquote = !$inquote; + } + $subject_lookin .= ")"; + $message_lookin .= ")"; + } + else + { + $keywords = str_replace("\"", '', trim($keywords)); + if(my_strlen($keywords) < $mybb->settings['minsearchword']) + { + $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']); + error($lang->error_minsearchlength); + } + $subject_lookin = " AND LOWER(t.subject) LIKE '%{$keywords}%'"; + if($search['postthread'] == 1) + { + $message_lookin = " AND LOWER(p.message) LIKE '%{$keywords}%'"; + } + } + } + $post_usersql = ''; + $thread_usersql = ''; + if($search['author']) + { + $userids = array(); + $search['author'] = my_strtolower($search['author']); + if($search['matchusername']) + { + $query = $db->simple_select("users", "uid", "LOWER(username)='".$db->escape_string($search['author'])."'"); + } + else + { + $query = $db->simple_select("users", "uid", "LOWER(username) LIKE '%".$db->escape_string_like($search['author'])."%'"); + } + + while($user = $db->fetch_array($query)) + { + $userids[] = $user['uid']; + } + if(count($userids) < 1) + { + error($lang->error_nosearchresults); + } + else + { + $userids = implode(',', $userids); + $post_usersql = " AND p.uid IN (".$userids.")"; + $thread_usersql = " AND t.uid IN (".$userids.")"; + } + } + $datecut = $post_datecut = $thread_datecut = ''; + if($search['postdate']) + { + if($search['pddir'] == 0) + { + $datecut = "<="; + } + else + { + $datecut = ">="; + } + $now = TIME_NOW; + $datelimit = $now-(86400 * $search['postdate']); + $datecut .= "'$datelimit'"; + $post_datecut = " AND p.dateline $datecut"; + $thread_datecut = " AND t.dateline $datecut"; + } + + $thread_replycut = ''; + if($search['numreplies'] != '' && $search['findthreadst']) + { + if((int)$search['findthreadst'] == 1) + { + $thread_replycut = " AND t.replies >= '".(int)$search['numreplies']."'"; + } + else + { + $thread_replycut = " AND t.replies <= '".(int)$search['numreplies']."'"; + } + } + + $thread_prefixcut = ''; + $prefixlist = array(); + if($search['threadprefix'] && $search['threadprefix'][0] != 'any') + { + foreach($search['threadprefix'] as $threadprefix) + { + $threadprefix = (int)$threadprefix; + $prefixlist[] = $threadprefix; + } + } + if(count($prefixlist) == 1) + { + $thread_prefixcut .= " AND t.prefix='$threadprefix' "; + } + else + { + if(count($prefixlist) > 1) + { + $thread_prefixcut = " AND t.prefix IN (".implode(',', $prefixlist).")"; + } + } + + $forumin = ''; + $fidlist = array(); + $searchin = array(); + if(!is_array($search['forums']) || $search['forums'][0] != "all") + { + if(!is_array($search['forums'])) + { + $search['forums'] = array((int)$search['forums']); + } + // Generate a comma separated list of all groups the user belongs to + $user_groups = $mybb->user['usergroup']; + if($mybb->user['additionalgroups']) + { + $user_groups .= ",".$mybb->user['additionalgroups']; + + // Setup some quick permissions for us + $fcache = $cache->read("forumpermissions"); + $add_groups = explode(",", $mybb->user['additionalgroups']); + } + foreach($search['forums'] as $forum) + { + $forum = (int)$forum; + if(empty($searchin[$forum])) + { + if(isset($add_groups) && is_array($add_groups)) + { + $can_search = 0; + foreach($add_groups as $add_group) + { + // Check to make sure that we have sufficient permissions to search this forum + if(!is_array($fcache[$forum][$add_group]) || $fcache[$forum][$add_group]['cansearch'] == 1 || $mybb->usergroup['cansearch'] == 1) + { + $can_search = 1; + } + } + + if($can_search == 0) + { + // We can't search this forum... + continue; + } + } + + switch($db->type) + { + case "pgsql": + $query = $db->simple_select("forums", "DISTINCT fid", "(','||parentlist||',' LIKE ',%{$forum}%,') = true AND active != 0"); + break; + case "sqlite": + $query = $db->simple_select("forums", "DISTINCT fid", "(','||parentlist||',' LIKE ',%{$forum}%,') > 0 AND active != 0"); + break; + default: + $query = $db->simple_select("forums", "DISTINCT fid", "INSTR(CONCAT(',',parentlist,','),',{$forum},') > 0 AND active != 0"); + } + + while($sforum = $db->fetch_array($query)) + { + $fidlist[] = $sforum['fid']; + } + } + } + if(count($fidlist) == 1) + { + $forumin .= " AND t.fid='$forum' "; + $searchin[$forum] = 1; + } + else + { + if(count($fidlist) > 1) + { + $forumin = " AND t.fid IN (".implode(',', $fidlist).")"; + } + } + } + + $permsql = ""; + $onlyusfids = array(); + + // Check group permissions if we can't view threads not started by us + if($group_permissions = forum_permissions()) + { + foreach($group_permissions as $fid => $forum_permissions) + { + if(isset($forum_permissions['canonlyviewownthreads']) && $forum_permissions['canonlyviewownthreads'] == 1) + { + $onlyusfids[] = $fid; + } + } + } + if(!empty($onlyusfids)) + { + $permsql .= "AND ((t.fid IN(".implode(',', $onlyusfids).") AND t.uid='{$mybb->user['uid']}') OR t.fid NOT IN(".implode(',', $onlyusfids)."))"; + } + + $unsearchforums = get_unsearchable_forums(); + if($unsearchforums) + { + $permsql .= " AND t.fid NOT IN ($unsearchforums)"; + } + $inactiveforums = get_inactive_forums(); + if($inactiveforums) + { + $permsql .= " AND t.fid NOT IN ($inactiveforums)"; + } + + $visiblesql = $post_visiblesql = $plain_post_visiblesql = ""; + if(isset($search['visible'])) + { + if($search['visible'] == 1) + { + $visiblesql = " AND t.visible = '1'"; + + if($search['postthread'] == 1) + { + $post_visiblesql = " AND p.visible = '1'"; + $plain_post_visiblesql = " AND visible = '1'"; + } + } + elseif($search['visible'] == -1) + { + $visiblesql = " AND t.visible = '-1'"; + + if($search['postthread'] == 1) + { + $post_visiblesql = " AND p.visible = '-1'"; + $plain_post_visiblesql = " AND visible = '-1'"; + } + } + else + { + $visiblesql = " AND t.visible == '0'"; + + if($search['postthread'] == 1) + { + $post_visiblesql = " AND p.visible == '0'"; + $plain_post_visiblesql = " AND visible == '0'"; + } + } + } + + // Searching a specific thread? + $tidsql = ''; + if(!empty($search['tid'])) + { + $tidsql = " AND t.tid='".(int)$search['tid']."'"; + } + + $limitsql = ''; + if((int)$mybb->settings['searchhardlimit'] > 0) + { + $limitsql = "LIMIT ".(int)$mybb->settings['searchhardlimit']; + } + + // Searching both posts and thread titles + $threads = array(); + $posts = array(); + $firstposts = array(); + if($search['postthread'] == 1) + { + // No need to search subjects when looking for results within a specific thread + if(empty($search['tid'])) + { + $query = $db->query(" + SELECT t.tid, t.firstpost + FROM ".TABLE_PREFIX."threads t + WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} AND t.closed NOT LIKE 'moved|%' {$subject_lookin} + {$limitsql} + "); + while($thread = $db->fetch_array($query)) + { + $threads[$thread['tid']] = $thread['tid']; + if($thread['firstpost']) + { + $posts[$thread['tid']] = $thread['firstpost']; + } + } + } + + $query = $db->query(" + SELECT p.pid, p.tid + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + WHERE 1=1 {$post_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$post_usersql} {$permsql} {$tidsql} {$visiblesql} {$post_visiblesql} AND t.closed NOT LIKE 'moved|%' {$message_lookin} + {$limitsql} + "); + while($post = $db->fetch_array($query)) + { + $posts[$post['pid']] = $post['pid']; + $threads[$post['tid']] = $post['tid']; + } + + if(count($posts) < 1 && count($threads) < 1) + { + error($lang->error_nosearchresults); + } + $threads = implode(',', $threads); + $posts = implode(',', $posts); + + } + // Searching only thread titles + else + { + $query = $db->query(" + SELECT t.tid, t.firstpost + FROM ".TABLE_PREFIX."threads t + WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} {$subject_lookin} + {$limitsql} + "); + while($thread = $db->fetch_array($query)) + { + $threads[$thread['tid']] = $thread['tid']; + if($thread['firstpost']) + { + $firstposts[$thread['tid']] = $thread['firstpost']; + } + } + if(count($threads) < 1) + { + error($lang->error_nosearchresults); + } + + $threads = implode(',', $threads); + $firstposts = implode(',', $firstposts); + if($firstposts) + { + $query = $db->simple_select("posts", "pid", "pid IN ($firstposts) {$plain_post_visiblesql} {$limitsql}"); + while($post = $db->fetch_array($query)) + { + $posts[$post['pid']] = $post['pid']; + } + $posts = implode(',', $posts); + } + } + return array( + "threads" => $threads, + "posts" => $posts, + "querycache" => '' + ); +} + +/** + * Perform a thread and post search under MySQL or MySQLi using boolean fulltext capabilities + * + * @param array Array of search data + * @return array Array of search data with results mixed in + */ +function perform_search_mysql_ft($search) +{ + global $mybb, $db, $lang; + + $keywords = clean_keywords_ft($search['keywords']); + if(!$keywords && !$search['author']) + { + error($lang->error_nosearchterms); + } + + // Attempt to determine minimum word length from MySQL for fulltext searches + $query = $db->query("SHOW VARIABLES LIKE 'ft_min_word_len';"); + $min_length = $db->fetch_field($query, 'Value'); + if(is_numeric($min_length)) + { + $mybb->settings['minsearchword'] = $min_length; + } + // Otherwise, could not fetch - default back to MySQL fulltext default setting + else + { + $mybb->settings['minsearchword'] = 4; + } + + if($keywords) + { + $keywords_exp = explode("\"", $keywords); + $inquote = false; + foreach($keywords_exp as $phrase) + { + if(!$inquote) + { + $split_words = preg_split("#\s{1,}#", $phrase, -1); + foreach($split_words as $word) + { + $word = str_replace(array("+", "-", "*"), '', $word); + if(!$word) + { + continue; + } + if(my_strlen($word) < $mybb->settings['minsearchword']) + { + $all_too_short = true; + } + else + { + $all_too_short = false; + break; + } + } + } + else + { + $phrase = str_replace(array("+", "-", "*"), '', $phrase); + if(my_strlen($phrase) < $mybb->settings['minsearchword']) + { + $all_too_short = true; + } + else + { + $all_too_short = false; + break; + } + } + $inquote = !$inquote; + } + // Show the minimum search term error only if all search terms are too short + if($all_too_short == true) + { + $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']); + error($lang->error_minsearchlength); + } + $message_lookin = "AND MATCH(message) AGAINST('".$db->escape_string($keywords)."' IN BOOLEAN MODE)"; + $subject_lookin = "AND MATCH(subject) AGAINST('".$db->escape_string($keywords)."' IN BOOLEAN MODE)"; + } + $post_usersql = ''; + $thread_usersql = ''; + if($search['author']) + { + $userids = array(); + $search['author'] = my_strtolower($search['author']); + if($search['matchusername']) + { + $query = $db->simple_select("users", "uid", "LOWER(username)='".$db->escape_string($search['author'])."'"); + } + else + { + $query = $db->simple_select("users", "uid", "LOWER(username) LIKE '%".$db->escape_string_like($search['author'])."%'"); + } + + while($user = $db->fetch_array($query)) + { + $userids[] = $user['uid']; + } + + if(count($userids) < 1) + { + error($lang->error_nosearchresults); + } + else + { + $userids = implode(',', $userids); + $post_usersql = " AND p.uid IN (".$userids.")"; + $thread_usersql = " AND t.uid IN (".$userids.")"; + } + } + $datecut = ''; + if($search['postdate']) + { + if($search['pddir'] == 0) + { + $datecut = "<="; + } + else + { + $datecut = ">="; + } + $now = TIME_NOW; + $datelimit = $now-(86400 * $search['postdate']); + $datecut .= "'$datelimit'"; + $post_datecut = " AND p.dateline $datecut"; + $thread_datecut = " AND t.dateline $datecut"; + } + + $thread_replycut = ''; + if($search['numreplies'] != '' && $search['findthreadst']) + { + if((int)$search['findthreadst'] == 1) + { + $thread_replycut = " AND t.replies >= '".(int)$search['numreplies']."'"; + } + else + { + $thread_replycut = " AND t.replies <= '".(int)$search['numreplies']."'"; + } + } + + $thread_prefixcut = ''; + $prefixlist = array(); + if($search['threadprefix'] && $search['threadprefix'][0] != 'any') + { + foreach($search['threadprefix'] as $threadprefix) + { + $threadprefix = (int)$threadprefix; + $prefixlist[] = $threadprefix; + } + } + if(count($prefixlist) == 1) + { + $thread_prefixcut .= " AND t.prefix='$threadprefix' "; + } + else + { + if(count($prefixlist) > 1) + { + $thread_prefixcut = " AND t.prefix IN (".implode(',', $prefixlist).")"; + } + } + + $forumin = ''; + $fidlist = array(); + $searchin = array(); + if(!is_array($search['forums']) || $search['forums'][0] != "all") + { + if(!is_array($search['forums'])) + { + $search['forums'] = array((int)$search['forums']); + } + // Generate a comma separated list of all groups the user belongs to + $user_groups = $mybb->user['usergroup']; + if($mybb->user['additionalgroups']) + { + $user_groups .= ",".$mybb->user['additionalgroups']; + } + foreach($search['forums'] as $forum) + { + $forum = (int)$forum; + if(empty($searchin[$forum])) + { + switch($db->type) + { + case "pgsql": + case "sqlite": + $query = $db->query(" + SELECT f.fid + FROM ".TABLE_PREFIX."forums f + LEFT JOIN ".TABLE_PREFIX."forumpermissions p ON (f.fid=p.fid AND p.gid IN (".$user_groups.")) + WHERE INSTR(','||parentlist||',',',$forum,') > 0 AND active!=0 AND ((p.fid) IS NULL OR p.cansearch=1) + "); + break; + default: + $query = $db->query(" + SELECT f.fid + FROM ".TABLE_PREFIX."forums f + LEFT JOIN ".TABLE_PREFIX."forumpermissions p ON (f.fid=p.fid AND p.gid IN (".$user_groups.")) + WHERE INSTR(CONCAT(',',parentlist,','),',$forum,') > 0 AND active!=0 AND ((p.fid) IS NULL OR p.cansearch=1) + "); + } + while($sforum = $db->fetch_array($query)) + { + $fidlist[] = $sforum['fid']; + } + } + } + if(count($fidlist) == 1) + { + $forumin .= " AND t.fid='$forum' "; + $searchin[$forum] = 1; + } + else + { + + if(count($fidlist) > 1) + { + $forumin = " AND t.fid IN (".implode(',', $fidlist).")"; + } + } + } + $permsql = ""; + $onlyusfids = array(); + + // Check group permissions if we can't view threads not started by us + $group_permissions = forum_permissions(); + foreach($group_permissions as $fid => $forum_permissions) + { + if($forum_permissions['canonlyviewownthreads'] == 1) + { + $onlyusfids[] = $fid; + } + } + if(!empty($onlyusfids)) + { + $permsql .= "AND ((t.fid IN(".implode(',', $onlyusfids).") AND t.uid='{$mybb->user['uid']}') OR t.fid NOT IN(".implode(',', $onlyusfids)."))"; + } + + $unsearchforums = get_unsearchable_forums(); + if($unsearchforums) + { + $permsql .= " AND t.fid NOT IN ($unsearchforums)"; + } + $inactiveforums = get_inactive_forums(); + if($inactiveforums) + { + $permsql .= " AND t.fid NOT IN ($inactiveforums)"; + } + + $visiblesql = $post_visiblesql = $plain_post_visiblesql = ""; + if(isset($search['visible'])) + { + if($search['visible'] == 1) + { + $visiblesql = " AND t.visible = '1'"; + + if($search['postthread'] == 1) + { + $post_visiblesql = " AND p.visible = '1'"; + $plain_post_visiblesql = " AND visible = '1'"; + } + } + elseif($search['visible'] == -1) + { + $visiblesql = " AND t.visible = '-1'"; + + if($search['postthread'] == 1) + { + $post_visiblesql = " AND p.visible = '-1'"; + $plain_post_visiblesql = " AND visible = '-1'"; + } + } + else + { + $visiblesql = " AND t.visible != '1'"; + + if($search['postthread'] == 1) + { + $post_visiblesql = " AND p.visible != '1'"; + $plain_post_visiblesql = " AND visible != '1'"; + } + } + } + + // Searching a specific thread? + if($search['tid']) + { + $tidsql = " AND t.tid='".(int)$search['tid']."'"; + } + + $limitsql = ''; + if((int)$mybb->settings['searchhardlimit'] > 0) + { + $limitsql = "LIMIT ".(int)$mybb->settings['searchhardlimit']; + } + + // Searching both posts and thread titles + $threads = array(); + $posts = array(); + $firstposts = array(); + if($search['postthread'] == 1) + { + // No need to search subjects when looking for results within a specific thread + if(!$search['tid']) + { + $query = $db->query(" + SELECT t.tid, t.firstpost + FROM ".TABLE_PREFIX."threads t + WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} AND t.closed NOT LIKE 'moved|%' {$subject_lookin} + {$limitsql} + "); + while($thread = $db->fetch_array($query)) + { + $threads[$thread['tid']] = $thread['tid']; + if($thread['firstpost']) + { + $posts[$thread['tid']] = $thread['firstpost']; + } + } + } + + $query = $db->query(" + SELECT p.pid, p.tid + FROM ".TABLE_PREFIX."posts p + LEFT JOIN ".TABLE_PREFIX."threads t ON (t.tid=p.tid) + WHERE 1=1 {$post_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$post_usersql} {$permsql} {$tidsql} {$post_visiblesql} {$visiblesql} AND t.closed NOT LIKE 'moved|%' {$message_lookin} + {$limitsql} + "); + while($post = $db->fetch_array($query)) + { + $posts[$post['pid']] = $post['pid']; + $threads[$post['tid']] = $post['tid']; + } + if(count($posts) < 1 && count($threads) < 1) + { + error($lang->error_nosearchresults); + } + $threads = implode(',', $threads); + $posts = implode(',', $posts); + + } + // Searching only thread titles + else + { + $query = $db->query(" + SELECT t.tid, t.firstpost + FROM ".TABLE_PREFIX."threads t + WHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} {$subject_lookin} + {$limitsql} + "); + while($thread = $db->fetch_array($query)) + { + $threads[$thread['tid']] = $thread['tid']; + if($thread['firstpost']) + { + $firstposts[$thread['tid']] = $thread['firstpost']; + } + } + if(count($threads) < 1) + { + error($lang->error_nosearchresults); + } + + $threads = implode(',', $threads); + $firstposts = implode(',', $firstposts); + if($firstposts) + { + $query = $db->simple_select("posts", "pid", "pid IN ($firstposts) {$plain_post_visiblesql} {$limitsql}"); + while($post = $db->fetch_array($query)) + { + $posts[$post['pid']] = $post['pid']; + } + $posts = implode(',', $posts); + } + } + return array( + "threads" => $threads, + "posts" => $posts, + "querycache" => '' + ); +} diff --git a/Upload/inc/functions_serverstats.php b/Upload/inc/functions_serverstats.php new file mode 100644 index 0000000..3aa7f83 --- /dev/null +++ b/Upload/inc/functions_serverstats.php @@ -0,0 +1,333 @@ + array( + 'dom' => array('bitwise' => 1, 'title' => 'DOMElement'), + 'soap' => array('bitwise' => 2, 'title' => 'SoapClient'), + 'xmlwriter' => array('bitwise' => 4, 'title' => 'XMLWriter'), + 'imagemagick' => array('bitwise' => 8, 'title' => 'Imagick'), + ), + + 'extensions' => array( + 'zendopt' => array('bitwise' => 1, 'title' => 'Zend Optimizer'), + 'xcache' => array('bitwise' => 2, 'title' => 'XCache'), + 'eaccelerator' => array('bitwise' => 4, 'title' => 'eAccelerator'), + 'ioncube' => array('bitwise' => 8, 'title' => 'ionCube Loader'), + 'PDO' => array('bitwise' => 16, 'title' => 'PDO'), + 'pdo_mysql' => array('bitwise' => 32, 'title' => 'pdo_mysql'), + 'pdo_pgsql' => array('bitwise' => 64, 'title' => 'pdo_pgsql'), + 'pdo_sqlite' => array('bitwise' => 128, 'title' => 'pdo_sqlite'), + 'pdo_oci' => array('bitwise' => 256, 'title' => 'pdo_oci'), + 'pdo_odbc' => array('bitwise' => 512, 'title' => 'pdo_odbc'), + ), + + 'phpinfo' => array( + 'zlib' => array('bitwise' => 1, 'title' => 'zlib'), + 'mbstring' => array('bitwise' => 2, 'title' => 'mbstring'), + 'exif' => array('bitwise' => 4, 'title' => 'exif'), + 'zlib' => array('bitwise' => 8, 'title' => 'zlib'), + + ), + + 'functions' => array( + 'sockets' => array('bitwise' => 1, 'title' => 'fsockopen'), + 'mcrypt' => array('bitwise' => 2, 'title' => 'mcrypt_encrypt'), + 'simplexml' => array('bitwise' => 4, 'title' => 'simplexml_load_string'), + 'ldap' => array('bitwise' => 8, 'title' => 'ldap_connect'), + 'mysqli' => array('bitwise' => 16, 'title' => 'mysqli_connect'), + 'imap' => array('bitwise' => 32, 'title' => 'imap_open'), + 'ftp' => array('bitwise' => 64, 'title' => 'ftp_login'), + 'pspell' => array('bitwise' => 128, 'title' => 'pspell_new'), + 'apc' => array('bitwise' => 256, 'title' => 'apc_cache_info'), + 'curl' => array('bitwise' => 512, 'title' => 'curl_init'), + 'iconv' => array('bitwise' => 1024, 'title' => 'iconv'), + ), + + 'php_ini' => array( + 'post_max_size' => 'post_max_size', + 'upload_max_filesize' => 'upload_max_filesize', + 'safe_mode' => 'safe_mode', + ), + ); + + foreach($check as $cat_name => $category) + { + foreach($category as $name => $what) + { + if(!isset($info[$cat_name])) + { + $info[$cat_name] = 0; + } + switch($cat_name) + { + case "classes": + if(class_exists($what['title'])) + { + $info[$cat_name] |= $what['bitwise']; + } + break; + case "extensions": + if(extension_loaded($what['title'])) + { + $info[$cat_name] |= $what['bitwise']; + } + break; + case "phpinfo": + if(array_key_exists($what['title'], $phpinfo)) + { + $info[$cat_name] |= $what['bitwise']; + } + break; + case "functions": + if(function_exists($what['title'])) + { + $info[$cat_name] |= $what['bitwise']; + } + break; + case "php_ini": + if(ini_get($what) != 0) + { + $info[$name] = ini_get($what); + } + else + { + $info[$name] = 0; + } + break; + } + } + } + + // Host URL & hostname + $info['hosturl'] = $info['hostname'] = "unknown/local"; + if($_SERVER['HTTP_HOST'] == 'localhost') + { + $info['hosturl'] = $info['hostname'] = "localhost"; + } + + // Check the hosting company + if(strpos($_SERVER['HTTP_HOST'], ".") !== false) + { + $host_url = "http://www.whoishostingthis.com/".str_replace(array('http://', 'www.'), '', $_SERVER['HTTP_HOST']); + + $hosting = fetch_remote_file($host_url); + + if($hosting) + { + preg_match('#We believe \
    ([^<]*)\<\/a\>#ism', $hosting, $matches); + + $info['hosturl'] = "unknown/no-url"; + if(isset($matches[1]) && strlen(trim($matches[1])) != 0 && strpos($matches[1], '.') !== false) + { + $info['hosturl'] = strtolower($matches[1]); + } + else if(isset($matches[3]) && strlen(trim($matches[3])) != 0 && strpos($matches[3], '.') !== false) + { + $info['hosturl'] = strtolower($matches[3]); + } + + if(isset($matches[4]) && strlen(trim($matches[4])) != 0) + { + $info['hostname'] = $matches[4]; + } + elseif(isset($matches[3]) && strlen(trim($matches[3])) != 0) + { + $info['hostname'] = $matches[3]; + } + elseif(isset($matches[2]) && strlen(trim($matches[2])) != 0) + { + $info['hostname'] = str_replace(array('title=', '"'), '', $matches[2][0]); + } + elseif(strlen(trim($info['hosturl'])) != 0 && $info['hosturl'] != "unknown/no-url") + { + $info['hostname'] = $info['hosturl']; + } + else + { + $info['hostname'] = "unknown/no-name"; + } + } + } + + if(isset($_SERVER['HTTP_USER_AGENT'])) + { + $info['useragent'] = $_SERVER['HTTP_USER_AGENT']; + } + + // We need a unique ID for the host so hash it to keep it private and send it over + $id = $_SERVER['HTTP_HOST'].time(); + + if(function_exists('sha1')) + { + $info['clientid'] = sha1($id); + } + else + { + $info['clientid'] = md5($id); + } + + $string = ""; + $amp = ""; + foreach($info as $key => $value) + { + $string .= $amp.$key."=".urlencode($value); + $amp = "&"; + } + + $server_stats_url = 'http://community.mybb.com/server_stats.php?'.$string; + + $return = array(); + $return['info_sent_success'] = false; + if(fetch_remote_file($server_stats_url) !== false) + { + $return['info_sent_success'] = true; + } + $return['info_image'] = ""; + $return['info_get_string'] = $string; + + return $return; +} + +/** +* parser_php_info +* Function to get and parse the list of PHP info into a usuable array +* +* @return Array An array of all the extensions installed in PHP +*/ +function parse_php_info() +{ + ob_start(); + phpinfo(INFO_MODULES); + $phpinfo_html = ob_get_contents(); + ob_end_clean(); + + $phpinfo_html = strip_tags($phpinfo_html, "

    + All Larabie Fonts are free for commercial use but a sample of your product would be + gratefully appreciated so I can see how the font looks in use. Contact www.larabiefonts.com/donation.html for + mailing information. +

    "); + $phpinfo_html = preg_replace("#]*>([^<]+)<\/th>#", "$1", $phpinfo_html); + $phpinfo_html = preg_replace("#]*>([^<]+)<\/td>#", "$1", $phpinfo_html); + $phpinfo_html = preg_split("#(]*>[^<]+<\/h2>)#", $phpinfo_html, -1, PREG_SPLIT_DELIM_CAPTURE); + $modules = array(); + + for($i=1; $i < count($phpinfo_html); $i++) + { + if(preg_match("#]*>([^<]+)<\/h2>#", $phpinfo_html[$i], $match)) + { + $name = trim($match[1]); + $tmp2 = explode("\n", $phpinfo_html[$i+1]); + foreach($tmp2 as $one) + { + $pat = '([^<]+)<\/info>'; + $pat3 = "/$pat\s*$pat\s*$pat/"; + $pat2 = "/$pat\s*$pat/"; + + // 3 columns + if(preg_match($pat3, $one, $match)) + { + $modules[$name][trim($match[1])] = array(trim($match[2]), trim($match[3])); + } + // 2 columns + else if(preg_match($pat2, $one, $match)) + { + $modules[$name][trim($match[1])] = trim($match[2]); + } + } + } + } + return $modules; +} + diff --git a/Upload/inc/functions_task.php b/Upload/inc/functions_task.php new file mode 100644 index 0000000..c6800d7 --- /dev/null +++ b/Upload/inc/functions_task.php @@ -0,0 +1,370 @@ + 0) + { + $query = $db->simple_select("tasks", "*", "tid='{$tid}'"); + $task = $db->fetch_array($query); + } + + // Run the next task due to be run + else + { + $query = $db->simple_select("tasks", "*", "enabled=1 AND nextrun<='".TIME_NOW."'", array("order_by" => "nextrun", "order_dir" => "asc", "limit" => 1)); + $task = $db->fetch_array($query); + } + + // No task? Return + if(!$task['tid']) + { + $cache->update_tasks(); + return false; + } + + // Is this task still running and locked less than 5 minutes ago? Well don't run it now - clearly it isn't broken! + if($task['locked'] != 0 && $task['locked'] > TIME_NOW-300) + { + $cache->update_tasks(); + return false; + } + // Lock it! It' mine, all mine! + else + { + $db->update_query("tasks", array("locked" => TIME_NOW), "tid='{$task['tid']}'"); + } + + // The task file does not exist + if(!file_exists(MYBB_ROOT."inc/tasks/{$task['file']}.php")) + { + if($task['logging'] == 1) + { + add_task_log($task, $lang->missing_task); + } + $cache->update_tasks(); + return false; + } + // Run the task + else + { + // Update the nextrun time now, so if the task causes a fatal error, it doesn't get stuck first in the queue + $nextrun = fetch_next_run($task); + $db->update_query("tasks", array("nextrun" => $nextrun), "tid='{$task['tid']}'"); + + include_once MYBB_ROOT."inc/tasks/{$task['file']}.php"; + $function = "task_{$task['file']}"; + if(function_exists($function)) + { + $function($task); + } + } + + $updated_task = array( + "lastrun" => TIME_NOW, + "locked" => 0 + ); + $db->update_query("tasks", $updated_task, "tid='{$task['tid']}'"); + + $cache->update_tasks(); + + return true; +} + +/** + * Adds information to the scheduled task log. + * + * @param int The task array to create the log entry for + * @param string The message to log + */ +function add_task_log($task, $message) +{ + global $db; + + if(!$task['logging']) + { + return; + } + + $log_entry = array( + "tid" => (int)$task['tid'], + "dateline" => TIME_NOW, + "data" => $db->escape_string($message) + ); + $db->insert_query("tasklog", $log_entry); +} + +/** + * Generate the next run time for a particular task. + * + * @param array The task array as fetched from the database. + * @return int The next run time as a UNIX timestamp + */ +function fetch_next_run($task) +{ + $time = TIME_NOW; + $next_minute = $current_minute = date("i", $time); + $next_hour = $current_hour = date("H", $time); + $next_day = $current_day = date("d", $time); + $next_weekday = $current_weekday = date("w", $time); + $next_month = $current_month = date("m", $time); + $next_year = $current_year = date("Y", $time); + $reset_day = $reset_hour = $reset_month = $reset_year = 0; + + if($task['minute'] == "*") + { + ++$next_minute; + if($next_minute > 59) + { + $reset_hour = 1; + $next_minute = 0; + } + } + else + { + if(build_next_run_bit($task['minute'], $current_minute) != false) + { + $next_minute = build_next_run_bit($task['minute'], $current_minute); + } + else + { + $next_minute = fetch_first_run_time($task['minute']); + } + if($next_minute <= $current_minute) + { + $reset_hour = 1; + } + } + + if($reset_hour || !run_time_exists($task['hour'], $current_hour)) + { + if($task['hour'] == "*") + { + ++$next_hour; + if($next_hour > 23) + { + $reset_day = 1; + $next_hour = 0; + } + } + else + { + if(build_next_run_bit($task['hour'], $current_hour) != false) + { + $next_hour = build_next_run_bit($task['hour'], $current_hour); + } + else + { + $next_hour = fetch_first_run_time($task['hour']); + $reset_day = 1; + } + if($next_hour < $current_hour) + { + $reset_day = 1; + } + } + $next_minute = fetch_first_run_time($task['minute']); + } + + if($reset_day || ($task['weekday'] == "*" && !run_time_exists($task['day'], $current_day) || $task['day'] == "*" && !run_time_exists($task['weekday'], $current_weekday))) + { + if($task['weekday'] == "*") + { + if($task['day'] == "*") + { + ++$next_day; + if($next_day > date("t", $time)) + { + $reset_month = 1; + $next_day = 1; + } + } + else + { + if(build_next_run_bit($task['day'], $current_day) != false) + { + $next_day = build_next_run_bit($task['day'], $current_day); + } + else + { + $next_day = fetch_first_run_time($task['day']); + $reset_month = 1; + } + if($next_day < $current_day) + { + $reset_month = 1; + } + } + } + else + { + if(build_next_run_bit($task['weekday'], $current_weekday) != false) + { + $next_weekday = build_next_run_bit($task['weekday'], $current_weekday); + } + else + { + $next_weekday = fetch_first_run_time($task['weekday']); + } + $next_day = $current_day + ($next_weekday-$current_weekday); + if($next_day <= $current_day) + { + $next_day += 7; + } + + if($next_day > date("t", $time)) + { + $reset_month = 1; + } + } + $next_minute = fetch_first_run_time($task['minute']); + $next_hour = fetch_first_run_time($task['hour']); + if($next_day == $current_day && $next_hour < $current_hour) + { + $reset_month = 1; + } + } + + if($reset_month || !run_time_exists($task['month'], $current_month)) + { + if($task['month'] == "*") + { + $next_month++; + if($next_month > 12) + { + $reset_year = 1; + $next_month = 1; + } + } + else + { + if(build_next_run_bit($task['month'], $current_month) != false) + { + $next_month = build_next_run_bit($task['month'], $current_month); + } + else + { + $next_month = fetch_first_run_time($task['month']); + $reset_year = 1; + } + if($next_month < $current_month) + { + $reset_year = 1; + } + } + $next_minute = fetch_first_run_time($task['minute']); + $next_hour = fetch_first_run_time($task['hour']); + if($task['weekday'] == "*") + { + $next_day = fetch_first_run_time($task['day']); + if($next_day == 0) $next_day = 1; + } + else + { + $next_weekday = fetch_first_run_time($task['weekday']); + $new_weekday = date("w", mktime($next_hour, $next_minute, 0, $next_month, 1, $next_year)); + $next_day = 1 + ($next_weekday-$new_weekday); + if($next_weekday < $new_weekday) + { + $next_day += 7; + } + } + if($next_month == $current_month && $next_day == $current_day && $next_hour < $current_hour) + { + $reset_year = 1; + } + } + + if($reset_year) + { + $next_year++; + $next_minute = fetch_first_run_time($task['minute']); + $next_hour = fetch_first_run_time($task['hour']); + $next_month = fetch_first_run_time($task['month']); + if($next_month == 0) $next_month = 1; + if($task['weekday'] == "*") + { + $next_day = fetch_first_run_time($task['day']); + if($next_day == 0) $next_day = 1; + } + else + { + $next_weekday = fetch_first_run_time($task['weekday']); + $new_weekday = date("w", mktime($next_hour, $next_minute, 0, $next_month, 1, $next_year)); + $next_day = 1 + ($next_weekday-$new_weekday); + if($next_weekday < $new_weekday) + { + $next_day += 7; + } + } + } + return mktime($next_hour, $next_minute, 0, $next_month, $next_day, $next_year); +} + +/** + * Builds the next run time bit for a particular item (day, hour, month etc). Used by fetch_next_run(). + * + * @param string A string containing the run timse for this particular item + * @param int The current value (be it current day etc) + * @return int The new or found value + */ +function build_next_run_bit($data, $bit) +{ + if($data == "*") return $bit; + $data = explode(",", $data); + foreach($data as $thing) + { + if($thing > $bit) + { + return $thing; + } + } + return false; +} + +/** + * Fetches the fist run bit for a particular item (day, hour, month etc). Used by fetch_next_run(). + * + * @param string A string containing the run times for this particular item + * @return int The first run time + */ +function fetch_first_run_time($data) +{ + if($data == "*") return "0"; + $data = explode(",", $data); + return $data[0]; +} + +/** + * Checks if a specific run time exists for a particular item (day, hour, month etc). Used by fetch_next_run(). + * + * @param string A string containing the run times for this particular item + * @param int The bit we're checking for + * @return boolean True if it exists, false if it does not + */ +function run_time_exists($data, $bit) +{ + if($data == "*") return true; + $data = explode(",", $data); + if(in_array($bit, $data)) + { + return true; + } + return false; +} diff --git a/Upload/inc/functions_time.php b/Upload/inc/functions_time.php new file mode 100644 index 0000000..862f980 --- /dev/null +++ b/Upload/inc/functions_time.php @@ -0,0 +1,878 @@ + 4 digit year conversion. The maximum is billions of years in the +future, but this is a theoretical limit as the computation of that year +would take too long with the current implementation of adodb_mktime(). + +This library replaces native functions as follows: + +
    +	getdate()  with  adodb_getdate()
    +	date()     with  adodb_date()
    +	gmdate()   with  adodb_gmdate()
    +	mktime()   with  adodb_mktime()
    +	gmmktime() with  adodb_gmmktime()
    +	strftime() with  adodb_strftime()
    +	strftime() with  adodb_gmstrftime()
    +
    + +The parameters are identical, except that adodb_date() accepts a subset +of date()'s field formats. Mktime() will convert from local time to GMT, +and date() will convert from GMT to local time, but daylight savings is +not handled currently. + +This library is independant of the rest of ADOdb, and can be used +as standalone code. + +PERFORMANCE + +For high speed, this library uses the native date functions where +possible, and only switches to PHP code when the dates fall outside +the 32-bit signed integer range. + +GREGORIAN CORRECTION + +Pope Gregory shortened October of A.D. 1582 by ten days. Thursday, +October 4, 1582 (Julian) was followed immediately by Friday, October 15, +1582 (Gregorian). + +Since 0.06, we handle this correctly, so: + +adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582) + == 24 * 3600 (1 day) + +============================================================================= + +COPYRIGHT + +(c) 2003-2005 John Lim and released under BSD-style license except for code by +jackbbs, which includes adodb_mktime, adodb_get_gmt_diff, adodb_is_leap_year +and originally found at http://www.php.net/manual/en/function.mktime.php + +============================================================================= + +BUG REPORTS + +These should be posted to the ADOdb forums at + + http://phplens.com/lens/lensforum/topics.php?id=4 + +============================================================================= +*/ + + +/* Initialization */ + +/* + Version Number +*/ +define('ADODB_DATE_VERSION', 0.33); + +$ADODB_DATETIME_CLASS = (PHP_VERSION >= 5.2); + +/* + This code was originally for windows. But apparently this problem happens + also with Linux, RH 7.3 and later! + + glibc-2.2.5-34 and greater has been changed to return -1 for dates < + 1970. This used to work. The problem exists with RedHat 7.3 and 8.0 + echo (mktime(0, 0, 0, 1, 1, 1960)); // prints -1 + + References: + http://bugs.php.net/bug.php?id=20048&edit=2 + http://lists.debian.org/debian-glibc/2002/debian-glibc-200205/msg00010.html +*/ + +if (!defined('ADODB_ALLOW_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1); + +/** + Returns day of week, 0 = Sunday,... 6=Saturday. + Algorithm from PEAR::Date_Calc +*/ +function adodb_dow($year, $month, $day) +{ +/* +Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and +proclaimed that from that time onwards 3 days would be dropped from the calendar +every 400 years. + +Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian). +*/ + if ($year <= 1582) { + if ($year < 1582 || + ($year == 1582 && ($month < 10 || ($month == 10 && $day < 15)))) $greg_correction = 3; + else + $greg_correction = 0; + } else + $greg_correction = 0; + + if($month > 2) + $month -= 2; + else { + $month += 10; + $year--; + } + + $day = floor((13 * $month - 1) / 5) + + $day + ($year % 100) + + floor(($year % 100) / 4) + + floor(($year / 100) / 4) - 2 * + floor($year / 100) + 77 + $greg_correction; + + return $day - 7 * floor($day / 7); +} + +/** + Checks for leap year, returns true if it is. No 2-digit year check. Also + handles julian calendar correctly. +*/ +function _adodb_is_leap_year($year) +{ + if ($year % 4 != 0) return false; + + if ($year % 400 == 0) { + return true; + // if gregorian calendar (>1582), century not-divisible by 400 is not leap + } else if ($year > 1582 && $year % 100 == 0 ) { + return false; + } + + return true; +} + +/** + checks for leap year, returns true if it is. Has 2-digit year check +*/ +function adodb_is_leap_year($year) +{ + return _adodb_is_leap_year(adodb_year_digit_check($year)); +} + +/** + Fix 2-digit years. Works for any century. + Assumes that if 2-digit is more than 30 years in future, then previous century. +*/ +function adodb_year_digit_check($y) +{ + if ($y < 100) { + + $yr = (integer) date("Y"); + $century = (integer) ($yr /100); + + if ($yr%100 > 50) { + $c1 = $century + 1; + $c0 = $century; + } else { + $c1 = $century; + $c0 = $century - 1; + } + $c1 *= 100; + // if 2-digit year is less than 30 years in future, set it to this century + // otherwise if more than 30 years in future, then we set 2-digit year to the prev century. + if (($y + $c1) < $yr+30) $y = $y + $c1; + else $y = $y + $c0*100; + } + return $y; +} + +function adodb_get_gmt_diff_ts($ts) +{ + if (0 <= $ts && $ts <= 0x7FFFFFFF) { // check if number in 32-bit signed range) { + $arr = getdate($ts); + $y = $arr['year']; + $m = $arr['mon']; + $d = $arr['mday']; + return adodb_get_gmt_diff($y,$m,$d); + } else { + return adodb_get_gmt_diff(false,false,false); + } + +} + +/** + get local time zone offset from GMT. Does not handle historical timezones before 1970. +*/ +function adodb_get_gmt_diff($y,$m,$d) +{ +static $TZ,$tzo; +global $ADODB_DATETIME_CLASS; + + if (!defined('ADODB_TEST_DATES')) $y = false; + else if ($y < 1970 || $y >= 2038) $y = false; + + if ($ADODB_DATETIME_CLASS && $y !== false) { + $dt = new DateTime(); + $dt->setISODate($y,$m,$d); + if (empty($tzo)) { + $tzo = new DateTimeZone(date_default_timezone_get()); + # $tzt = timezone_transitions_get( $tzo ); + } + return -$tzo->getOffset($dt); + } else { + if (isset($TZ)) return $TZ; + $y = date('Y'); + $TZ = mktime(0,0,0,12,2,$y) - gmmktime(0,0,0,12,2,$y); + } + + return $TZ; +} + +/** + Returns an array with date info. +*/ +function adodb_getdate($d=false,$fast=false) +{ + if ($d === false) return getdate(); + if (!defined('ADODB_TEST_DATES')) { + if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range + if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer + return @getdate($d); + } + } + return _adodb_getdate($d); +} + +$_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31); +$_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31); + +/** + Low-level function that returns the getdate() array. We have a special + $fast flag, which if set to true, will return fewer array values, + and is much faster as it does not calculate dow, etc. +*/ +function _adodb_getdate($origd=false,$fast=false,$is_gmt=false) +{ +static $YRS; +global $_month_table_normal,$_month_table_leaf; + + $d = $origd - ($is_gmt ? 0 : adodb_get_gmt_diff_ts($origd)); + $_day_power = 86400; + $_hour_power = 3600; + $_min_power = 60; + + if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction + + $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31); + $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31); + + $d366 = $_day_power * 366; + $d365 = $_day_power * 365; + + if ($d < 0) { + + if (empty($YRS)) $YRS = array( + 1970 => 0, + 1960 => -315619200, + 1950 => -631152000, + 1940 => -946771200, + 1930 => -1262304000, + 1920 => -1577923200, + 1910 => -1893456000, + 1900 => -2208988800, + 1890 => -2524521600, + 1880 => -2840140800, + 1870 => -3155673600, + 1860 => -3471292800, + 1850 => -3786825600, + 1840 => -4102444800, + 1830 => -4417977600, + 1820 => -4733596800, + 1810 => -5049129600, + 1800 => -5364662400, + 1790 => -5680195200, + 1780 => -5995814400, + 1770 => -6311347200, + 1760 => -6626966400, + 1750 => -6942499200, + 1740 => -7258118400, + 1730 => -7573651200, + 1720 => -7889270400, + 1710 => -8204803200, + 1700 => -8520336000, + 1690 => -8835868800, + 1680 => -9151488000, + 1670 => -9467020800, + 1660 => -9782640000, + 1650 => -10098172800, + 1640 => -10413792000, + 1630 => -10729324800, + 1620 => -11044944000, + 1610 => -11360476800, + 1600 => -11676096000); + + if ($is_gmt) $origd = $d; + // The valid range of a 32bit signed timestamp is typically from + // Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT + // + + # old algorithm iterates through all years. new algorithm does it in + # 10 year blocks + + /* + # old algo + for ($a = 1970 ; --$a >= 0;) { + $lastd = $d; + + if ($leaf = _adodb_is_leap_year($a)) $d += $d366; + else $d += $d365; + + if ($d >= 0) { + $year = $a; + break; + } + } + */ + + $lastsecs = 0; + $lastyear = 1970; + foreach($YRS as $year => $secs) { + if ($d >= $secs) { + $a = $lastyear; + break; + } + $lastsecs = $secs; + $lastyear = $year; + } + + $d -= $lastsecs; + if (!isset($a)) $a = $lastyear; + + //echo ' yr=',$a,' ', $d,'.'; + + for (; --$a >= 0;) { + $lastd = $d; + + if ($leaf = _adodb_is_leap_year($a)) $d += $d366; + else $d += $d365; + + if ($d >= 0) { + $year = $a; + break; + } + } + /**/ + + $secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd; + + $d = $lastd; + $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal; + for ($a = 13 ; --$a > 0;) { + $lastd = $d; + $d += $mtab[$a] * $_day_power; + if ($d >= 0) { + $month = $a; + $ndays = $mtab[$a]; + break; + } + } + + $d = $lastd; + $day = $ndays + ceil(($d+1) / ($_day_power)); + + $d += ($ndays - $day+1)* $_day_power; + $hour = floor($d/$_hour_power); + + } else { + for ($a = 1970 ;; $a++) { + $lastd = $d; + + if ($leaf = _adodb_is_leap_year($a)) $d -= $d366; + else $d -= $d365; + if ($d < 0) { + $year = $a; + break; + } + } + $secsInYear = $lastd; + $d = $lastd; + $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal; + for ($a = 1 ; $a <= 12; $a++) { + $lastd = $d; + $d -= $mtab[$a] * $_day_power; + if ($d < 0) { + $month = $a; + $ndays = $mtab[$a]; + break; + } + } + $d = $lastd; + $day = ceil(($d+1) / $_day_power); + $d = $d - ($day-1) * $_day_power; + $hour = floor($d /$_hour_power); + } + + $d -= $hour * $_hour_power; + $min = floor($d/$_min_power); + $secs = $d - $min * $_min_power; + if ($fast) { + return array( + 'seconds' => $secs, + 'minutes' => $min, + 'hours' => $hour, + 'mday' => $day, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secsInYear/$_day_power), + 'leap' => $leaf, + 'ndays' => $ndays + ); + } + + $dow = adodb_dow($year,$month,$day); + + return array( + 'seconds' => $secs, + 'minutes' => $min, + 'hours' => $hour, + 'mday' => $day, + 'wday' => $dow, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secsInYear/$_day_power), + 'weekday' => gmdate('l',$_day_power*(3+$dow)), + 'month' => gmdate('F',mktime(0,0,0,$month,2,1971)), + 0 => $origd + ); +} + +function adodb_tz_offset($gmt,$isphp5) +{ + $zhrs = abs($gmt)/3600; + $hrs = floor($zhrs); + if ($isphp5) + return sprintf('%s%02d%02d',($gmt<=0)?'+':'-',floor($zhrs),($zhrs-$hrs)*60); + else + return sprintf('%s%02d%02d',($gmt<0)?'+':'-',floor($zhrs),($zhrs-$hrs)*60); + break; +} + +function adodb_gmdate($fmt,$d=false) +{ + return adodb_date($fmt,$d,true); +} + +// accepts unix timestamp and iso date format in $d +function adodb_date2($fmt, $d=false, $is_gmt=false) +{ + if ($d !== false) { + if (!preg_match( + "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ -]?(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|", + ($d), $rr)) return adodb_date($fmt,false,$is_gmt); + + if ($rr[1] <= 100 && $rr[2]<= 1) return adodb_date($fmt,false,$is_gmt); + + // h-m-s-MM-DD-YY + if (!isset($rr[5])) $d = adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1],false,$is_gmt); + else $d = @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1],false,$is_gmt); + } + + return adodb_date($fmt,$d,$is_gmt); +} + +/** + Return formatted date based on timestamp $d +*/ +function adodb_date($fmt,$d=false,$is_gmt=false) +{ +static $daylight; +global $ADODB_DATETIME_CLASS; + + if ($d === false) return ($is_gmt)? @gmdate($fmt): @date($fmt); + if (!defined('ADODB_TEST_DATES')) { + if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range + if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer + return ($is_gmt)? @gmdate($fmt,$d): @date($fmt,$d); + + } + } + $_day_power = 86400; + + $arr = _adodb_getdate($d,true,$is_gmt); + + if (!isset($daylight)) $daylight = function_exists('adodb_daylight_sv'); + if ($daylight) adodb_daylight_sv($arr, $is_gmt); + + $year = $arr['year']; + $month = $arr['mon']; + $day = $arr['mday']; + $hour = $arr['hours']; + $min = $arr['minutes']; + $secs = $arr['seconds']; + + $max = strlen($fmt); + $dates = ''; + + $isphp5 = PHP_VERSION >= 5; + + /* + at this point, we have the following integer vars to manipulate: + $year, $month, $day, $hour, $min, $secs + */ + for ($i=0; $i < $max; $i++) { + switch($fmt[$i]) { + case 'T': + if ($ADODB_DATETIME_CLASS) { + $dt = new DateTime(); + $dt->SetDate($year,$month,$day); + $dates .= $dt->Format('T'); + } else + $dates .= date('T'); + break; + // YEAR + case 'L': $dates .= $arr['leap'] ? '1' : '0'; break; + case 'r': // Thu, 21 Dec 2000 16:01:07 +0200 + + // 4.3.11 uses '04 Jun 2004' + // 4.3.8 uses ' 4 Jun 2004' + $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))).', ' + . ($day<10?'0'.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' '; + + if ($hour < 10) $dates .= '0'.$hour; else $dates .= $hour; + + if ($min < 10) $dates .= ':0'.$min; else $dates .= ':'.$min; + + if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs; + + $gmt = adodb_get_gmt_diff($year,$month,$day); + + $dates .= ' '.adodb_tz_offset($gmt,$isphp5); + break; + + case 'Y': $dates .= $year; break; + case 'y': $dates .= substr($year,strlen($year)-2,2); break; + // MONTH + case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break; + case 'Q': $dates .= ($month+3)>>2; break; + case 'n': $dates .= $month; break; + case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break; + case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break; + // DAY + case 't': $dates .= $arr['ndays']; break; + case 'z': $dates .= $arr['yday']; break; + case 'w': $dates .= adodb_dow($year,$month,$day); break; + case 'l': $dates .= gmdate('l',$_day_power*(3+adodb_dow($year,$month,$day))); break; + case 'D': $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))); break; + case 'j': $dates .= $day; break; + case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; break; + case 'S': + $d10 = $day % 10; + if ($d10 == 1) $dates .= 'st'; + else if ($d10 == 2 && $day != 12) $dates .= 'nd'; + else if ($d10 == 3) $dates .= 'rd'; + else $dates .= 'th'; + break; + + // HOUR + case 'Z': + $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff($year,$month,$day); break; + case 'O': + $gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff($year,$month,$day); + + $dates .= adodb_tz_offset($gmt,$isphp5); + break; + + case 'H': + if ($hour < 10) $dates .= '0'.$hour; + else $dates .= $hour; + break; + case 'h': + if ($hour > 12) $hh = $hour - 12; + else { + if ($hour == 0) $hh = '12'; + else $hh = $hour; + } + + if ($hh < 10) $dates .= '0'.$hh; + else $dates .= $hh; + break; + + case 'G': + $dates .= $hour; + break; + + case 'g': + if ($hour > 12) $hh = $hour - 12; + else { + if ($hour == 0) $hh = '12'; + else $hh = $hour; + } + $dates .= $hh; + break; + // MINUTES + case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break; + // SECONDS + case 'U': $dates .= $d; break; + case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break; + // AM/PM + // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM + case 'a': + if ($hour>=12) $dates .= 'pm'; + else $dates .= 'am'; + break; + case 'A': + if ($hour>=12) $dates .= 'PM'; + else $dates .= 'AM'; + break; + default: + $dates .= $fmt[$i]; break; + // ESCAPE + case "\\": + $i++; + if ($i < $max) $dates .= $fmt[$i]; + break; + } + } + return $dates; +} + +/** + Returns a timestamp given a GMT/UTC time. + Note that $is_dst is not implemented and is ignored. +*/ +function adodb_gmmktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false) +{ + return adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst,true); +} + +/** + Return a timestamp given a local time. Originally by jackbbs. + Note that $is_dst is not implemented and is ignored. + + Not a very fast algorithm - O(n) operation. Could be optimized to O(1). + + NOTE: returns time() when the year is > 9999 +*/ +function adodb_mktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false,$is_gmt=false) +{ + if (!defined('ADODB_TEST_DATES')) { + + if ($mon === false) { + return $is_gmt? @gmmktime($hr,$min,$sec): @mktime($hr,$min,$sec); + } + + // for windows, we don't check 1970 because with timezone differences, + // 1 Jan 1970 could generate negative timestamp, which is illegal + $usephpfns = (1971 < $year && $year < 2038 + || !defined('ADODB_NO_NEGATIVE_TS') && (1901 < $year && $year < 2038) + ); + + + if ($usephpfns && ($year + $mon/12+$day/365.25+$hr/(24*365.25) >= 2038)) $usephpfns = false; + + if ($usephpfns) { + return $is_gmt ? + @gmmktime($hr,$min,$sec,$mon,$day,$year): + @mktime($hr,$min,$sec,$mon,$day,$year); + } + } + + $gmt_different = ($is_gmt) ? 0 : adodb_get_gmt_diff($year,$mon,$day); + + /* + # disabled because some people place large values in $sec. + # however we need it for $mon because we use an array... + $hr = (int)$hr; + $min = (int)$min; + $sec = (int)$sec; + */ + $mon = (int)$mon; + $day = (int)$day; + $year = (int)$year; + + + $year = adodb_year_digit_check($year); + + if ($mon > 12) { + $y = floor(($mon-1)/ 12); + $year += $y; + $mon -= $y*12; + } else if ($mon < 1) { + $y = ceil((1-$mon) / 12); + $year -= $y; + $mon += $y*12; + } + + $_day_power = 86400; + $_hour_power = 3600; + $_min_power = 60; + + $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31); + $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31); + + $_total_date = 0; + if($year > 9999) { + return time(); + } else if ($year >= 1970) { + for ($a = 1970 ; $a <= $year; $a++) { + $leaf = _adodb_is_leap_year($a); + if ($leaf == true) { + $loop_table = $_month_table_leaf; + $_add_date = 366; + } else { + $loop_table = $_month_table_normal; + $_add_date = 365; + } + if ($a < $year) { + $_total_date += $_add_date; + } else { + for($b=1;$b<$mon;$b++) { + $_total_date += $loop_table[$b]; + } + } + } + $_total_date +=$day-1; + $ret = $_total_date * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different; + + } else { + for ($a = 1969 ; $a >= $year; $a--) { + $leaf = _adodb_is_leap_year($a); + if ($leaf == true) { + $loop_table = $_month_table_leaf; + $_add_date = 366; + } else { + $loop_table = $_month_table_normal; + $_add_date = 365; + } + if ($a > $year) { $_total_date += $_add_date; + } else { + for($b=12;$b>$mon;$b--) { + $_total_date += $loop_table[$b]; + } + } + } + $_total_date += $loop_table[$mon] - $day; + + $_day_time = $hr * $_hour_power + $min * $_min_power + $sec; + $_day_time = $_day_power - $_day_time; + $ret = -( $_total_date * $_day_power + $_day_time - $gmt_different); + if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction + else if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582. + } + //print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret; + return $ret; +} + +function adodb_gmstrftime($fmt, $ts=false) +{ + return adodb_strftime($fmt,$ts,true); +} + +// hack - convert to adodb_date +function adodb_strftime($fmt, $ts=false,$is_gmt=false) +{ +global $ADODB_DATE_LOCALE; + + if (!defined('ADODB_TEST_DATES')) { + if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range + if (!defined('ADODB_NO_NEGATIVE_TS') || $ts >= 0) // if windows, must be +ve integer + return ($is_gmt)? @gmstrftime($fmt,$ts): @strftime($fmt,$ts); + + } + } + + if (empty($ADODB_DATE_LOCALE)) { + /* + $tstr = strtoupper(gmstrftime('%c',31366800)); // 30 Dec 1970, 1 am + $sep = substr($tstr,2,1); + $hasAM = strrpos($tstr,'M') !== false; + */ + # see http://phplens.com/lens/lensforum/msgs.php?id=14865 for reasoning, and changelog for version 0.24 + $dstr = gmstrftime('%x',31366800); // 30 Dec 1970, 1 am + $sep = substr($dstr,2,1); + $tstr = strtoupper(gmstrftime('%X',31366800)); // 30 Dec 1970, 1 am + $hasAM = strrpos($tstr,'M') !== false; + + $ADODB_DATE_LOCALE = array(); + $ADODB_DATE_LOCALE[] = strncmp($tstr,'30',2) == 0 ? 'd'.$sep.'m'.$sep.'y' : 'm'.$sep.'d'.$sep.'y'; + $ADODB_DATE_LOCALE[] = ($hasAM) ? 'h:i:s a' : 'H:i:s'; + + } + $inpct = false; + $fmtdate = ''; + for ($i=0,$max = strlen($fmt); $i < $max; $i++) { + $ch = $fmt[$i]; + if ($ch == '%') { + if ($inpct) { + $fmtdate .= '%'; + $inpct = false; + } else + $inpct = true; + } else if ($inpct) { + + $inpct = false; + switch($ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'E': + case 'O': + /* ignore format modifiers */ + $inpct = true; + break; + + case 'a': $fmtdate .= 'D'; break; + case 'A': $fmtdate .= 'l'; break; + case 'h': + case 'b': $fmtdate .= 'M'; break; + case 'B': $fmtdate .= 'F'; break; + case 'c': $fmtdate .= $ADODB_DATE_LOCALE[0].$ADODB_DATE_LOCALE[1]; break; + case 'C': $fmtdate .= '\C?'; break; // century + case 'd': $fmtdate .= 'd'; break; + case 'D': $fmtdate .= 'm/d/y'; break; + case 'e': $fmtdate .= 'j'; break; + case 'g': $fmtdate .= '\g?'; break; //? + case 'G': $fmtdate .= '\G?'; break; //? + case 'H': $fmtdate .= 'H'; break; + case 'I': $fmtdate .= 'h'; break; + case 'j': $fmtdate .= '?z'; $parsej = true; break; // wrong as j=1-based, z=0-basd + case 'm': $fmtdate .= 'm'; break; + case 'M': $fmtdate .= 'i'; break; + case 'n': $fmtdate .= "\n"; break; + case 'p': $fmtdate .= 'a'; break; + case 'r': $fmtdate .= 'h:i:s a'; break; + case 'R': $fmtdate .= 'H:i:s'; break; + case 'S': $fmtdate .= 's'; break; + case 't': $fmtdate .= "\t"; break; + case 'T': $fmtdate .= 'H:i:s'; break; + case 'u': $fmtdate .= '?u'; $parseu = true; break; // wrong strftime=1-based, date=0-based + case 'U': $fmtdate .= '?U'; $parseU = true; break;// wrong strftime=1-based, date=0-based + case 'x': $fmtdate .= $ADODB_DATE_LOCALE[0]; break; + case 'X': $fmtdate .= $ADODB_DATE_LOCALE[1]; break; + case 'w': $fmtdate .= '?w'; $parseu = true; break; // wrong strftime=1-based, date=0-based + case 'W': $fmtdate .= '?W'; $parseU = true; break;// wrong strftime=1-based, date=0-based + case 'y': $fmtdate .= 'y'; break; + case 'Y': $fmtdate .= 'Y'; break; + case 'Z': $fmtdate .= 'T'; break; + } + } else if (('A' <= ($ch) && ($ch) <= 'Z' ) || ('a' <= ($ch) && ($ch) <= 'z' )) + $fmtdate .= "\\".$ch; + else + $fmtdate .= $ch; + } + //echo "fmt=",$fmtdate,"
    "; + if ($ts === false) $ts = time(); + $ret = adodb_date($fmtdate, $ts, $is_gmt); + return $ret; +} + diff --git a/Upload/inc/functions_upload.php b/Upload/inc/functions_upload.php new file mode 100644 index 0000000..ad98216 --- /dev/null +++ b/Upload/inc/functions_upload.php @@ -0,0 +1,771 @@ +escape_string($posthash); + if($posthash != "") + { + $query = $db->simple_select("attachments", "aid, attachname, thumbnail, visible", "aid='{$aid}' AND posthash='{$posthash}'"); + $attachment = $db->fetch_array($query); + } + else + { + $query = $db->simple_select("attachments", "aid, attachname, thumbnail, visible", "aid='{$aid}' AND pid='{$pid}'"); + $attachment = $db->fetch_array($query); + } + + $plugins->run_hooks("remove_attachment_do_delete", $attachment); + + $db->delete_query("attachments", "aid='{$attachment['aid']}'"); + + if(defined('IN_ADMINCP')) + { + $uploadpath = '../'.$mybb->settings['uploadspath']; + } + else + { + $uploadpath = $mybb->settings['uploadspath']; + } + + // Check if this attachment is referenced in any other posts. If it isn't, then we are safe to delete the actual file. + $query = $db->simple_select("attachments", "COUNT(aid) as numreferences", "attachname='".$db->escape_string($attachment['attachname'])."'"); + if($db->fetch_field($query, "numreferences") == 0) + { + delete_uploaded_file($uploadpath."/".$attachment['attachname']); + if($attachment['thumbnail']) + { + delete_uploaded_file($uploadpath."/".$attachment['thumbnail']); + } + + $date_directory = explode('/', $attachment['attachname']); + if(@is_dir($uploadpath."/".$date_directory[0])) + { + delete_upload_directory($uploadpath."/".$date_directory[0]); + } + } + + if($attachment['visible'] == 1 && $pid) + { + $post = get_post($pid); + update_thread_counters($post['tid'], array("attachmentcount" => "-1")); + } +} + +/** + * Remove all of the attachments from a specific post + * + * @param int $pid The post ID + * @param string $posthash The posthash if available + */ +function remove_attachments($pid, $posthash="") +{ + global $db, $mybb, $plugins; + + if($pid) + { + $post = get_post($pid); + } + $posthash = $db->escape_string($posthash); + if($posthash != "" && !$pid) + { + $query = $db->simple_select("attachments", "*", "posthash='$posthash'"); + } + else + { + $query = $db->simple_select("attachments", "*", "pid='$pid'"); + } + + if(defined('IN_ADMINCP')) + { + $uploadpath = '../'.$mybb->settings['uploadspath']; + } + else + { + $uploadpath = $mybb->settings['uploadspath']; + } + + $num_attachments = 0; + while($attachment = $db->fetch_array($query)) + { + if($attachment['visible'] == 1) + { + $num_attachments++; + } + + $plugins->run_hooks("remove_attachments_do_delete", $attachment); + + $db->delete_query("attachments", "aid='".$attachment['aid']."'"); + + // Check if this attachment is referenced in any other posts. If it isn't, then we are safe to delete the actual file. + $query2 = $db->simple_select("attachments", "COUNT(aid) as numreferences", "attachname='".$db->escape_string($attachment['attachname'])."'"); + if($db->fetch_field($query2, "numreferences") == 0) + { + delete_uploaded_file($uploadpath."/".$attachment['attachname']); + if($attachment['thumbnail']) + { + delete_uploaded_file($uploadpath."/".$attachment['thumbnail']); + } + + $date_directory = explode('/', $attachment['attachname']); + if(@is_dir($uploadpath."/".$date_directory[0])) + { + delete_upload_directory($uploadpath."/".$date_directory[0]); + } + } + } + + if($post['tid']) + { + update_thread_counters($post['tid'], array("attachmentcount" => "-{$num_attachments}")); + } +} + +/** + * Remove any matching avatars for a specific user ID + * + * @param int $uid The user ID + * @param string $exclude A file name to be excluded from the removal + */ +function remove_avatars($uid, $exclude="") +{ + global $mybb, $plugins; + + if(defined('IN_ADMINCP')) + { + $avatarpath = '../'.$mybb->settings['avataruploadpath']; + } + else + { + $avatarpath = $mybb->settings['avataruploadpath']; + } + + $dir = opendir($avatarpath); + if($dir) + { + while($file = @readdir($dir)) + { + $plugins->run_hooks("remove_avatars_do_delete", $file); + + if(preg_match("#avatar_".$uid."\.#", $file) && is_file($avatarpath."/".$file) && $file != $exclude) + { + delete_uploaded_file($avatarpath."/".$file); + } + } + + @closedir($dir); + } +} + +/** + * Upload a new avatar in to the file system + * + * @param array $avatar Incoming FILE array, if we have one - otherwise takes $_FILES['avatarupload'] + * @param int $uid User ID this avatar is being uploaded for, if not the current user + * @return array Array of errors if any, otherwise filename of successful. + */ +function upload_avatar($avatar=array(), $uid=0) +{ + global $db, $mybb, $lang, $plugins, $cache; + + $ret = array(); + + if(!$uid) + { + $uid = $mybb->user['uid']; + } + + if(!$avatar['name'] || !$avatar['tmp_name']) + { + $avatar = $_FILES['avatarupload']; + } + + if(!is_uploaded_file($avatar['tmp_name'])) + { + $ret['error'] = $lang->error_uploadfailed; + return $ret; + } + + // Check we have a valid extension + // This is attached to the attachment types allowed to be uploaded (set in the ACP) + $valid_extensions = array(); + $extensions = $cache->read("attachtypes"); + + foreach($extensions as $ext => $type) + { + if(substr($type['mimetype'], 0, 5) == 'image') + { + $valid_extensions[$ext] = 1; + } + } + + $ext = get_extension(my_strtolower($avatar['name'])); + + if(!isset($valid_extensions[$ext])) + { + $ret['error'] = $lang->error_avatartype; + return $ret; + } + + if(defined('IN_ADMINCP')) + { + $avatarpath = '../'.$mybb->settings['avataruploadpath']; + $lang->load("messages", true); + } + else + { + $avatarpath = $mybb->settings['avataruploadpath']; + } + + $filename = "avatar_".$uid.".".$ext; + $file = upload_file($avatar, $avatarpath, $filename); + if($file['error']) + { + delete_uploaded_file($avatarpath."/".$filename); + $ret['error'] = $lang->error_uploadfailed; + return $ret; + } + + // Lets just double check that it exists + if(!file_exists($avatarpath."/".$filename)) + { + $ret['error'] = $lang->error_uploadfailed; + delete_uploaded_file($avatarpath."/".$filename); + return $ret; + } + + // Check if this is a valid image or not + $img_dimensions = @getimagesize($avatarpath."/".$filename); + if(!is_array($img_dimensions)) + { + delete_uploaded_file($avatarpath."/".$filename); + $ret['error'] = $lang->error_uploadfailed; + return $ret; + } + + // Check avatar dimensions + if($mybb->settings['maxavatardims'] != '') + { + list($maxwidth, $maxheight) = @explode("x", $mybb->settings['maxavatardims']); + if(($maxwidth && $img_dimensions[0] > $maxwidth) || ($maxheight && $img_dimensions[1] > $maxheight)) + { + // Automatic resizing enabled? + if($mybb->settings['avatarresizing'] == "auto" || ($mybb->settings['avatarresizing'] == "user" && $mybb->input['auto_resize'] == 1)) + { + require_once MYBB_ROOT."inc/functions_image.php"; + $thumbnail = generate_thumbnail($avatarpath."/".$filename, $avatarpath, $filename, $maxheight, $maxwidth); + if(!$thumbnail['filename']) + { + $ret['error'] = $lang->sprintf($lang->error_avatartoobig, $maxwidth, $maxheight); + $ret['error'] .= "

    ".$lang->error_avatarresizefailed; + delete_uploaded_file($avatarpath."/".$filename); + return $ret; + } + else + { + // Reset filesize + $avatar['size'] = filesize($avatarpath."/".$filename); + // Reset dimensions + $img_dimensions = @getimagesize($avatarpath."/".$filename); + } + } + else + { + $ret['error'] = $lang->sprintf($lang->error_avatartoobig, $maxwidth, $maxheight); + if($mybb->settings['avatarresizing'] == "user") + { + $ret['error'] .= "

    ".$lang->error_avataruserresize; + } + delete_uploaded_file($avatarpath."/".$filename); + return $ret; + } + } + } + + // Next check the file size + if($avatar['size'] > ($mybb->settings['avatarsize']*1024) && $mybb->settings['avatarsize'] > 0) + { + delete_uploaded_file($avatarpath."/".$filename); + $ret['error'] = $lang->error_uploadsize; + return $ret; + } + + // Check a list of known MIME types to establish what kind of avatar we're uploading + switch(my_strtolower($avatar['type'])) + { + case "image/gif": + $img_type = 1; + break; + case "image/jpeg": + case "image/x-jpg": + case "image/x-jpeg": + case "image/pjpeg": + case "image/jpg": + $img_type = 2; + break; + case "image/png": + case "image/x-png": + $img_type = 3; + break; + default: + $img_type = 0; + } + + // Check if the uploaded file type matches the correct image type (returned by getimagesize) + if($img_dimensions[2] != $img_type || $img_type == 0) + { + $ret['error'] = $lang->error_uploadfailed; + delete_uploaded_file($avatarpath."/".$filename); + return $ret; + } + // Everything is okay so lets delete old avatars for this user + remove_avatars($uid, $filename); + + $ret = array( + "avatar" => $mybb->settings['avataruploadpath']."/".$filename, + "width" => (int)$img_dimensions[0], + "height" => (int)$img_dimensions[1] + ); + $ret = $plugins->run_hooks("upload_avatar_end", $ret); + return $ret; +} + +/** + * Upload an attachment in to the file system + * + * @param array $attachment Attachment data (as fed by PHPs $_FILE) + * @param boolean $update_attachment Whether or not we are updating a current attachment or inserting a new one + * @return array Array of attachment data if successful, otherwise array of error data + */ +function upload_attachment($attachment, $update_attachment=false) +{ + global $mybb, $db, $theme, $templates, $posthash, $pid, $tid, $forum, $mybb, $lang, $plugins, $cache; + + $posthash = $db->escape_string($mybb->get_input('posthash')); + $pid = (int)$pid; + + if(isset($attachment['error']) && $attachment['error'] != 0) + { + $ret['error'] = $lang->error_uploadfailed.$lang->error_uploadfailed_detail; + switch($attachment['error']) + { + case 1: // UPLOAD_ERR_INI_SIZE + $ret['error'] .= $lang->error_uploadfailed_php1; + break; + case 2: // UPLOAD_ERR_FORM_SIZE + $ret['error'] .= $lang->error_uploadfailed_php2; + break; + case 3: // UPLOAD_ERR_PARTIAL + $ret['error'] .= $lang->error_uploadfailed_php3; + break; + case 4: // UPLOAD_ERR_NO_FILE + $ret['error'] .= $lang->error_uploadfailed_php4; + break; + case 6: // UPLOAD_ERR_NO_TMP_DIR + $ret['error'] .= $lang->error_uploadfailed_php6; + break; + case 7: // UPLOAD_ERR_CANT_WRITE + $ret['error'] .= $lang->error_uploadfailed_php7; + break; + default: + $ret['error'] .= $lang->sprintf($lang->error_uploadfailed_phpx, $attachment['error']); + break; + } + return $ret; + } + + if(!is_uploaded_file($attachment['tmp_name']) || empty($attachment['tmp_name'])) + { + $ret['error'] = $lang->error_uploadfailed.$lang->error_uploadfailed_php4; + return $ret; + } + + $attachtypes = $cache->read('attachtypes'); + $attachment = $plugins->run_hooks("upload_attachment_start", $attachment); + + $ext = get_extension($attachment['name']); + // Check if we have a valid extension + if(!isset($attachtypes[$ext])) + { + $ret['error'] = $lang->error_attachtype; + return $ret; + } + else + { + $attachtype = $attachtypes[$ext]; + } + + // Check the size + if($attachment['size'] > $attachtype['maxsize']*1024 && $attachtype['maxsize'] != "") + { + $ret['error'] = $lang->sprintf($lang->error_attachsize, $attachtype['maxsize']); + return $ret; + } + + // Double check attachment space usage + if($mybb->usergroup['attachquota'] > 0) + { + $query = $db->simple_select("attachments", "SUM(filesize) AS ausage", "uid='".$mybb->user['uid']."'"); + $usage = $db->fetch_array($query); + $usage = $usage['ausage']+$attachment['size']; + if($usage > ($mybb->usergroup['attachquota']*1024)) + { + $friendlyquota = get_friendly_size($mybb->usergroup['attachquota']*1024); + $ret['error'] = $lang->sprintf($lang->error_reachedattachquota, $friendlyquota); + return $ret; + } + } + + // Gather forum permissions + $forumpermissions = forum_permissions($forum['fid']); + + // Check if an attachment with this name is already in the post + if($pid != 0) + { + $uploaded_query = "pid='{$pid}'"; + } + else + { + $uploaded_query = "posthash='{$posthash}'"; + } + $query = $db->simple_select("attachments", "*", "filename='".$db->escape_string($attachment['name'])."' AND ".$uploaded_query); + $prevattach = $db->fetch_array($query); + if($prevattach['aid'] && $update_attachment == false) + { + if(!$mybb->usergroup['caneditattachments'] && !$forumpermissions['caneditattachments']) + { + $ret['error'] = $lang->error_alreadyuploaded_perm; + return $ret; + } + + $ret['error'] = $lang->error_alreadyuploaded; + return $ret; + } + + // Check to see how many attachments exist for this post already + if($mybb->settings['maxattachments'] > 0 && $update_attachment == false) + { + $query = $db->simple_select("attachments", "COUNT(aid) AS numattachs", $uploaded_query); + $attachcount = $db->fetch_field($query, "numattachs"); + if($attachcount >= $mybb->settings['maxattachments']) + { + $ret['error'] = $lang->sprintf($lang->error_maxattachpost, $mybb->settings['maxattachments']); + return $ret; + } + } + + $month_dir = ''; + if($mybb->safemode == false) + { + // Check if the attachment directory (YYYYMM) exists, if not, create it + $month_dir = gmdate("Ym"); + if(!@is_dir($mybb->settings['uploadspath']."/".$month_dir)) + { + @mkdir($mybb->settings['uploadspath']."/".$month_dir); + // Still doesn't exist - oh well, throw it in the main directory + if(!@is_dir($mybb->settings['uploadspath']."/".$month_dir)) + { + $month_dir = ''; + } + } + } + + // All seems to be good, lets move the attachment! + $filename = "post_".$mybb->user['uid']."_".TIME_NOW."_".md5(random_str()).".attach"; + + $file = upload_file($attachment, $mybb->settings['uploadspath']."/".$month_dir, $filename); + + // Failed to create the attachment in the monthly directory, just throw it in the main directory + if(!empty($file['error']) && $month_dir) + { + $file = upload_file($attachment, $mybb->settings['uploadspath'].'/', $filename); + } + elseif($month_dir) + { + $filename = $month_dir."/".$filename; + } + + if(!empty($file['error'])) + { + $ret['error'] = $lang->error_uploadfailed.$lang->error_uploadfailed_detail; + switch($file['error']) + { + case 1: + $ret['error'] .= $lang->error_uploadfailed_nothingtomove; + break; + case 2: + $ret['error'] .= $lang->error_uploadfailed_movefailed; + break; + } + return $ret; + } + + // Lets just double check that it exists + if(!file_exists($mybb->settings['uploadspath']."/".$filename)) + { + $ret['error'] = $lang->error_uploadfailed.$lang->error_uploadfailed_detail.$lang->error_uploadfailed_lost; + return $ret; + } + + // Generate the array for the insert_query + $attacharray = array( + "pid" => $pid, + "posthash" => $posthash, + "uid" => $mybb->user['uid'], + "filename" => $db->escape_string($file['original_filename']), + "filetype" => $db->escape_string($file['type']), + "filesize" => (int)$file['size'], + "attachname" => $filename, + "downloads" => 0, + "dateuploaded" => TIME_NOW + ); + + // If we're uploading an image, check the MIME type compared to the image type and attempt to generate a thumbnail + if($ext == "gif" || $ext == "png" || $ext == "jpg" || $ext == "jpeg" || $ext == "jpe") + { + // Check a list of known MIME types to establish what kind of image we're uploading + switch(my_strtolower($file['type'])) + { + case "image/gif": + $img_type = 1; + break; + case "image/jpeg": + case "image/x-jpg": + case "image/x-jpeg": + case "image/pjpeg": + case "image/jpg": + $img_type = 2; + break; + case "image/png": + case "image/x-png": + $img_type = 3; + break; + default: + $img_type = 0; + } + + $supported_mimes = array(); + foreach($attachtypes as $attachtype) + { + if(!empty($attachtype['mimetype'])) + { + $supported_mimes[] = $attachtype['mimetype']; + } + } + + // Check if the uploaded file type matches the correct image type (returned by getimagesize) + $img_dimensions = @getimagesize($mybb->settings['uploadspath']."/".$filename); + + $mime = ""; + $file_path = $mybb->settings['uploadspath']."/".$filename; + if(function_exists("finfo_open")) + { + $file_info = finfo_open(FILEINFO_MIME); + list($mime, ) = explode(';', finfo_file($file_info, MYBB_ROOT.$file_path), 1); + finfo_close($file_info); + } + else if(function_exists("mime_content_type")) + { + $mime = mime_content_type(MYBB_ROOT.$file_path); + } + + if(!is_array($img_dimensions) || ($img_dimensions[2] != $img_type && !in_array($mime, $supported_mimes))) + { + delete_uploaded_file($mybb->settings['uploadspath']."/".$filename); + $ret['error'] = $lang->error_uploadfailed; + return $ret; + } + require_once MYBB_ROOT."inc/functions_image.php"; + $thumbname = str_replace(".attach", "_thumb.$ext", $filename); + + $attacharray = $plugins->run_hooks("upload_attachment_thumb_start", $attacharray); + + $thumbnail = generate_thumbnail($mybb->settings['uploadspath']."/".$filename, $mybb->settings['uploadspath'], $thumbname, $mybb->settings['attachthumbh'], $mybb->settings['attachthumbw']); + + if($thumbnail['filename']) + { + $attacharray['thumbnail'] = $thumbnail['filename']; + } + elseif($thumbnail['code'] == 4) + { + $attacharray['thumbnail'] = "SMALL"; + } + } + if($forumpermissions['modattachments'] == 1 && !is_moderator($forum['fid'], "canapproveunapproveattachs")) + { + $attacharray['visible'] = 0; + } + else + { + $attacharray['visible'] = 1; + } + + $attacharray = $plugins->run_hooks("upload_attachment_do_insert", $attacharray); + + if($prevattach['aid'] && $update_attachment == true) + { + unset($attacharray['downloads']); // Keep our download count if we're updating an attachment + $db->update_query("attachments", $attacharray, "aid='".$db->escape_string($prevattach['aid'])."'"); + + // Remove old attachment file + // Check if this attachment is referenced in any other posts. If it isn't, then we are safe to delete the actual file. + $query = $db->simple_select("attachments", "COUNT(aid) as numreferences", "attachname='".$db->escape_string($prevattach['attachname'])."'"); + if($db->fetch_field($query, "numreferences") == 0) + { + delete_uploaded_file($mybb->settings['uploadspath']."/".$prevattach['attachname']); + if($prevattach['thumbnail']) + { + delete_uploaded_file($mybb->settings['uploadspath']."/".$prevattach['thumbnail']); + } + + $date_directory = explode('/', $prevattach['attachname']); + if(@is_dir($mybb->settings['uploadspath']."/".$date_directory[0])) + { + delete_upload_directory($mybb->settings['uploadspath']."/".$date_directory[0]); + } + } + + $aid = $prevattach['aid']; + } + else + { + $aid = $db->insert_query("attachments", $attacharray); + if($pid) + { + update_thread_counters($tid, array("attachmentcount" => "+1")); + } + } + $ret['aid'] = $aid; + return $ret; +} + +/** + * Delete an uploaded file both from the relative path and the CDN path if a CDN is in use. + * + * @param string $path The relative path to the uploaded file. + * + * @return bool Whether the file was deleted successfully. + */ +function delete_uploaded_file($path = '') +{ + global $mybb; + + $deleted = false; + + $deleted = @unlink($path); + + $cdn_base_path = rtrim($mybb->settings['cdnpath'], '/'); + $path = ltrim($path, '/'); + $cdn_path = realpath($cdn_base_path . '/' . $path); + + + if($mybb->settings['usecdn'] && !empty($cdn_base_path)) + { + $deleted = $deleted && @unlink($cdn_path); + } + + return $deleted; +} + +/** + * Delete an upload directory on both the local filesystem and the CDN filesystem. + * + * @param string $path The directory to delete. + * + * @return bool Whether the directory was deleted. + */ +function delete_upload_directory($path = '') +{ + global $mybb; + + $deleted = false; + + $deleted = @rmdir($path); + + $cdn_base_path = rtrim($mybb->settings['cdnpath'], '/'); + $path = ltrim($path, '/'); + $cdn_path = rtrim(realpath($cdn_base_path . '/' . $path), '/'); + + if($mybb->settings['usecdn'] && !empty($cdn_base_path)) + { + $deleted = $deleted && @rmdir($cdn_path); + } + + return $deleted; +} + +/** + * Actually move a file to the uploads directory + * + * @param array $file The PHP $_FILE array for the file + * @param string $path The path to save the file in + * @param string $filename The filename for the file (if blank, current is used) + * @return array The uploaded file + */ +function upload_file($file, $path, $filename="") +{ + global $plugins, $mybb; + + $upload = array(); + + if(empty($file['name']) || $file['name'] == "none" || $file['size'] < 1) + { + $upload['error'] = 1; + return $upload; + } + + if(!$filename) + { + $filename = $file['name']; + } + + $upload['original_filename'] = preg_replace("#/$#", "", $file['name']); // Make the filename safe + $filename = preg_replace("#/$#", "", $filename); // Make the filename safe + $moved = @move_uploaded_file($file['tmp_name'], $path."/".$filename); + + $moved_cdn = false; + $cdn_base_path = rtrim($mybb->settings['cdnpath'], '/'); + $cdn_path = rtrim(realpath($cdn_base_path . '/' . $path), '/'); + + if($mybb->settings['usecdn'] && !empty($cdn_base_path)) + { + $moved_cdn = @copy($path . '/' . $filename, $cdn_path . '/' . $filename); + @my_chmod($cdn_path . '/' . $filename, '0644'); + } + + if(!$moved) + { + $upload['error'] = 2; + return $upload; + } + @my_chmod($path."/".$filename, '0644'); + $upload['filename'] = $filename; + $upload['path'] = $path; + $upload['type'] = $file['type']; + $upload['size'] = $file['size']; + $upload = $plugins->run_hooks("upload_file_end", $upload); + + if($moved_cdn) + { + $upload['cdn_path'] = $cdn_path; + } + + return $upload; +} diff --git a/Upload/inc/functions_user.php b/Upload/inc/functions_user.php new file mode 100644 index 0000000..7907692 --- /dev/null +++ b/Upload/inc/functions_user.php @@ -0,0 +1,732 @@ +simple_select("users", "COUNT(*) as user", "uid='".(int)$uid."'", array('limit' => 1)); + if($db->fetch_field($query, 'user') == 1) + { + return true; + } + else + { + return false; + } +} + +/** + * Checks if $username already exists in the database. + * + * @param string The username for check for. + * @return boolean True when exists, false when not. + */ +function username_exists($username) +{ + global $db; + + $options = array( + 'username_method' => 2 + ); + + return (bool)get_user_by_username($username, $options); +} + +/** + * Checks a password with a supplied username. + * + * @param string The username of the user. + * @param string The plain-text password. + * @return boolean|array False when no match, array with user info when match. + */ +function validate_password_from_username($username, $password) +{ + global $db, $mybb; + + $options = array( + 'fields' => array('username', 'password', 'salt', 'loginkey', 'coppauser', 'usergroup'), + 'username_method' => $mybb->settings['username_method'], + ); + + $user = get_user_by_username($username, $options); + + if(!$user['uid']) + { + return false; + } + + return validate_password_from_uid($user['uid'], $password, $user); +} + +/** + * Checks a password with a supplied uid. + * + * @param int The user id. + * @param string The plain-text password. + * @param string An optional user data array. + * @return boolean|array False when not valid, user data array when valid. + */ +function validate_password_from_uid($uid, $password, $user = array()) +{ + global $db, $mybb; + if(isset($mybb->user['uid']) && $mybb->user['uid'] == $uid) + { + $user = $mybb->user; + } + if(!$user['password']) + { + $query = $db->simple_select("users", "uid,username,password,salt,loginkey,usergroup", "uid='".(int)$uid."'"); + $user = $db->fetch_array($query); + } + if(!$user['salt']) + { + // Generate a salt for this user and assume the password stored in db is a plain md5 password + $user['salt'] = generate_salt(); + $user['password'] = salt_password($user['password'], $user['salt']); + $sql_array = array( + "salt" => $user['salt'], + "password" => $user['password'] + ); + $db->update_query("users", $sql_array, "uid='".$user['uid']."'"); + } + + if(!$user['loginkey']) + { + $user['loginkey'] = generate_loginkey(); + $sql_array = array( + "loginkey" => $user['loginkey'] + ); + $db->update_query("users", $sql_array, "uid = ".$user['uid']); + } + if(salt_password(md5($password), $user['salt']) == $user['password']) + { + return $user; + } + else + { + return false; + } +} + +/** + * Updates a user's password. + * + * @param int The user's id. + * @param string The md5()'ed password. + * @param string (Optional) The salt of the user. + * @return array The new password. + */ +function update_password($uid, $password, $salt="") +{ + global $db, $plugins; + + $newpassword = array(); + + // If no salt was specified, check in database first, if still doesn't exist, create one + if(!$salt) + { + $query = $db->simple_select("users", "salt", "uid='$uid'"); + $user = $db->fetch_array($query); + if($user['salt']) + { + $salt = $user['salt']; + } + else + { + $salt = generate_salt(); + } + $newpassword['salt'] = $salt; + } + + // Create new password based on salt + $saltedpw = salt_password($password, $salt); + + // Generate new login key + $loginkey = generate_loginkey(); + + // Update password and login key in database + $newpassword['password'] = $saltedpw; + $newpassword['loginkey'] = $loginkey; + $db->update_query("users", $newpassword, "uid='$uid'"); + + $plugins->run_hooks("password_changed"); + + return $newpassword; +} + +/** + * Salts a password based on a supplied salt. + * + * @param string The md5()'ed password. + * @param string The salt. + * @return string The password hash. + */ +function salt_password($password, $salt) +{ + return md5(md5($salt).$password); +} + +/** + * Generates a random salt + * + * @return string The salt. + */ +function generate_salt() +{ + return random_str(8); +} + +/** + * Generates a 50 character random login key. + * + * @return string The login key. + */ +function generate_loginkey() +{ + return random_str(50); +} + +/** + * Updates a user's salt in the database (does not update a password). + * + * @param int The uid of the user to update. + * @return string The new salt. + */ +function update_salt($uid) +{ + global $db; + + $salt = generate_salt(); + $sql_array = array( + "salt" => $salt + ); + $db->update_query("users", $sql_array, "uid='{$uid}'"); + + return $salt; +} + +/** + * Generates a new login key for a user. + * + * @param int The uid of the user to update. + * @return string The new login key. + */ +function update_loginkey($uid) +{ + global $db; + + $loginkey = generate_loginkey(); + $sql_array = array( + "loginkey" => $loginkey + ); + $db->update_query("users", $sql_array, "uid='{$uid}'"); + + return $loginkey; + +} + +/** + * Adds a thread to a user's thread subscription list. + * If no uid is supplied, the currently logged in user's id will be used. + * + * @param int The tid of the thread to add to the list. + * @param int (Optional) The type of notification to receive for replies (0=none, 1=email, 2=pm) + * @param int (Optional) The uid of the user who's list to update. + * @return boolean True when success, false when otherwise. + */ +function add_subscribed_thread($tid, $notification=1, $uid="") +{ + global $mybb, $db; + + if(!$uid) + { + $uid = $mybb->user['uid']; + } + + if(!$uid) + { + return; + } + + $query = $db->simple_select("threadsubscriptions", "*", "tid='".(int)$tid."' AND uid='".(int)$uid."'"); + $subscription = $db->fetch_array($query); + if(!$subscription['tid']) + { + $insert_array = array( + 'uid' => (int)$uid, + 'tid' => (int)$tid, + 'notification' => (int)$notification, + 'dateline' => TIME_NOW, + 'subscriptionkey' => md5(TIME_NOW.$uid.$tid) + + ); + $db->insert_query("threadsubscriptions", $insert_array); + } + else + { + // Subscription exists - simply update notification + $update_array = array( + "notification" => (int)$notification + ); + $db->update_query("threadsubscriptions", $update_array, "uid='{$uid}' AND tid='{$tid}'"); + } + return true; +} + +/** + * Remove a thread from a user's thread subscription list. + * If no uid is supplied, the currently logged in user's id will be used. + * + * @param int The tid of the thread to remove from the list. + * @param int (Optional) The uid of the user who's list to update. + * @return boolean True when success, false when otherwise. + */ +function remove_subscribed_thread($tid, $uid="") +{ + global $mybb, $db; + + if(!$uid) + { + $uid = $mybb->user['uid']; + } + + if(!$uid) + { + return; + } + $db->delete_query("threadsubscriptions", "tid='".$tid."' AND uid='{$uid}'"); + + return true; +} + +/** + * Adds a forum to a user's forum subscription list. + * If no uid is supplied, the currently logged in user's id will be used. + * + * @param int The fid of the forum to add to the list. + * @param int (Optional) The uid of the user who's list to update. + * @return boolean True when success, false when otherwise. + */ +function add_subscribed_forum($fid, $uid="") +{ + global $mybb, $db; + + if(!$uid) + { + $uid = $mybb->user['uid']; + } + + if(!$uid) + { + return; + } + + $fid = (int)$fid; + $uid = (int)$uid; + + $query = $db->simple_select("forumsubscriptions", "*", "fid='".$fid."' AND uid='{$uid}'", array('limit' => 1)); + $fsubscription = $db->fetch_array($query); + if(!$fsubscription['fid']) + { + $insert_array = array( + 'fid' => $fid, + 'uid' => $uid + ); + $db->insert_query("forumsubscriptions", $insert_array); + } + + return true; +} + +/** + * Removes a forum from a user's forum subscription list. + * If no uid is supplied, the currently logged in user's id will be used. + * + * @param int The fid of the forum to remove from the list. + * @param int (Optional) The uid of the user who's list to update. + * @return boolean True when success, false when otherwise. + */ +function remove_subscribed_forum($fid, $uid="") +{ + global $mybb, $db; + + if(!$uid) + { + $uid = $mybb->user['uid']; + } + + if(!$uid) + { + return; + } + $db->delete_query("forumsubscriptions", "fid='".$fid."' AND uid='{$uid}'"); + + return true; +} + +/** + * Constructs the usercp navigation menu. + * + */ +function usercp_menu() +{ + global $mybb, $templates, $theme, $plugins, $lang, $usercpnav, $usercpmenu; + + $lang->load("usercpnav"); + + // Add the default items as plugins with separated priorities of 10 + if($mybb->settings['enablepms'] != 0) + { + $plugins->add_hook("usercp_menu", "usercp_menu_messenger", 10); + } + + $plugins->add_hook("usercp_menu", "usercp_menu_profile", 20); + $plugins->add_hook("usercp_menu", "usercp_menu_misc", 30); + + // Run the plugin hooks + $plugins->run_hooks("usercp_menu"); + global $usercpmenu; + + eval("\$usercpnav = \"".$templates->get("usercp_nav")."\";"); + + $plugins->run_hooks("usercp_menu_built"); +} + +/** + * Constructs the usercp messenger menu. + * + */ +function usercp_menu_messenger() +{ + global $db, $mybb, $templates, $theme, $usercpmenu, $lang, $collapsed, $collapsedimg; + + $usercp_nav_messenger = $templates->get("usercp_nav_messenger"); + // Hide tracking link if no permission + $tracking = ''; + if($mybb->usergroup['cantrackpms']) + { + $tracking = $templates->get("usercp_nav_messenger_tracking"); + } + eval("\$ucp_nav_tracking = \"". $tracking ."\";"); + + // Hide compose link if no permission + $ucp_nav_compose = ''; + if($mybb->usergroup['cansendpms'] == 1) + { + eval("\$ucp_nav_compose = \"".$templates->get("usercp_nav_messenger_compose")."\";"); + } + + $folderlinks = $folder_id = $folder_name = ''; + $foldersexploded = explode("$%%$", $mybb->user['pmfolders']); + foreach($foldersexploded as $key => $folders) + { + $folderinfo = explode("**", $folders, 2); + $folderinfo[1] = get_pm_folder_name($folderinfo[0], $folderinfo[1]); + if($folderinfo[0] == 4) + { + $class = "usercp_nav_trash_pmfolder"; + } + else if($folderlinks) + { + $class = "usercp_nav_sub_pmfolder"; + } + else + { + $class = "usercp_nav_pmfolder"; + } + + $folder_id = $folderinfo[0]; + $folder_name = $folderinfo[1]; + + eval("\$folderlinks .= \"".$templates->get("usercp_nav_messenger_folder")."\";"); + } + + if(!isset($collapsedimg['usercppms'])) + { + $collapsedimg['usercppms'] = ''; + } + + if(!isset($collapsed['usercppms_e'])) + { + $collapsed['usercppms_e'] = ''; + } + + eval("\$usercpmenu .= \"".$usercp_nav_messenger."\";"); +} + +/** + * Constructs the usercp profile menu. + * + */ +function usercp_menu_profile() +{ + global $db, $mybb, $templates, $theme, $usercpmenu, $lang, $collapsed, $collapsedimg; + + $changenameop = ''; + if($mybb->usergroup['canchangename'] != 0) + { + eval("\$changenameop = \"".$templates->get("usercp_nav_changename")."\";"); + } + + $changesigop = ''; + if($mybb->usergroup['canusesig'] == 1 && ($mybb->usergroup['canusesigxposts'] == 0 || $mybb->usergroup['canusesigxposts'] > 0 && $mybb->user['postnum'] > $mybb->usergroup['canusesigxposts'])) + { + if($mybb->user['suspendsignature'] == 0 || $mybb->user['suspendsignature'] == 1 && $mybb->user['suspendsigtime'] > 0 && $mybb->user['suspendsigtime'] < TIME_NOW) + { + eval("\$changesigop = \"".$templates->get("usercp_nav_editsignature")."\";"); + } + } + + if(!isset($collapsedimg['usercpprofile'])) + { + $collapsedimg['usercpprofile'] = ''; + } + + if(!isset($collapsed['usercpprofile_e'])) + { + $collapsed['usercpprofile_e'] = ''; + } + + eval("\$usercpmenu .= \"".$templates->get("usercp_nav_profile")."\";"); +} + +/** + * Constructs the usercp misc menu. + * + */ +function usercp_menu_misc() +{ + global $db, $mybb, $templates, $theme, $usercpmenu, $lang, $collapsed, $collapsedimg; + + $draftstart = $draftend = ''; + $draftcount = $lang->ucp_nav_drafts; + + $query = $db->simple_select("posts", "COUNT(pid) AS draftcount", "visible = '-2' AND uid = '{$mybb->user['uid']}'"); + $count = $db->fetch_field($query, 'draftcount'); + + if($count > 0) + { + $draftcount = $lang->sprintf($lang->ucp_nav_drafts_active, my_number_format($count)); + } + + if($mybb->settings['enableattachments'] != 0) + { + eval("\$attachmentop = \"".$templates->get("usercp_nav_attachments")."\";"); + } + + if(!isset($collapsedimg['usercpmisc'])) + { + $collapsedimg['usercpmisc'] = ''; + } + + if(!isset($collapsed['usercpmisc_e'])) + { + $collapsed['usercpmisc_e'] = ''; + } + + $profile_link = get_profile_link($mybb->user['uid']); + eval("\$usercpmenu .= \"".$templates->get("usercp_nav_misc")."\";"); +} + +/** + * Gets the usertitle for a specific uid. + * + * @param int The uid of the user to get the usertitle of. + * @return string The usertitle of the user. + */ +function get_usertitle($uid="") +{ + global $db, $mybb; + + if($mybb->user['uid'] == $uid) + { + $user = $mybb->user; + } + else + { + $query = $db->simple_select("users", "usertitle,postnum", "uid='$uid'", array('limit' => 1)); + $user = $db->fetch_array($query); + } + + if($user['usertitle']) + { + return $user['usertitle']; + } + else + { + $usertitles = $mybb->cache->read('usertitles'); + foreach($usertitles as $title) + { + if($title['posts'] <= $user['postnum']) + { + $usertitle = $title; + } + } + + return $usertitle['title']; + } +} + +/** + * Updates a users private message count in the users table with the number of pms they have. + * + * @param int The user id to update the count for. If none, assumes currently logged in user. + * @param int Bitwise value for what to update. 1 = total, 2 = new, 4 = unread. Combinations accepted. + * @param int The unix timestamp the user with uid last visited. If not specified, will be queried. + */ +function update_pm_count($uid=0, $count_to_update=7) +{ + global $db, $mybb; + + // If no user id, assume that we mean the current logged in user. + if((int)$uid == 0) + { + $uid = $mybb->user['uid']; + } + + $uid = (int)$uid; + $pmcount = array(); + if($uid == 0) + { + return $pmcount; + } + + // Update total number of messages. + if($count_to_update & 1) + { + $query = $db->simple_select("privatemessages", "COUNT(pmid) AS pms_total", "uid='".$uid."'"); + $total = $db->fetch_array($query); + $pmcount['totalpms'] = $total['pms_total']; + } + + // Update number of unread messages. + if($count_to_update & 2 && $db->field_exists("unreadpms", "users") == true) + { + $query = $db->simple_select("privatemessages", "COUNT(pmid) AS pms_unread", "uid='".$uid."' AND status='0' AND folder='1'"); + $unread = $db->fetch_array($query); + $pmcount['unreadpms'] = $unread['pms_unread']; + } + + if(!empty($pmcount)) + { + $db->update_query("users", $pmcount, "uid='".$uid."'"); + } + return $pmcount; +} + +/** + * Return the language specific name for a PM folder. + * + * @param int The ID of the folder. + * @param string The folder name - can be blank, will use language default. + * @return string The name of the folder. + */ +function get_pm_folder_name($fid, $name="") +{ + global $lang; + + if($name != '') + { + return $name; + } + + switch($fid) + { + case 1: + return $lang->folder_inbox; + break; + case 2: + return $lang->folder_sent_items; + break; + case 3: + return $lang->folder_drafts; + break; + case 4: + return $lang->folder_trash; + break; + default: + return $lang->folder_untitled; + } +} + +/** + * Generates a security question for registration. + * + * @return string The question session id. + */ +function generate_question() +{ + global $db; + + if($db->type == 'pgsql' || $db->type == 'sqlite') + { + $order_by = 'RANDOM()'; + } + else + { + $order_by = 'RAND()'; + } + + $query = $db->simple_select('questions', 'qid, shown', 'active=1', array('limit' => 1, 'order_by' => $order_by)); + $question = $db->fetch_array($query); + + if(!$db->num_rows($query)) + { + // No active questions exist + return false; + } + else + { + $sessionid = random_str(32); + + $sql_array = array( + "sid" => $sessionid, + "qid" => $question['qid'], + "dateline" => TIME_NOW + ); + $db->insert_query("questionsessions", $sql_array); + + $update_question = array( + "shown" => $question['shown'] + 1 + ); + $db->update_query("questions", $update_question, "qid = '{$question['qid']}'"); + + return $sessionid; + } +} + +/** + * Check whether we can show the Purge Spammer Feature + * + * @param int The users post count + * @param int The usergroup of our user + * @param int The uid of our user + * @return boolean Whether or not to show the feature + */ +function purgespammer_show($post_count, $usergroup, $uid) +{ + global $mybb, $cache; + + // only show this if the current user has permission to use it and the user has less than the post limit for using this tool + $bangroup = $mybb->settings['purgespammerbangroup']; + $usergroups = $cache->read('usergroups'); + + return ($mybb->user['uid'] != $uid && is_member($mybb->settings['purgespammergroups']) && !is_super_admin($uid) + && !$usergroups[$usergroup]['cancp'] && !$usergroups[$usergroup]['canmodcp'] && !$usergroups[$usergroup]['issupermod'] + && (str_replace($mybb->settings['thousandssep'], '', $post_count) <= $mybb->settings['purgespammerpostlimit'] || $mybb->settings['purgespammerpostlimit'] == 0) + && !is_member($bangroup, $uid) && !$usergroups[$usergroup]['isbannedgroup']); +} diff --git a/Upload/inc/functions_warnings.php b/Upload/inc/functions_warnings.php new file mode 100644 index 0000000..286f594 --- /dev/null +++ b/Upload/inc/functions_warnings.php @@ -0,0 +1,120 @@ + -1, // Ban + 2 => -1, // Revoke posting + 3 => -1 // Moderate posting + ); + $check_levels = array( + 1 => false, // Ban + 2 => false, // Revoke posting + 3 => false // Moderate posting + ); + while($warn_level = $db->fetch_array($query)) + { + // revoke actions taken at this warning level + $action = my_unserialize($warn_level['action']); + if($action['type'] < 1 || $action['type'] > 3) // prevent any freak-ish cases + { + continue; + } + + $check_levels[$action['type']] = true; + + $max_exp_time = &$max_expiration_times[$action['type']]; + if($action['length'] && $max_exp_time != 0) + { + $expiration = $action['length']; + if($expiration > $max_exp_time) + { + $max_exp_time = $expiration; + } + } + else + { + $max_exp_time = 0; + } + } +} + +/** + * Returns a friendly expiration time of a suspension/warning + * + * @param int The time period of the suspension/warning + * @return array An array of the time/period remaining + */ +function fetch_friendly_expiration($time) +{ + if($time == 0 || $time == -1) + { + return array("period" => "never"); + } + else if($time % 2592000 == 0) + { + return array("time" => $time/2592000, "period" => "months"); + } + else if($time % 604800 == 0) + { + return array("time" => $time/604800, "period" => "weeks"); + } + else if($time % 86400 == 0) + { + return array("time" => $time/86400, "period" => "days"); + } + else + { + return array("time" => ceil($time/3600), "period" => "hours"); + } +} + +/** + * Figures out the length of a suspension/warning + * + * @param int The amount of time to calculate the length of suspension/warning + * @param string The period of time to calculate the length of suspension/warning + * @return int Length of the suspension/warning (in seconds) + */ +function fetch_time_length($time, $period) +{ + $time = (int)$time; + + if($period == "hours") + { + $time = $time*3600; + } + else if($period == "days") + { + $time = $time*86400; + } + else if($period == "weeks") + { + $time = $time*604800; + } + else if($period == "months") + { + $time = $time*2592000; + } + else if($period == "never" && $time == 0) + { + // User is permanentely banned + $time = "-1"; + } + else + { + $time = 0; + } + return $time; +} diff --git a/Upload/inc/index.html b/Upload/inc/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/init.php b/Upload/inc/init.php new file mode 100644 index 0000000..8034277 --- /dev/null +++ b/Upload/inc/init.php @@ -0,0 +1,299 @@ +
    Please make sure IN_MYBB is defined."); +} + +/* Defines the root directory for MyBB. + + Uncomment the below line and set the path manually + if you experience problems. + + Always add a trailing slash to the end of the path. + + * Path to your copy of MyBB + */ +//define('MYBB_ROOT', "./"); + +// Attempt autodetection +if(!defined('MYBB_ROOT')) +{ + define('MYBB_ROOT', dirname(dirname(__FILE__))."/"); +} + +define("TIME_NOW", time()); + +if(function_exists('date_default_timezone_set') && !ini_get('date.timezone')) +{ + date_default_timezone_set('GMT'); +} + +require_once MYBB_ROOT."inc/class_error.php"; +$error_handler = new errorHandler(); + +if(!function_exists('json_encode') || !function_exists('json_decode')) +{ + require_once MYBB_ROOT.'inc/3rdparty/json/json.php'; +} + +require_once MYBB_ROOT."inc/functions.php"; + +require_once MYBB_ROOT."inc/class_timers.php"; +$maintimer = new timer(); + +require_once MYBB_ROOT."inc/class_core.php"; +$mybb = new MyBB; + +$not_installed = false; +if(!file_exists(MYBB_ROOT."inc/config.php")) +{ + $not_installed = true; +} +else +{ + // Include the required core files + require_once MYBB_ROOT."inc/config.php"; + $mybb->config = &$config; + + if(!isset($config['database'])) + { + $not_installed = true; + } +} + +if($not_installed !== false) +{ + if(file_exists(MYBB_ROOT."install/index.php")) + { + if(defined("IN_ARCHIVE") || defined("IN_ADMINCP")) + { + header("Location: ../install/index.php"); + exit; + } + header("Location: ./install/index.php"); + exit; + } + + $mybb->trigger_generic_error("board_not_installed"); +} + +if(!is_array($config['database'])) +{ + $mybb->trigger_generic_error("board_not_upgraded"); +} + +if(empty($config['admin_dir'])) +{ + $config['admin_dir'] = "admin"; +} + +// Trigger an error if the installation directory exists +if(is_dir(MYBB_ROOT."install") && !file_exists(MYBB_ROOT."install/lock")) +{ + $mybb->trigger_generic_error("install_directory"); +} + +require_once MYBB_ROOT."inc/db_".$config['database']['type'].".php"; + +switch($config['database']['type']) +{ + case "sqlite": + $db = new DB_SQLite; + break; + case "pgsql": + $db = new DB_PgSQL; + break; + case "mysqli": + $db = new DB_MySQLi; + break; + default: + $db = new DB_MySQL; +} + +// Check if our DB engine is loaded +if(!extension_loaded($db->engine)) +{ + // Throw our super awesome db loading error + $mybb->trigger_generic_error("sql_load_error"); +} + +require_once MYBB_ROOT."inc/class_templates.php"; +$templates = new templates; + +require_once MYBB_ROOT."inc/class_datacache.php"; +$cache = new datacache; + +require_once MYBB_ROOT."inc/class_plugins.php"; +$plugins = new pluginSystem; + +// Include our base data handler class +require_once MYBB_ROOT."inc/datahandler.php"; + +// Connect to Database +define("TABLE_PREFIX", $config['database']['table_prefix']); +$db->connect($config['database']); +$db->set_table_prefix(TABLE_PREFIX); +$db->type = $config['database']['type']; + +// Language initialisation +require_once MYBB_ROOT."inc/class_language.php"; +$lang = new MyLanguage; +$lang->set_path(MYBB_ROOT."inc/languages"); + +// Load cache +$cache->cache(); + +// Load Settings +if(file_exists(MYBB_ROOT."inc/settings.php")) +{ + require_once MYBB_ROOT."inc/settings.php"; +} + +if(!file_exists(MYBB_ROOT."inc/settings.php") || empty($settings)) +{ + if(function_exists('rebuild_settings')) + { + rebuild_settings(); + } + else + { + $options = array( + "order_by" => "title", + "order_dir" => "ASC" + ); + + $query = $db->simple_select("settings", "value, name", "", $options); + + $settings = array(); + while($setting = $db->fetch_array($query)) + { + $setting['value'] = str_replace("\"", "\\\"", $setting['value']); + $settings[$setting['name']] = $setting['value']; + } + $db->free_result($query); + } +} + +$settings['wolcutoff'] = $settings['wolcutoffmins']*60; +$settings['bbname_orig'] = $settings['bbname']; +$settings['bbname'] = strip_tags($settings['bbname']); +$settings['orig_bblanguage'] = $settings['bblanguage']; + +// Fix for people who for some specify a trailing slash on the board URL +if(substr($settings['bburl'], -1) == "/") +{ + $settings['bburl'] = my_substr($settings['bburl'], 0, -1); +} + +// Setup our internal settings and load our encryption key +$settings['internal'] = $cache->read("internal_settings"); +if(!$settings['internal']['encryption_key']) +{ + $cache->update("internal_settings", array('encryption_key' => random_str(32))); + $settings['internal'] = $cache->read("internal_settings"); +} + +$mybb->settings = &$settings; +$mybb->parse_cookies(); +$mybb->cache = &$cache; +$mybb->asset_url = $mybb->get_asset_url(); + +if($mybb->use_shutdown == true) +{ + register_shutdown_function('run_shutdown'); +} + +// Did we just upgrade to a new version and haven't run the upgrade scripts yet? +$version = $cache->read("version"); +if(!defined("IN_INSTALL") && !defined("IN_UPGRADE") && $version['version_code'] < $mybb->version_code) +{ + $version_history = $cache->read("version_history"); + if(empty($version_history) || file_exists(MYBB_ROOT."install/resources/upgrade".(int)(end($version_history)+1).".php")) + { + $mybb->trigger_generic_error("board_not_upgraded"); + } +} + +// Load plugins +if(!defined("NO_PLUGINS") && !($mybb->settings['no_plugins'] == 1)) +{ + $plugins->load(); +} + +// Set up any shutdown functions we need to run globally +add_shutdown('send_mail_queue'); + +/* URL Definitions */ +if($mybb->settings['seourls'] == "yes" || ($mybb->settings['seourls'] == "auto" && isset($_SERVER['SEO_SUPPORT']) && $_SERVER['SEO_SUPPORT'] == 1)) +{ + $mybb->seo_support = true; + + define('FORUM_URL', "dzial-{fid}.html"); + define('FORUM_URL_PAGED', "dzial-{fid}-strona-{page}.html"); + define('THREAD_URL', "watek-{tid}.html"); + define('THREAD_URL_PAGED', "watek-{tid}-strona-{page}.html"); + define('THREAD_URL_ACTION', 'watek-{tid}-{action}.html'); + define('THREAD_URL_POST', 'watek-{tid}-post-{pid}.html'); + define('POST_URL', "post-{pid}.html"); + define('PROFILE_URL', "uzytkownik-{uid}.html"); + define('ANNOUNCEMENT_URL', "ogloszenie-{aid}.html"); + define('CALENDAR_URL', "kalendarz-{calendar}.html"); + define('CALENDAR_URL_MONTH', 'kalendarz-{calendar}-rok-{year}-miesiac-{month}.html'); + define('CALENDAR_URL_DAY', 'kalendarz-{calendar}-rok-{year}-miesiac-{month}-dzien-{day}.html'); + define('CALENDAR_URL_WEEK', 'kalendarz-{calendar}-tydzien-{week}.html'); + define('EVENT_URL', "wydarzenie-{eid}.html"); +} +else +{ + define('FORUM_URL', "forumdisplay.php?fid={fid}"); + define('FORUM_URL_PAGED', "forumdisplay.php?fid={fid}&page={page}"); + define('THREAD_URL', "showthread.php?tid={tid}"); + define('THREAD_URL_PAGED', "showthread.php?tid={tid}&page={page}"); + define('THREAD_URL_ACTION', 'showthread.php?tid={tid}&action={action}'); + define('THREAD_URL_POST', 'showthread.php?tid={tid}&pid={pid}'); + define('POST_URL', "showthread.php?pid={pid}"); + define('PROFILE_URL', "member.php?action=profile&uid={uid}"); + define('ANNOUNCEMENT_URL', "announcements.php?aid={aid}"); + define('CALENDAR_URL', "calendar.php?calendar={calendar}"); + define('CALENDAR_URL_MONTH', "calendar.php?calendar={calendar}&year={year}&month={month}"); + define('CALENDAR_URL_DAY', 'calendar.php?action=dayview&calendar={calendar}&year={year}&month={month}&day={day}'); + define('CALENDAR_URL_WEEK', 'calendar.php?action=weekview&calendar={calendar}&week={week}'); + define('EVENT_URL', "calendar.php?action=event&eid={eid}"); +} +define('INDEX_URL', "index.php"); + +// An array of valid date formats (Used for user selections etc) +$date_formats = array( + 1 => "m-d-Y", + 2 => "m-d-y", + 3 => "m.d.Y", + 4 => "m.d.y", + 5 => "d-m-Y", + 6 => "d-m-y", + 7 => "d.m.Y", + 8 => "d.m.y", + 9 => "F jS, Y", + 10 => "l, F jS, Y", + 11 => "jS F, Y", + 12 => "l, jS F, Y", + // ISO 8601 + 13 => "Y-m-d" +); + +// An array of valid time formats (Used for user selections etc) +$time_formats = array( + 1 => "h:i a", + 2 => "h:i A", + 3 => "H:i" +); + diff --git a/Upload/inc/languages/index.html b/Upload/inc/languages/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/languages/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/languages/polish.php b/Upload/inc/languages/polish.php new file mode 100644 index 0000000..954c49a --- /dev/null +++ b/Upload/inc/languages/polish.php @@ -0,0 +1,31 @@ + on all pages +$langinfo['htmllang'] = "pl"; + +// Sets the character set, blank uses the default. +$langinfo['charset'] = "UTF-8"; \ No newline at end of file diff --git a/Upload/inc/languages/polish/admin/config_attachment_types.lang.php b/Upload/inc/languages/polish/admin/config_attachment_types.lang.php new file mode 100644 index 0000000..11d7249 --- /dev/null +++ b/Upload/inc/languages/polish/admin/config_attachment_types.lang.php @@ -0,0 +1,44 @@ +Pokaż listÄ™ dostÄ™pnych typów
    )"; +$l['maximum_file_size'] = "Maksymalny rozmiar pliku (w kilobajtach)"; +$l['maximum_file_size_desc'] = "Maksymalny rozmiar pliku jaki można załadować dla tego rozszerzenia, rozmiar podaj w kilobajtach (1 MB = 1024 KB)"; +$l['limit_intro'] = "Upewnij się, że rozmiar pliku jest mniejszy niż ustalony w konfiguracji PHP:"; +$l['limit_post_max_size'] = "Maksymalny rozmiar posta: {1}"; +$l['limit_upload_max_filesize'] = "Maksymalny rozmiar załącznika: {1}"; +$l['attachment_icon'] = "Ikona załącznika"; +$l['attachment_icon_desc'] = "Jeżeli chcesz, by przy załącznikach tego typu pokazywała się ikonka, podaj tutaj jej ścieżkę. \"{theme}\" zostanie zastąpione przez adres katalogu z obrazkami aktualnie używanego stylu."; +$l['save_attachment_type'] = "Zapisz typ załączników"; + +$l['error_invalid_attachment_type'] = "Wybrano niepoprawny typ załącznika."; +$l['error_missing_mime_type'] = "Nie podano typu MIME dla tego rodzaju plików"; +$l['error_missing_extension'] = "Nie podano rozszerzenia dla tego rodzaju plików"; + +$l['success_attachment_type_created'] = "Typ załączników został utworzony."; +$l['success_attachment_type_updated'] = "Typ załączników został zaktualizowany."; +$l['success_attachment_type_deleted'] = "Typ załączników został usunięty."; + +$l['confirm_attachment_type_deletion'] = "Czy na pewno chcesz usunąć ten typ załączników?"; diff --git a/Upload/inc/languages/polish/admin/config_badwords.lang.php b/Upload/inc/languages/polish/admin/config_badwords.lang.php new file mode 100644 index 0000000..a413b20 --- /dev/null +++ b/Upload/inc/languages/polish/admin/config_badwords.lang.php @@ -0,0 +1,35 @@ +{subject} reprezentuje oryginalny temat, a {username} reprezentuje login moderatora."; + +$l['success_mod_tool_created'] = "Narzędzie moderacji zostało utworzone."; +$l['success_mod_tool_updated'] = "Narzędzie moderacji zostało zaktualizowane."; + +$l['inline_post_moderation'] = "Liniowa moderacja postów"; +$l['delete_posts'] = "Usunąć posty?"; +$l['merge_posts'] = "Połączyć posty?"; +$l['merge_posts_desc'] = "Używane tylko z moderacji liniowej."; +$l['approve_unapprove_posts'] = "Akceptować | Odrzucić post(y)?"; +$l['softdelete_restore_posts'] = "Usunąć nietrwale/przywrócić posty?"; + +$l['split_posts'] = "Oddziel posty"; +$l['split_posts2'] = "Oddzielić posty?"; +$l['do_not_split'] = "Nie oddzielaj postów"; +$l['split_to_same_forum'] = "Oddziel i pozostaw w tym dziale"; +$l['close_split_thread'] = "Zamknąć oddzielony wątek?"; +$l['stick_split_thread'] = "Przypiąć oddzielony wątek?"; +$l['unapprove_split_thread'] = "Odrzucić oddzielony wątek?"; +$l['split_thread_prefix'] = "Prefiks oddzielonego wątku"; +$l['split_thread_subject'] = "Temat oddzielonego wątku"; +$l['split_thread_subject_desc'] = "{subject} reprezentuje oryginalny temat. Wymagane tylko podczas oddzielania postów."; +$l['add_new_split_reply'] = "Napisz odpowiedź do łączonego wątku"; +$l['add_new_split_reply_desc'] = "Pozostaw puste, jeżeli nie chcesz udzielać odpowiedzi."; +$l['split_reply_subject'] = "Temat odpowiedzi"; +$l['split_reply_subject_desc'] = "Używane tylko gdy pozostawiasz odpowiedź"; +$l['save_post_tool'] = "Zapisz narzędzie postów"; + +$l['send_private_message'] = 'Wyślij prywatną wiadomość'; +$l['private_message_message'] = 'Wiadomość'; +$l['private_message_message_desc'] = 'Wiadomość do autora wątku. Pozostaw puste, żeby wyłączyć tę funkcję.'; +$l['private_message_subject'] = 'Temat'; +$l['private_message_subject_desc'] = 'Wpisz temat prywatnej wiadomości.'; + +$l['error_missing_title'] = "Wpisz nazwę dla tego narzędzia."; +$l['error_missing_description'] = "Krótko opisz to narzędzie."; +$l['error_no_forums_selected'] = "Wybierz działy, w których będzie dostępne to narzędzie."; +$l['error_no_groups_selected'] = "Wybierz grupy, dla których będzie dostępne to narzędzie."; +$l['error_forum_is_category'] = "Nie można wybrać kategorii jako działu docelowego."; diff --git a/Upload/inc/languages/polish/admin/config_module_meta.lang.php b/Upload/inc/languages/polish/admin/config_module_meta.lang.php new file mode 100644 index 0000000..ba0e151 --- /dev/null +++ b/Upload/inc/languages/polish/admin/config_module_meta.lang.php @@ -0,0 +1,45 @@ +inc/plugins na Twoim forum. Aby nie pokazywać plugina na liście, ale nie utracić żadnych zapisanych przez niego informacji, kliknij na przycisk Dezaktywuj."; +$l['plugin_updates'] = "Aktualizacje pluginów"; +$l['plugin_updates_desc'] = "Sprawdź czy istnieją aktualizacje pluginów zainstalowanych na Twoim forum."; +$l['browse_plugins'] = "Przeglądaj pluginy"; +$l['browse_plugins_desc'] = "Przeglądaj oficjalną stronę MyBB w poszukiwaniu modyfikacji i pluginów kompatybilnych z tą wersją MyBB."; +$l['browse_all_plugins'] = "Przeglądaj wszystkie pluginy"; + +$l['plugin'] = "Plugin"; +$l['active_plugin'] = "Aktywne pluginy"; +$l['inactive_plugin'] = "Nieaktywne pluginy"; +$l['your_version'] = "Posiadana wersja"; +$l['latest_version'] = "Najnowsza wersja"; +$l['download'] = "Pobierz"; +$l['deactivate'] = "Dezaktywuj"; +$l['activate'] = "Aktywuj"; +$l['install_and_activate'] = "Zainstaluj i aktywuj"; +$l['uninstall'] = "Odinstaluj"; +$l['created_by'] = "Autor"; +$l['no_plugins'] = "W tym momencie nie ma żadnych pluginów na Twoim forum."; +$l['no_active_plugins'] = "W tym momencie nie ma żadnych aktywnych pluginów na Twoim forum."; +$l['no_inactive_plugins'] = "W tym momencie nie ma żadnych nieaktywnych pluginów na Twoim forum."; + +$l['plugin_incompatible'] = "Ten plugin jest niekompatybilny z MyBB {1}"; + +$l['recommended_plugins_for_mybb'] = "Zalecane pluginy dla MyBB {1}"; +$l['browse_results_for_mybb'] = "Przeglądaj wyniki dla MyBB {1}"; +$l['search_for_plugins'] = "Szukaj pluginów"; +$l['search'] = "Szukaj"; + +$l['error_vcheck_no_supported_plugins'] = "Żadne z zainstalowanych pluginów nie obsługują sprawdzania wersji."; +$l['error_vcheck_communications_problem'] = "Wystąpił problem z komunikacją z serwerem dodatków. Spróbuj ponownie za kilka minut."; +$l['error_vcheck_vulnerable'] = "[Plugin podatny na ataki]:"; +$l['error_vcheck_vulnerable_notes'] = "Ten plugin został oznaczony przez Ekipę MyBB jako podatny na ataki. Zalecamy jego kompletne usunięcie. Więcej informacji:"; +$l['error_no_input'] = "Kod błędu 1: nie wybrano wejścia."; +$l['error_no_pids'] = "Kod błędu 2: nie wybrano ID."; +$l['error_communication_problem'] = "Wystąpił problem z komunikacją z serwerem dodatków. Spróbuj ponownie za kilka minut."; +$l['error_invalid_plugin'] = "Wybrany plugin nie istnieje"; +$l['error_no_results_found'] = "Wyszukiwanie z podanymi słowami kluczowymi nie zwróciło żadnych wyników."; + +$l['success_plugins_up_to_date'] = "Wszystkie zainstalowane pluginy są w swoich najnowszych wersjach."; +$l['success_plugin_activated'] = "Plugin został aktywowany."; +$l['success_plugin_deactivated'] = "Plugin został zdezaktywowany."; +$l['success_plugin_installed'] = "Plugin został zainstalowany i aktywowany."; +$l['success_plugin_uninstalled'] = "Plugin został odinstalowany."; diff --git a/Upload/inc/languages/polish/admin/config_post_icons.lang.php b/Upload/inc/languages/polish/admin/config_post_icons.lang.php new file mode 100644 index 0000000..20047df --- /dev/null +++ b/Upload/inc/languages/polish/admin/config_post_icons.lang.php @@ -0,0 +1,47 @@ +{theme}. W jego miejsce podstawiony zostanie katalog z obrazkami danego stylu."; +$l['save_post_icon'] = "Zapisz ikonkę postów"; +$l['reset'] = "Resetuj"; + +$l['path_to_images'] = "Ścieżka do obrazków"; +$l['path_to_images_desc'] = "To jest ścieżka do folderu, gdzie są obrazki."; +$l['show_post_icons'] = "Pokaż ikonki postów"; +$l['image'] = "Obrazek"; +$l['add'] = "Dodać?"; +$l['save_post_icons'] = "Zapisz ikonki postów"; + +$l['no_post_icons'] = "W tym momencie nie ma ikonek postów na Twoim forum."; + +$l['error_missing_name'] = "Nie wpisano nazwy dla tej ikonki postów"; +$l['error_missing_path'] = "Nie wpisano ścieżki do tej ikony postów"; +$l['error_missing_path_multiple'] = "Nie wpisano ścieżki"; +$l['error_invalid_path'] = "Nie wpisano poprawnej ścieżki"; +$l['error_no_images'] = "Nie ma ikon postów w podanym katalogu, lub wszystkie ikony w tym folderze zostały już dodane."; +$l['error_none_included'] = "Nie wybrano żadnych ikonek postów do załączenia."; +$l['error_invalid_post_icon'] = "Wybrana ikonka postów nie istnieje."; + +$l['success_post_icon_added'] = "Ikona postów została dodana."; +$l['success_post_icons_added'] = "Wybrane ikony postów zostały dodane."; +$l['success_post_icon_updated'] = "Ikona postów została zaktualizowana."; +$l['success_post_icon_deleted'] = "Wybrana ikona postów została usunięta."; + +$l['confirm_post_icon_deletion'] = "Czy na pewno chcesz usunąć tę ikonę postów?"; diff --git a/Upload/inc/languages/polish/admin/config_profile_fields.lang.php b/Upload/inc/languages/polish/admin/config_profile_fields.lang.php new file mode 100644 index 0000000..3558607 --- /dev/null +++ b/Upload/inc/languages/polish/admin/config_profile_fields.lang.php @@ -0,0 +1,77 @@ + +Przykład: ([a-z0-9_\- ,.+]+)"; +$l['selectable_options'] = "Wybieralne opcje?"; +$l['selectable_options_desc'] = "Wpisz każdą opcję w oddzielnej linii. Tyczy się to tylko do pól wyboru, pól zaznaczania i przycisków radio."; +$l['required'] = "Wymagane?"; +$l['required_desc'] = "Czy jest wymagane, aby to pole zostało uzupełnione podczas rejestracji lub edycji profilu? Zauważ, że to nie ma zastosowania, jeżeli pole jest ukryte lub jego edycja została zablokowana."; +$l['show_on_registration'] = "Pokazywać podczas rejestracji?"; +$l['show_on_registration_desc'] = "Czy pole powinno być widoczne w formularzu rejestracyjnym? To ustawienie nie ma zastosowania, jeśli edycja pola została zablokowana. Ponadto, pola oznaczone jako wymagane zawsze będą wyświetlane w formularzu rejestracyjnym."; +$l['display_on_profile'] = "Pokazywać w profilu użytkownika?"; +$l['display_on_profile_desc'] = "Czy zawartość tego pola powinna być wyświetlana w profilu użytkownika? To ustawienie nie ma zastosowania do administratorów i moderatorów."; + +$l['display_on_postbit'] = "Wyświetlać w opisie posta?"; +$l['display_on_postbit_desc'] = "Czy to pole powinno być wyświetlane w opisie posta? To ustawienie nie zadziała, jeśli to pole jest ukryte lub jest polem tekstowym."; +$l['viewableby'] = 'Widoczne dla'; +$l['viewableby_desc'] = 'Wybierz grupy użytkowników, które mogą wyświetlać zawartość tego pola..'; +$l['editableby'] = 'Edytowalne przez'; +$l['editableby_desc'] = 'Wybierz grupy użytkowników, które mogą edytować to pole.'; +$l['min_posts_enabled'] = "Dostępne tylko dla użytkowników z określoną liczbą postów?"; +$l['min_posts_enabled_desc'] = "Czy to pole może być edytowane przez użytkownika, który posiada określoną minimalną liczbę postów? Jeżeli tak, wpisz ją w pole poniżej."; +$l['parser_options'] = "Ustawienia parsowania"; +$l['parse_allowhtml'] = "Zezwalaj na kod HTML."; +$l['parse_allowmycode'] = "Zezwalaj na kod MyCode."; +$l['parse_allowsmilies'] = "Zezwalaj na emotikony."; +$l['parse_allowimgcode'] = "Zezwól na tag [img]."; +$l['parse_allowvideocode'] = "Zezwól na tag [video]."; +$l['save_profile_field'] = "Zapisz pole profilu"; +$l['name'] = "Nazwa"; +$l['registration'] = "Widoczne podczas rejestracji?"; +$l['editable'] = "Edytowalne?"; +$l['profile'] = "Widoczne w profilu?"; +$l['postbit'] = "W opisie posta?"; +$l['edit_field'] = "Edytuj pole"; +$l['delete_field'] = "Usuń pole"; +$l['no_profile_fields'] = "W tym momencie nie ma dodatkowych pól w profilu na Twoim forum."; + +$l['error_missing_name'] = "Nie wpisano tytułu dla tego dodatkowego pola w profilu"; +$l['error_missing_description'] = "Nie wpisano opisu dla tego dodatkowego pola w profilu"; +$l['error_invalid_fid'] = "Wybrane pole w profilu nie istnieje."; + +$l['success_profile_field_added'] = "Dodatkowe pole w profilu zostało utworzone."; +$l['success_profile_field_saved'] = "Dodatkowe pole w profilu zostało zapisane."; +$l['success_profile_field_deleted'] = "Dodatkowe pole w profilu zostało usunięte."; + +$l['confirm_profile_field_deletion'] = "Czy na pewno chcesz usunąć to dodatkowe pole w profilu?"; diff --git a/Upload/inc/languages/polish/admin/config_questions.lang.php b/Upload/inc/languages/polish/admin/config_questions.lang.php new file mode 100644 index 0000000..f660ef5 --- /dev/null +++ b/Upload/inc/languages/polish/admin/config_questions.lang.php @@ -0,0 +1,41 @@ +Aby uzyskać więcej informacji na temat nadawania uprawnień CHMOD, sprawdź href=\"http://docs.mybb.com/HowTo_Chmod.html\" target=\"_blank\">Dokumentację MyBB."; +$l['error_hidden_captcha_conflict'] = "Wartość ukrytego pola CAPTCHA nie może być równa \"{1}\", ponieważ koliduje z innym polem rejestracji."; + +$l['success_setting_added'] = "Wpis ustawień został utworzony."; +$l['success_setting_updated'] = "Wpis ustawień został zaktualizowany."; +$l['success_setting_deleted'] = "Wpis ustawień został usunięty."; +$l['success_settings_updated'] = "Wpisy ustawień zostały zaktualizowane."; +$l['success_display_orders_updated'] = "Kolejność wyświetlania została zaktualizowana."; +$l['success_setting_group_added'] = "Grupa ustawień została utworzona."; +$l['success_setting_group_updated'] = "Grupa ustawień została zaktualizowana."; +$l['success_setting_group_deleted'] = "Grupa ustawień została usunięta."; +$l['success_duplicate_settings_deleted'] = "Wszystkie zduplikowane grupy ustawień zostały usunięte."; + +$l['searching'] = 'Wyszukiwanie...'; +$l['search_error'] = 'Wystąpił błąd podczas zwracania wyników wyszukiwania:'; +$l['search_done'] = 'Zrobione!'; + +/** Tłumaczenie nazw grup i ustawień **/ + +$l['setting_group_onlineoffline'] = "Forum zamknięte / otwarte"; +$l['setting_group_onlineoffline_desc'] = "Ustawienia dotyczące zamykania i otwierania forum (z możliwością podania powodu)."; +$l['setting_group_details'] = "Ustawienia strony"; +$l['setting_group_details_desc'] = "Ustawienia strony, m.in. nazwa i adres forum, a także nazwa i adres głównej strony serwisu."; +$l['setting_group_general'] = "Ustawienia ogólne"; +$l['setting_group_general_desc'] = "Ustawienia ogólne dotyczące podstawowych funkcjonalności forum."; +$l['setting_group_server'] = "Ustawienia serwera i optymalizacji"; +$l['setting_group_server_desc'] = "Ustawienia związane z użytkowaniem serwera przez skrypt (ich dostosowanie pozwala na zmniejszenie obciążenie serwera i osiągnięcie lepszej wydajności skryptu)."; +$l['setting_group_datetime'] = "Formaty daty i czasu"; +$l['setting_group_datetime_desc'] = "Ustawienia formatu wyświetlania daty i czasu na forum."; +$l['setting_group_forumhome'] = "Opcje strony głównej"; +$l['setting_group_forumhome_desc'] = "Ustawienia związane ze stroną główną forum (index.php)."; +$l['setting_group_forumdisplay'] = "Opcje wyświetlania działów"; +$l['setting_group_forumdisplay_desc'] = "Ustawienia dotyczące wyświetlania działów forum (forumdisplay.php)."; +$l['setting_group_showthread'] = "Opcje wyświetlania wątków"; +$l['setting_group_showthread_desc'] = "Ustawienia dotyczące wyświetlania wątków (showthread.php)."; +$l['setting_group_member'] = "Opcje rejestracji i profilu"; +$l['setting_group_member_desc'] = "Ustawienia dotyczące rejestracji użytkowników i zarządzania ich profilami."; +$l['setting_group_posting'] = "Pisanie postów"; +$l['setting_group_posting_desc'] = "Ustawienia związane z procesem pisania postów na forum."; +$l['setting_group_memberlist'] = "Lista użytkowników"; +$l['setting_group_memberlist_desc'] = "Ustawienia dotyczące strony z listą użytkowników forum (memberlist.php), (m.in. liczba użytkowników pokazywanych na pojedynczej stronie i ilość szczegółowych informacji)."; +$l['setting_group_reputation'] = "Reputacja"; +$l['setting_group_reputation_desc'] = "System reputacji pozwala użytkownikom na wzajemne ocenianie się i komentowanie swoich profili. W tej sekcji masz możliwość wyłączenia i zmiany ustawień strony reputacji (reputation.php)."; +$l['setting_group_showteam'] = "Ustawienia strony \"Ekipa forum\""; +$l['setting_group_showteam_desc'] = "Ustawienia dotyczące strony \"Ekipa forum\" (showteam.php)."; +$l['setting_group_privatemessaging'] = "Prywatne wiadomości"; +$l['setting_group_privatemessaging_desc'] = "Ustawienia dotyczące prywatnych wiadomości (private.php), m.in. możliwość używania HTML, MyCode, emotikonów, czy też kodu [img]."; +$l['setting_group_calendar'] = "Kalendarz"; +$l['setting_group_calendar_desc'] = "Ustawienia dotyczące kalendarza (kalendarz na forum zawiera przypomnienia o wydarzeniach, zarówno prywatnych, jak i publicznych, a także o urodzinach użytkowników)."; +$l['setting_group_whosonline'] = "Kto jest online"; +$l['setting_group_whosonline_desc'] = "Ustawienia związane z wyświetlaniem strony \"Kto jest online\"."; +$l['setting_group_userpruning'] = "Automatyczne usuwanie użytkowników"; +$l['setting_group_userpruning_desc'] = "Automatyczne usuwanie użytkowników pozwala na usunięcie z forum użytkowników, którzy spełniają podane kryteria. Tutaj możesz je dostosować."; +$l['setting_group_portal'] = "Ustawienia portalu"; +$l['setting_group_portal_desc'] = "Strona portalu zawiera skondensowane informacje o Twoim forum, m.in. ostatnie posty, listę \"Kto jest online\", statystyki, ogłoszenia i inne. W tej sekcji możesz zmienić jej ustawienia (portal.php)."; +$l['setting_group_search'] = "System wyszukiwania"; +$l['setting_group_search_desc'] = "Ustawienia dotyczące wbudowanego w MyBB systemu wyszukiwania wątków i postów."; +$l['setting_group_clickablecode'] = "Podręczna lista emotikonów i edytor MyCode"; +$l['setting_group_clickablecode_desc'] = "Ustawienia dotyczące podręcznej listy emotikonów i edytora MyCode podczas redagowania posta."; +$l['setting_group_cpprefs'] = "Preferencje panelu administratora (globalnie)"; +$l['setting_group_cpprefs_desc'] = "Globalne ustawienia dotyczące panelu administratora."; +$l['setting_group_contactsettings'] = "Formularz kontaktowy"; +$l['setting_group_contactsettings_desc'] = "Ustawienia dotyczące formularzu kontaktowego (contact.php)."; +$l['setting_group_purgespammer'] = "Usuwanie spamerów"; +$l['setting_group_purgespammer_desc'] = "W tej sekcji masz możliwość zarządzania wbudowanym systemem usuwania spamerów."; +$l['setting_group_stopforumspam'] = "Stop Forum Spam"; +$l['setting_group_stopforumspam_desc'] = "W tej sekcji masz możliwość zarządzania ustawieniami odpowiedzialnymi za integrację forum ze stroną StopForumSpam.com."; +$l['setting_group_contactdetails'] = "Dane kontaktowe"; +$l['setting_group_contactdetails_desc'] = "Ustawienia pól z danymi kontaktowymi w profilu użytkownika."; +$l['setting_group_statspage'] = "Strona statystyk"; +$l['setting_group_statspage_desc'] = "Ustawienia strony ze statystykami forum."; + +$l['setting_boardclosed'] = "Forum zamknięte"; +$l['setting_boardclosed_desc'] = "Możesz tutaj zamknąć swoje forum, np. celem przeprowadzenia jakichś prac (aktualizacji itp.). Użytkownicy nie będą mogli przeglądać forum, zobaczą jedynie informację o powodzie zamknięcia, który podasz poniżej.

    Administratorzy będą nadal mogli przeglądać forum."; +$l['setting_boardclosed_reason'] = "Powód zamknięcia forum"; +$l['setting_boardclosed_reason_desc'] = "Jeżeli zamykasz forum, możesz podać tutaj informację, którą zobaczą użytkownicy."; +$l['setting_bbname'] = "Nazwa forum"; +$l['setting_bbname_desc'] = "Nazwa forum dyskusyjnego. Nie powinna być dłuższa niż 75 znaków."; +$l['setting_bburl'] = "URL forum"; +$l['setting_bburl_desc'] = "Adres URL forum.
    DoÅ‚Ä…cz \"http://\". NIE DOÅÄ„CZAJ ukoÅ›nika na koÅ„cu."; +$l['setting_homename'] = "Nazwa głównej strony serwisu"; +$l['setting_homename_desc'] = "Nazwa głównej strony serwisu. BÄ™dzie wyÅ›wietlana jako link w stopce forum."; +$l['setting_homeurl'] = "URL strony głównej serwisu"; +$l['setting_homeurl_desc'] = "PeÅ‚en adres URL strony głównej serwisu. Pod ten adres bÄ™dzie prowadziÅ‚ link w stopce."; +$l['setting_adminemail'] = "Adres e-mail administratora"; +$l['setting_adminemail_desc'] = "Adres e-mail administratora. BÄ™dzie używany do sygnowania e-maili wysyÅ‚anych za poÅ›rednictwem forum."; +$l['setting_contactlink'] = "Link \"Kontakt\""; +$l['setting_contactlink_desc'] = "Adres, pod który bÄ™dzie prowadziÅ‚ link \"Kontakt\" w stopce forum. Może to być adres e-mail (w formacie mailto:adres@domena.com) albo adres URL."; +$l['setting_bblanguage'] = "DomyÅ›lny jÄ™zyk"; +$l['setting_bblanguage_desc'] = "JÄ™zyk, w jakim domyÅ›lnie ma być wyÅ›wietlany interfejs MyBB dla goÅ›ci oraz użytkowników, którzy nie dokonali wyboru jÄ™zyka w swoim panelu użytkownika."; +$l['setting_cookiedomain'] = "Domena cookies"; +$l['setting_cookiedomain_desc'] = "Domena, na jakÄ… zostanÄ… ustawione cookies. To pole może pozostać puste. Jeżeli chcesz, by wÅ‚Ä…czone zostaÅ‚y tutaj wszystkie subdomeny - wpisz kropkÄ™ na poczÄ…tku adresu."; +$l['setting_cookiepath'] = "Åšcieżka cookies"; +$l['setting_cookiepath_desc'] = "Åšcieżka, na jakÄ… zostanÄ… ustawione cookies. Zalecane jest wpisanie tutaj peÅ‚nej Å›cieżki do forum, wÅ‚Ä…cznie z ukoÅ›nikiem na koÅ„cu."; +$l['setting_showvernum'] = "Pokaż numer wersji"; +$l['setting_showvernum_desc'] = "Możesz wÅ‚Ä…czyć lub wyÅ‚Ä…czyć pokazywanie numeru wersji aktualnie zainstalowanej kopii MyBB."; +$l['setting_captchaimage'] = "Obrazki CAPTCHA przy rejestracji i postowaniu"; +$l['setting_captchaimage_desc'] = "Jeżeli wybierzesz \"tak\" oraz zainstalowana jest biblioteka GD, podczas rejestracji i podczas pisania posta wyÅ›wietlany bÄ™dzie obrazek. ObowiÄ…zkiem użytkowników bÄ™dzie przepisanie ciÄ…gu znaków z niego do pola tekstowego. Pomoże to w ograniczeniu liczby zautomatyzowanych rejestracji i wiadomoÅ›ci wysyÅ‚anych przez boty."; +$l['setting_reportmethod'] = "Sposób raportowania postów"; +$l['setting_reportmethod_desc'] = "Wybierz z listy obok sposób, w jaki majÄ… być przechowywane informacje o raportowanych postach. Najprawdopodobniej najlepszym wyborem bÄ™dzie przechowywanie informacji w bazie danych."; +$l['setting_statslimit'] = "Liczba wÄ…tków w statystykach"; +$l['setting_statslimit_desc'] = "Liczba wÄ…tków, jakie majÄ… pojawiać siÄ™ na stronie statystyk w zestawieniach wÄ…tków o najwiÄ™kszej liczbie odpowiedzi i wyÅ›wietleÅ„."; +$l['setting_decpoint'] = "Separator dziesiÄ™tny"; +$l['setting_decpoint_desc'] = "Separator dziesiÄ™tny używany w Twoim regionie. W jÄ™zyku polskim jest to przecinek: \",\"."; +$l['setting_thousandssep'] = "Separator tysiÄ™cy"; +$l['setting_thousandssep_desc'] = "Znak, którego chcesz używać do oddzielania trzycyfrowych grup w zapisie liczb. W Polsce najczęściej używa siÄ™ spacji \" \" lub kropki \".\"."; +$l['setting_gzipoutput'] = "Używać kompresji GZip?"; +$l['setting_gzipoutput_desc'] = "Czy chcesz, by strony byÅ‚y wysyÅ‚ane do przeglÄ…darki w formacie skompresowanym GZip? DziÄ™ki temu strony bÄ™dÄ… Å‚adować siÄ™ szybciej, z wykorzystaniem mniejszej iloÅ›ci transferu."; +$l['setting_gziplevel'] = "StopieÅ„ kompresji GZip"; +$l['setting_gziplevel_desc'] = "Wybierz stopieÅ„ kompresji GZip w skali od 0 do 9 (0=brak kompresji, 9=maksymalna kompresja). Ta opcja bÄ™dzie miaÅ‚a znaczenie tylko w przypadku, gdy kompresja GZip jest wÅ‚Ä…czona oraz na serwerze zainstalowane jest PHP w wersji co najmniej 4.2. Jeżeli używasz starszej wersji PHP, użyty zostanie domyÅ›lny stopieÅ„ kompresji."; +$l['setting_standardheaders'] = "WysyÅ‚ać standardowe nagłówki?"; +$l['setting_standardheaders_desc'] = "Na niektórych serwerach wÅ‚Ä…czenie tej opcji może powodować problemy - na innych z kolei jest konieczne."; +$l['setting_nocacheheaders'] = "WysyÅ‚ać nagłówki \"no-cache\"?"; +$l['setting_nocacheheaders_desc'] = "WÅ‚Ä…czenie tej opcji zapobiegnie tworzeniu kopii forum w pamiÄ™ci podrÄ™cznej przeglÄ…darek."; +$l['setting_redirects'] = "Przyjazne użytkownikowi strony przekierowaÅ„"; +$l['setting_redirects_desc'] = "WÅ‚Ä…czenie tej opcji spowoduje wyÅ›wietlanie przyjaznych użytkownikowi stron o treÅ›ci \"Teraz nastÄ…pi przeniesienie...\" przed bezpoÅ›rednim przekierowaniem."; +$l['setting_load'] = "Limit obciążenia serwera *NIX"; +$l['setting_load_desc'] = "Limit obciążenia serwera (server load), powyżej którego MyBB zacznie odrzucać poÅ‚Ä…czenia. Wpisz 0, by nie nakÅ‚adać ograniczenia. Zalecana wartość to 5.0."; +$l['setting_tplhtmlcomments'] = "Wypisywać komentarze na poczÄ…tku / koÅ„cu szablonów?"; +$l['setting_tplhtmlcomments_desc'] = "WÅ‚Ä…czenie tej opcji spowoduje wypisywanie komentarzy HTML przed szablonami i po nich."; +$l['setting_useshutdownfunc'] = "Użyj funkcji shutdown w PHP"; +$l['setting_useshutdownfunc_desc'] = "W wiÄ™kszoÅ›ci przypadków powinno siÄ™ zostawić tutaj domyÅ›lnÄ… wartość. Jeżeli napotkasz problemy z aktualizowaniem tagów meta, wybierz \"nie\"."; +$l['setting_extraadmininfo'] = "Zaawansowane statystyki i dane debugowania"; +$l['setting_extraadmininfo_desc'] = "Zdecyduj, czy administratorzy majÄ… widzieć informacjÄ™ o obciążeniu serwera, czasie parsowania i generowania strony, kompresji GZip itd. u doÅ‚u strony."; +$l['setting_uploadspath'] = "Åšcieżka do plików wysyÅ‚anych na serwer"; +$l['setting_uploadspath_desc'] = "Åšcieżka, do której wysyÅ‚ane bÄ™dÄ… pliki przyjÄ™te od użytkowników. Na serwerach *NIX ten katalog musi posiadać CHMOD 777."; +$l['setting_enableforumjump'] = "WyÅ›wietlać menu \"Skocz do...\"?"; +$l['setting_enableforumjump_desc'] = "Menu \"Skocz do...\" jest wyÅ›wietlane na stronach widoku działów i wÄ…tków. Jeżeli masz sporo działów, może powodować poważne obciążenie serwera. Wybierz \"nie\", by je wyÅ‚Ä…czyć."; +$l['setting_dateformat'] = "Format daty"; +$l['setting_dateformat_desc'] = "Format, w jakim wyÅ›wietlane bÄ™dÄ… daty na forum. Format ten korzysta ze skÅ‚adni funkcji date() w PHP - nie zmieniaj go, jeÅ›li jej nie znasz."; +$l['setting_timeformat'] = "Format czasu"; +$l['setting_timeformat_desc'] = "Format, w jakim wyÅ›wietlane bÄ™dÄ… godziny na forum. Format ten korzysta ze skÅ‚adni funkcji date() w PHP - nie zmieniaj go, jeÅ›li jej nie znasz."; +$l['setting_regdateformat'] = "Format daty rejestracji"; +$l['setting_regdateformat_desc'] = "Format, w jakim wyÅ›wietlane bÄ™dÄ… daty rejestracji użytkowników na forum. Format ten korzysta ze skÅ‚adni funkcji date() w PHP - nie zmieniaj go, jeÅ›li jej nie znasz."; +$l['setting_timezoneoffset'] = "DomyÅ›lna strefa czasowa"; +$l['setting_timezoneoffset_desc'] = "Możesz tutaj wybrać domyÅ›lnÄ… strefÄ™ czasowÄ… - dla goÅ›ci oraz tych użytkowników, którzy używajÄ… domyÅ›lnych ustawieÅ„ strefy czasowej."; +$l['setting_dstcorrection'] = "Czas letni"; +$l['setting_dstcorrection_desc'] = "Jeżeli pomimo dobrze dobranej strefy czasowej, różnica w czasie miÄ™dzy czasem ustawionym na forum a pożądanym wynosi jednÄ… godzinÄ™ - wÅ‚Ä…cz czas letni."; +$l['setting_showdescriptions'] = "Pokazywać opisy działów?"; +$l['setting_showdescriptions_desc'] = "Możesz ukryć opisy działów na swoim forum."; +$l['setting_subforumsindex'] = "Liczba poddziałów wyÅ›wietlanych na stronie głównej"; +$l['setting_subforumsindex_desc'] = "Liczba poddziałów, które chcesz wyÅ›wietlać na stronie głównej i stronie wyÅ›wietlania dziaÅ‚u. Wpisz 0 by nie wyÅ›wietlać listy poddziałów."; +$l['setting_subforumsstatusicons'] = "Pokazywać ikony statusu poddziałów?"; +$l['setting_subforumsstatusicons_desc'] = "Czy przy poddziaÅ‚ach majÄ… być pokazywane ikony informujÄ…ce o istnieniu nieprzeczytanych postów w danym poddziale?"; +$l['setting_hideprivateforums'] = "Ukryć dziaÅ‚y prywatne?"; +$l['setting_hideprivateforums_desc'] = "WÅ‚Ä…czajÄ…c tÄ™ opcjÄ™ możesz ukryć na stronie głównej i na liÅ›cie \"Skocz do...\" dziaÅ‚y prywatne i wszystkie ich poddziaÅ‚y."; +$l['setting_modlist'] = "WyÅ›wietlanie list moderatorów działów"; +$l['setting_modlist_desc'] = "Możesz wÅ‚Ä…czyć lub wyÅ‚Ä…czyć funkcjÄ™ wyÅ›wietlania list moderatorów przy opisach działów na stronie głównej oraz stronie wyÅ›wietlania dziaÅ‚u."; +$l['setting_showbirthdays'] = "Pokazywać dzisiejsze urodziny?"; +$l['setting_showbirthdays_desc'] = "Czy chcesz, by na stronie głównej wyÅ›wietlana byÅ‚a lista dzisiejszych urodzin?"; +$l['setting_showwol'] = "Pokazywać \"Kto jest online\"?"; +$l['setting_showwol_desc'] = "Czy chcesz, by na stronie głównej byÅ‚a wyÅ›wietlana lista aktywnych w danym momencie użytkowników?"; +$l['setting_showindexstats'] = "Pokazywać sekcjÄ™ statystyk?"; +$l['setting_showindexstats_desc'] = "Czy chcesz, by na stronie głównej wyÅ›wietlana byÅ‚a liczba wÄ…tków, postów, zarejestrowanych użytkowników oraz login ostatnio zarejestrowanego użytkownika?"; +$l['setting_threadsperpage'] = "Liczba wÄ…tków na stronÄ™"; +$l['setting_threadsperpage_desc'] = "Liczba wÄ…tków do wyÅ›wietlenia na jednej stronie."; +$l['setting_hottopic'] = "Wymagana liczba odpowiedzi dla \"Popularnego wÄ…tku\""; +$l['setting_hottopic_desc'] = "Liczba odpowiedzi, po przekroczeniu której wÄ…tek zostanie uznany za \"popularny\"."; +$l['setting_hottopicviews'] = "Wymagana liczba wyÅ›wietleÅ„ dla \"Popularnego wÄ…tku\""; +$l['setting_hottopicviews_desc'] = "Liczba wyÅ›wietleÅ„, po przekroczeniu której wÄ…tek zostanie uznany za \"popularny\"."; +$l['setting_usertppoptions'] = "Liczba wÄ…tków na stronÄ™ - opcje dla użytkowników"; +$l['setting_usertppoptions_desc'] = "Jeżeli chcesz, by użytkownicy w swoich panelach użytkowników mogli wybrać, ile wÄ…tków chcÄ… widzieć na jednej stronie - wpisz dostÄ™pne dla nich opcje, oddzielajÄ…c je przecinkami. Jeżeli pozostawisz to pole puste, użytkownicy nie bÄ™dÄ… mogli wybrać liczby wÄ…tków na stronÄ™."; +$l['setting_dotfolders'] = "Użyj ikon \"z kropkÄ…\""; +$l['setting_dotfolders_desc'] = "Czy chcesz, by ikony wÄ…tków, w których dany użytkownik braÅ‚ udziaÅ‚, byÅ‚y wyróżnione?"; +$l['setting_browsingthisforum'] = "Użytkownicy przeglÄ…dajÄ…cy ten dziaÅ‚"; +$l['setting_browsingthisforum_desc'] = "Możesz tutaj wyÅ‚Ä…czyć opcjÄ™ wyÅ›wietlania listy \"Użytkowników przeglÄ…dajÄ…cych ten dziaÅ‚\"."; +$l['setting_announcementlimit'] = "Limit ogÅ‚oszeÅ„"; +$l['setting_announcementlimit_desc'] = "Liczba ogÅ‚oszeÅ„, które majÄ… być wyÅ›wietlane na liÅ›cie wÄ…tków. Wpisz 0 by wyÅ‚Ä…czyć limit."; +$l['setting_postsperpage'] = "Liczba postów na stronÄ™"; +$l['setting_postsperpage_desc'] = "Liczba postów, jakie bÄ™dÄ… wyÅ›wietlane na pojedynczej stronie. Nie jest zalecana wartość wiÄ™ksza niż 20."; +$l['setting_userpppoptions'] = "Liczba postów na stronÄ™ - opcje dla użytkowników"; +$l['setting_userpppoptions_desc'] = "Jeżeli chcesz, by użytkownicy w swoich panelach użytkowników mogli wybrać, ile postów chcÄ… widzieć na jednej stronie - wpisz dostÄ™pne dla nich opcje, oddzielajÄ…c je przecinkami. Jeżeli pozostawisz to pole puste, użytkownicy nie bÄ™dÄ… mogli wybrać liczby postów na stronÄ™."; +$l['setting_threadreadcut'] = "Okres przechowywania informacji o przeczytanych wÄ…tkach"; +$l['setting_threadreadcut_desc'] = "Liczba dni przechowywania informacji o wÄ…tkach przeczytanych przez użytkownika. Na dużych forach wysoka wartość może powodować problemy z wydajnoÅ›ciÄ…. Wpisz 0, by nie ustalać limitu."; +$l['setting_threadusenetstyle'] = "WyÅ›wietlanie wÄ…tków w stylu grupy dyskusyjnej"; +$l['setting_threadusenetstyle_desc'] = "Wybierz \"tak\" jeżeli chcesz, by wÄ…tki byÅ‚y wyÅ›wietlane w formie podobnej do grup dyskusyjnych."; +$l['setting_quickreply'] = "WyÅ›wietlanie formularza szybkiej odpowiedzi"; +$l['setting_quickreply_desc'] = "Możesz tutaj wyÅ‚Ä…czyć opcjÄ™ wyÅ›wietlania formularza \"szybkiej odpowiedzi\" u doÅ‚u strony wÄ…tku."; +$l['setting_multiquote'] = "WyÅ›wietlanie przycisków szybkiego cytowania"; +$l['setting_multiquote_desc'] = "Przyciski szybkiego cytowania pozwalajÄ… na wybranie kilku postów, jakie chcÄ… jednoczeÅ›nie zacytować w swojej odpowiedzi."; +$l['setting_showsimilarthreads'] = "Pokazywać tabelÄ™ \"Podobne wÄ…tki\"?"; +$l['setting_showsimilarthreads_desc'] = "Tabela \"Podobne wÄ…tki\" przedstawia listÄ™ wÄ…tków podobnych do aktualnie przeglÄ…danego. Możesz poniżej wybrać stopieÅ„ podobieÅ„stwa."; +$l['setting_browsingthisthread'] = "Użytkownicy przeglÄ…dajÄ…cy ten wÄ…tek"; +$l['setting_browsingthisthread_desc'] = "Możesz tutaj wyÅ‚Ä…czyć opcjÄ™ wyÅ›wietlania listy \"Użytkowników przeglÄ…dajÄ…cych ten wÄ…tek\"."; + +$l['setting_similarityrating'] = "StopieÅ„ podobieÅ„stwa \"Podobnych wÄ…tków\""; +$l['setting_similarityrating_desc'] = "Możesz tutaj ustalić limit stopnia podobieÅ„stwa, który bÄ™dzie decydowaÅ‚ o wyÅ›wietlaniu wÄ…tków na liÅ›cie \"Podobnych wÄ…tków\". Liczba ta nie powinna być wiÄ™ksza niż 10, a dla dużych forów nie powinna być mniejsza niż 5."; +$l['setting_similarlimit'] = "Limit liczby \"Podobnych wÄ…tków\"."; +$l['setting_similarlimit_desc'] = "Możesz tutaj ustalić maksymalnÄ… liczbÄ™ wÄ…tków wyÅ›wietlanych na liÅ›cie \"Podobnych wÄ…tków\". Liczba ta nie powinna przekroczyć 15 na każde 56 tys. użytkowników."; +$l['setting_disableregs'] = "Zablokować rejestracje?"; +$l['setting_disableregs_desc'] = "Możesz tutaj caÅ‚kowicie wyÅ‚Ä…czyć możliwość rejestracji na swoim forum."; +$l['setting_regtype'] = "Metoda aktywacji"; +$l['setting_regtype_desc'] = "Wybierz metodÄ™, jaka ma być zastosowana do aktywacji użytkowników na forum."; +$l['setting_minnamelength'] = "Minimalna dÅ‚ugość loginu"; +$l['setting_minnamelength_desc'] = "Minimalna liczba znaków w loginie."; +$l['setting_maxnamelength'] = "Maksymalna dÅ‚ugość loginu"; +$l['setting_maxnamelength_desc'] = "Maksymalna liczba znaków w loginie."; +$l['setting_minpasswordlength'] = "Minimalna dÅ‚ugość hasÅ‚a"; +$l['setting_minpasswordlength_desc'] = "Minimalna liczba znaków w haÅ›le użytkownika."; +$l['setting_requirecomplexpasswords'] = "Wymagać skomplikowanych haseÅ‚?"; +$l['setting_requirecomplexpasswords_desc'] = "Czy chcesz, by od użytkowników byÅ‚o wymagane użycie skomplikowanego hasÅ‚a?"; +$l['setting_maxpasswordlength'] = "Maksymalna dÅ‚ugość hasÅ‚a"; +$l['setting_maxpasswordlength_desc'] = "Maksymalna liczba znaków w haÅ›le użytkownika."; +$l['setting_customtitlemaxlength'] = "Maksymalna dÅ‚ugość wÅ‚asnego tytuÅ‚u użytkownika"; +$l['setting_customtitlemaxlength_desc'] = "Maksymalna liczba znaków we wÅ‚asnym tytule użytkownika."; +$l['setting_betweenregstime'] = "Czas pomiÄ™dzy rejestracjami"; +$l['setting_betweenregstime_desc'] = "Czas (w godzinach), jaki musi upÅ‚ynąć pomiÄ™dzy dwoma rejestracjami z tego samego adresu IP."; +$l['setting_maxregsbetweentime'] = "Maksymalna liczba rejestracji na jeden adres IP"; +$l['setting_failedcaptchalogincount'] = "Maksymalna liczba nieudanych prób logowania przed weryfikacjÄ…"; +$l['setting_failedcaptchalogincount_desc'] = "Podaj po ilu nieudanych próbach zalogowania użytkownik bÄ™dzie musiaÅ‚ przepisać kod CAPTCHA. Wpisz 0, aby wyÅ‚Ä…czyć ograniczenie."; +$l['setting_maxregsbetweentime_desc'] = "Ta opcja pozwala na ustawienie maksymalnej liczby rejestracji, jakie użytkownicy mogÄ… wykonać przy użyciu jednego adresu IP."; +$l['setting_failedlogincount'] = "Maksymalna liczba nieudanych prób logowania"; +$l['setting_failedlogincount_desc'] = "Maksymalna liczba nieudanych prób zalogowania. Wpisz 0, by nie ustalać takiego ograniczenia."; +$l['setting_failedlogintime'] = "Czas pomiÄ™dzy nieudanymi próbami zalogowania"; +$l['setting_failedlogintime_desc'] = "Czas (w minutach) jaki trzeba bÄ™dzie odczekać przed ponownÄ… próbÄ… zalogowania po wykorzystaniu powyższego limitu."; +$l['setting_failedlogintext'] = "WyÅ›wietlać liczbÄ™ nieudanych prób logowania?"; +$l['setting_failedlogintext_desc'] = "Czy chcesz, by po nieudanej próbie logowania wyÅ›wietlana byÅ‚a informacja o liczbie pozostaÅ‚ych prób?"; +$l['setting_usereferrals'] = "Używać systemu polecajÄ…cych?"; +$l['setting_usereferrals_desc'] = "Czy chcesz, by na forum byÅ‚ używany system osób polecajÄ…cych?"; +$l['setting_sigmycode'] = "WÅ‚Ä…czyć myCode w sygnaturkach?"; +$l['setting_sigmycode_desc'] = "Czy chcesz, by użytkownicy mogli używać myCode w sygnaturkach?"; +$l['setting_maxsigimages'] = "Maksymalna liczba obrazków w sygnaturze"; +$l['setting_maxsigimages_desc'] = "Podaj maksymalnÄ… liczbÄ™ obrazków (w tym emotikonów), jakie bÄ™dzie można wstawić w sygnaturce. Wpisz 0, by caÅ‚kowicie zabronić wstawiania obrazków."; +$l['setting_sigsmilies'] = "WÅ‚Ä…czyć emotikony w sygnaturach?"; +$l['setting_sigsmilies_desc'] = "Czy chcesz, by użytkownicy w sygnaturach mogli używać emotikonów?"; +$l['setting_sightml'] = "WÅ‚Ä…czyć HTML w sygnaturach?"; +$l['setting_sightml_desc'] = "Czy chcesz, by użytkownicy w sygnaturach mogli używać kodu HTML?"; +$l['setting_sigimgcode'] = "WÅ‚Ä…czyć tag [img] w sygnaturach?"; +$l['setting_sigimgcode_desc'] = "Czy chcesz, by użytkownicy w sygnaturach mogli używać tagu [img]?"; +$l['setting_siglength'] = "Limit dÅ‚ugoÅ›ci sygnatury"; +$l['setting_siglength_desc'] = "Maksymalna liczba znaków w sygnaturze."; +$l['setting_sigcountmycode'] = "Czy zaliczać myCode do dÅ‚ugoÅ›ci sygnatury?"; +$l['setting_sigcountmycode_desc'] = "Czy chcesz, by myCode byÅ‚ wliczany do dÅ‚ugoÅ›ci sygnatury?"; +$l['setting_maxavatardims'] = "Maksymalne wymiary awatara"; +$l['setting_maxavatardims_desc'] = "Maksymalne wymiary, jakie może posiadać awatar, w formacie szerokośćxwysokość. Jeżeli to pole pozostanie puste - na wymiary awatara nie bÄ™dzie naÅ‚ożone żadne ograniczenie."; +$l['setting_avatarsize'] = "Maksymalny rozmiar wysyÅ‚anego na serwer awatara"; +$l['setting_avatarsize_desc'] = "Maksymalny rozmiar pliku (w kilobajtach) z wysyÅ‚anym na serwer awatarem."; +$l['setting_avatardir'] = "Katalog awatarów"; +$l['setting_avatardir_desc'] = "Åšcieżka do katalogu, w którym przechowywane sÄ… domyÅ›lne awatary. SÄ… one wyÅ›wietlane na liÅ›cie awatarów w panelu użytkownika."; +$l['setting_avataruploadpath'] = "Katalog wysyÅ‚anych na serwer awatarów"; +$l['setting_avataruploadpath_desc'] = "Åšcieżka do katalogu, w którym przechowywane sÄ… awatary wysyÅ‚ane na serwer. Ten katalog musi posiadać CHMOD 777, żeby awatary mogÅ‚y być przyjmowane od użytkowników."; +$l['setting_emailkeep'] = "Utrzymywanie adresu e-mail"; +$l['setting_emailkeep_desc'] = "Jeżeli użytkownik zarejestrowaÅ‚ siÄ™ na dany adres e-mail przed decyzjÄ… o zbanowaniu tego adresu, to czy może pozostać przy swoim dotychczasowym adresie?"; +$l['setting_minmessagelength'] = "Minimalna dÅ‚ugość posta"; +$l['setting_minmessagelength_desc'] = "Minimalna liczba znaków w jednym poÅ›cie."; +$l['setting_maxmessagelength'] = "Maksymalna dÅ‚ugość posta"; +$l['setting_maxmessagelength_desc'] = "Maksymalna liczba znaków w jednym poÅ›cie. Wpisz 0, by nie nakÅ‚adać ograniczenia."; +$l['setting_maxposts'] = "Maksymalna liczba postów na dzieÅ„"; +$l['setting_maxposts_desc'] = "Maksymalna liczba postów na użytkownika dziennie. Wpisz 0, by nie nakÅ‚adać ograniczenia."; +$l['setting_postfloodcheck'] = "Zabezpieczenie przed floodowaniem"; +$l['setting_postfloodcheck_desc'] = "WÅ‚Ä…cz, jeżeli chcesz uaktywnić zabezpieczenie przed masowym wysyÅ‚aniem postów."; +$l['setting_postfloodsecs'] = "Czas zabezpieczenia przed floodowaniem"; +$l['setting_postfloodsecs_desc'] = "Podaj liczbÄ™ sekund, jakÄ… użytkownicy bÄ™dÄ… musieli odczekać pomiÄ™dzy napisaniem dwóch postów; upewnij siÄ™, że zabezpieczenie jest wÅ‚Ä…czone (opcja powyżej)."; +$l['setting_logip'] = "Zapisywać adresy IP postujÄ…cych?"; +$l['setting_logip_desc'] = "Czy chcesz, aby adresy IP użytkowników byÅ‚y zapisywane w bazie danych przy ich postach? Jeżeli tak, to wybierz, kto bÄ™dzie miaÅ‚ do nich dostÄ™p."; +$l['setting_showeditedby'] = "Pokazywać notatkÄ™ \"Edytowane przez\"?"; +$l['setting_showeditedby_desc'] = "Czy po edycji posta ma być do niego doklejana informacja o tym, kto i kiedy wykonaÅ‚ tÄ™ operacjÄ™?"; +$l['setting_showeditedbyadmin'] = "Pokazywać notatkÄ™ \"Edytowane przez\" po edycji postów przez osoby zarzÄ…dzajÄ…ce forum?"; +$l['setting_showeditedbyadmin_desc'] = "Czy po edycji posta przez osobÄ™ zarzÄ…dzajÄ…cÄ… forum (administratora, moderatora) ma być do niego doklejana informacja o tym, kto i kiedy wykonaÅ‚ tÄ™ operacjÄ™?"; +$l['setting_maxpostimages'] = "Maksymalna liczba obrazków w poÅ›cie"; +$l['setting_maxpostimages_desc'] = "Podaj maksymalnÄ… liczbÄ™ obrazków (w tym emotikonów) możliwÄ… do doÅ‚Ä…czenia do posta. Wpisz 0, by nie nakÅ‚adać takiego ograniczenia."; +$l['setting_maxpostvideos'] = "Maksymalna liczba plików wideo w poÅ›cie"; +$l['setting_maxpostvideos_desc'] = "Podaj maksymalnÄ… liczbÄ™ plików wideo możliwÄ… do doÅ‚Ä…czenia do posta. Wpisz 0, by nie nakÅ‚adać takiego ograniczenia."; +$l['setting_subscribeexcerpt'] = "Liczba znaków w podglÄ…dzie posta w subskrypcji"; +$l['setting_subscribeexcerpt_desc'] = "Ile pierwszych znaków z posta ma być doÅ‚Ä…czonych w e-mailu informujÄ…cym o odpowiedzi?"; +$l['setting_maxattachments'] = "Maksymalna liczba zaÅ‚Ä…czników do posta"; +$l['setting_maxattachments_desc'] = "Maksymalna liczba plików, jakie można doÅ‚Ä…czyć do pojedynczego posta."; +$l['setting_attachthumbnails'] = "Pokazywać miniaturki zaÅ‚Ä…czników w postach?"; +$l['setting_attachthumbnails_desc'] = "Czy chcesz, by w postach wyÅ›wietlane byÅ‚y miniaturki zaÅ‚Ä…czonych obrazków?"; +$l['setting_attachthumbh'] = "Maksymalna wysokość miniaturki"; +$l['setting_attachthumbh_desc'] = "Podaj wysokość, jakÄ… majÄ… mieć miniaturki zaÅ‚Ä…czonych obrazków."; +$l['setting_attachthumbw'] = "Maksymalna szerokość miniaturki"; +$l['setting_attachthumbw_desc'] = "Podaj szerokość, jakÄ… majÄ… mieć miniaturki zaÅ‚Ä…czonych obrazków."; +$l['setting_edittimelimit'] = "Limit czasu edycji"; +$l['setting_edittimelimit_desc'] = "Liczba minut, po jakich użytkownicy przestanÄ… mieć możliwość edycji swoich postów. Wpisz 0, by nie ustalać takiego ograniczenia."; +$l['setting_wordwrap'] = "Maksymalna liczba znaków w sÅ‚owie"; +$l['setting_wordwrap_desc'] = "Maksymalna liczba znaków, jakie może zawierać pojedyncze sÅ‚owo (jeÅ›li zostanie przekroczona, sÅ‚owo zostanie automatycznie podzielone, co pomoże zapobiec bÅ‚Ä™dnemu wyÅ›wietlaniu layoutu strony. Wpisz 0, by nie ustalać takiego ograniczenia."; +$l['setting_polloptionlimit'] = "Maksymalna dÅ‚ugość odpowiedzi w ankiecie"; +$l['setting_polloptionlimit_desc'] = "Maksymalna dÅ‚ugość pojedynczej odpowiedzi w ankiecie (w znakach). Wpisz 0, by nie ustalać takiego ograniczenia."; +$l['setting_maxpolloptions'] = "Maksymalna liczba odpowiedzi w ankiecie"; +$l['setting_maxpolloptions_desc'] = "Maksymalna liczba odpowiedzi jakie użytkownik może zaproponować w ankiecie."; +$l['setting_enablememberlist'] = "WÅ‚Ä…cz wyÅ›wietlanie listy użytkowników"; +$l['setting_enablememberlist_desc'] = "JeÅ›li nie chcesz, by forum posiadaÅ‚o stronÄ™ z listÄ… zarejestrowanych użytkowników, ustaw tÄ™ opcjÄ™ na \"nie\"."; +$l['setting_membersperpage'] = "Liczba użytkowników na stronÄ™"; +$l['setting_membersperpage_desc'] = "Liczba użytkowników pokazywanych na pojedynczej stronie listy."; +$l['setting_default_memberlist_sortby'] = "DomyÅ›lnie sortuj wg..."; +$l['setting_default_memberlist_sortby_desc'] = "Pole, wedÅ‚ug którego lista bÄ™dzie domyÅ›lnie sortowana."; +$l['setting_default_memberlist_order'] = "DomyÅ›lny porzÄ…dek sortowania"; +$l['setting_default_memberlist_order_desc'] = "Wybierz porzÄ…dek, w jakim sortowane majÄ… być dane (domyÅ›lnie)."; +$l['setting_enablereputation'] = "WÅ‚Ä…czyć system reputacji?"; +$l['setting_enablereputation_desc'] = "JeÅ›li chcesz zdezaktywować system reputacji na swoim forum, wybierz \"nie\"."; +$l['setting_negrep'] = "Zezwalać na negatywne punkty reputacji?"; +$l['setting_negrep_desc'] = "JeÅ›li nie chcesz, aby użytkownicy mogli przyznawać negatywne punkty reputacji na swoim forum, wybierz \"nie\"."; +$l['setting_multirep'] = "Zezwalać na wielokrotne przyznawanie punktów reputacji?"; +$l['setting_multirep_desc'] = "JeÅ›li nie chcesz, aby dany użytkownik mógÅ‚ przyznać temu samemu użytkownikowi kilka punktów reputacji na swoim forum, wybierz \"nie\"."; +$l['setting_postrep'] = "Zezwalać na przyznawanie punktów reputacji za posty?"; +$l['setting_postrep_desc'] = "JeÅ›li nie chcesz, aby użytkownicy mogli przyznawać punkty reputacji za posty, wybierz \"nie\"."; + +$l['setting_repsperpage'] = "Liczba ocen reputacji na stronÄ™"; +$l['setting_repsperpage_desc'] = "Podaj liczbÄ™ ocen reputacji, jakie majÄ… być wyÅ›wietlane na pojedynczej stronie listy."; +$l['setting_maxreplength'] = "Maksymalna dÅ‚ugość opisu punktu reputacji"; +$l['setting_maxreplength_desc'] = "Maksymalna liczba znaków, jaka może zostać użyta w opisie punktu reputacji."; + +$l['setting_showteamleaders'] = "Wyróżnij liderów grup"; +$l['setting_showteamleaders_desc'] = "Jeżeli wybierzesz \"tak\", a grupy posiadajÄ… swoich liderów, zostanÄ… oni wyÅ›wietleni ponad resztÄ… czÅ‚onków grupy."; +$l['setting_enablepms'] = "Umożliwić przesyÅ‚anie prywatnych wiadomoÅ›ci?"; +$l['setting_enablepms_desc'] = "JeÅ›li chcesz wyÅ‚Ä…czyć system prywatnych wiadomoÅ›ci na swoim forum, wybierz opcjÄ™ \"nie\"."; +$l['setting_pmsallowhtml'] = "Zezwolić na HTML?"; +$l['setting_pmsallowhtml_desc'] = "Wybierz \"tak\", jeÅ›li chcesz zezwolić na użycie HTML w prywatnych wiadomoÅ›ciach."; +$l['setting_allowbuddyonly'] = "Zezwolić na wysyÅ‚anie wiadomoÅ›ci tylko do znajomych na liÅ›cie kontaktów?"; +$l['setting_allowbuddyonly_desc'] = "Czy użytkownicy majÄ… mieć możliwość wysyÅ‚ania wiadomoÅ›ci tylko do osób, które znajdujÄ… siÄ™ na ich liÅ›cie znajomych?"; +$l['setting_pmsallowmycode'] = "Zezwolić na MyCode?"; +$l['setting_pmsallowmycode_desc'] = "Wybierz \"tak\", jeÅ›li chcesz zezwolić na użycie MyCode w prywatnych wiadomoÅ›ciach."; +$l['setting_pmsallowsmilies'] = "Zezwolić na emotikony?"; +$l['setting_pmsallowsmilies_desc'] = "Wybierz \"tak\", jeÅ›li chcesz zezwolić na użycie emotikonów w prywatnych wiadomoÅ›ciach."; +$l['setting_pmsallowimgcode'] = "Zezwolić na użycie kodu [img]? "; +$l['setting_pmsallowimgcode_desc'] = "Wybierz \"tak\", jeÅ›li chcesz zezwolić na użycie kodu [img] w prywatnych wiadomoÅ›ciach."; +$l['setting_pmsallowvideocode'] = "Zezwolić na użycie kodu [video]? "; +$l['setting_pmsallowvideocode_desc'] = "Wybierz \"tak\", jeÅ›li chcesz zezwolić na użycie kodu [video] w prywatnych wiadomoÅ›ciach."; +$l['setting_pmfloodsecs'] = "Czas zabezpieczenia przed floodowaniem"; +$l['setting_pmfloodsecs_desc'] = "Podaj liczbÄ™ sekund, jakÄ… użytkownicy bÄ™dÄ… musieli odczekać pomiÄ™dzy napisaniem kolejnych prywatnych wiadomoÅ›ci; upewnij siÄ™, że zabezpieczenie jest wÅ‚Ä…czone (opcja powyżej)."; +$l['setting_logip'] = "Zapisywać adresy IP postujÄ…cych?"; +$l['setting_enablecalendar'] = "Kalendarz wÅ‚Ä…czony?"; +$l['setting_enablecalendar_desc'] = "Jeżeli chcesz wyÅ‚Ä…czyć Kalendarz na swoim forum, wybierz \"Nie\"."; +$l['setting_wolcutoffmins'] = "Maksymalny czas bezczynnoÅ›ci (w minutach)"; +$l['setting_wolcutoffmins_desc'] = "Liczba minut, w których użytkownik powinien wykonać jakÄ…Å› akcjÄ™, zanim zostanie uznany za nieobecnego. Zalecana wartość: 15."; +$l['setting_refreshwol'] = "Czas odÅ›wieżenia strony \"Kto jest online\"?"; +$l['setting_refreshwol_desc'] = "Podaj liczbÄ™ minut, po której strona \"Kto jest online\" bÄ™dzie automatycznie odÅ›wieżana. Wpisz 0, jeÅ›li chcesz wyÅ‚Ä…czyć automatyczne odÅ›wieżanie."; +$l['setting_portal_announcementsfid'] = "DziaÅ‚y z ogÅ‚oszeniami"; +$l['setting_portal_announcementsfid_desc'] = "Wybierz dziaÅ‚y, których wÄ…tki bÄ™dÄ… wyÅ›wietlane jako ogÅ‚oszenia."; +$l['setting_portal_numannouncements'] = "Liczba ogÅ‚oszeÅ„ do wyÅ›wietlenia"; +$l['setting_portal_numannouncements_desc'] = "Podaj liczbÄ™ ogÅ‚oszeÅ„, jakie bÄ™dÄ… wyÅ›wietlane na stronie głównej."; +$l['setting_portal_showwelcome'] = "Pokazywać okno z powitaniem?"; +$l['setting_portal_showwelcome_desc'] = "Czy chcesz, by wyÅ›wietlane byÅ‚o okno z powitaniem?"; +$l['setting_portal_showpms'] = "Pokazywać użytkownikom liczbÄ™ PW?"; +$l['setting_portal_showpms_desc'] = "Czy chcesz, by wyÅ›wietlana byÅ‚a liczba prywatnych wiadomoÅ›ci, jakie użytkownik ma w swojej skrzynce?"; +$l['setting_portal_showstats'] = "Pokazywać statystyki forum?"; +$l['setting_portal_showstats_desc'] = "Czy chcesz, by na stronie portalu wyÅ›wietlane byÅ‚y: liczba postów, wÄ…tków, użytkowników oraz login ostatnio zarejestrowanego użytkownika?"; +$l['setting_portal_showwol'] = "Pokazywać \"Kto jest online\"?"; +$l['setting_portal_showwol_desc'] = "Czy chcesz, by na stronie portalu wyÅ›wietlany byÅ‚ panel \"Kto jest online\"?"; +$l['setting_portal_showsearch'] = "Pokazywać panel wyszukiwania?"; +$l['setting_portal_showsearch_desc'] = "Czy chcesz, by wyÅ›wietlany byÅ‚ panel wyszukiwania, dziÄ™ki któremu użytkownicy bÄ™dÄ… mogli szybko znaleźć potrzebne im wiadomoÅ›ci na forum?"; +$l['setting_portal_showdiscussions'] = "Pokazywać listÄ™ ostatnich dyskusji?"; +$l['setting_portal_showdiscussions_desc'] = "Czy chcesz, by na stronie portalu wyÅ›wietlana byÅ‚a lista ostatnio aktywnych wÄ…tków?"; +$l['setting_portal_showdiscussionsnum'] = "Liczba ostatnich dyskusji do wyÅ›wietlenia"; +$l['setting_portal_showdiscussionsnum_desc'] = "Wpisz liczbÄ™ ostatnio aktywnych wÄ…tków, jakie majÄ… być wyÅ›wietlone na stronie portalu."; +$l['setting_searchtype'] = "Sposób wyszukiwania"; +$l['setting_searchtype_desc'] = "Wybierz sposób wyszukiwania, którego chcesz używać. W zależnoÅ›ci od typu bazy, możesz wybrać opcje \"Standard\", i \"Full Text\". Wyszukiwanie \"Full Text\" jest wydajniejsze i wygodniejsze od standardowego."; +$l['setting_searchfloodtime'] = "Czas kontroli floodowania (w sekundach)"; +$l['setting_searchfloodtime_desc'] = "Wpisz czas w sekundach, jaki musi upÅ‚ynąć pomiÄ™dzy dwiema akcjami wyszukiwania przeprowadzonymi przez tego samego użytkownika. Pozwoli to zapobiec próbom przeciążenia serwera przez nieustanne próby wyszukiwania. Wpisz 0, by nie ustalać takiego ograniczenia."; +$l['setting_minsearchword'] = "Minimalna dÅ‚ugość sÅ‚owa"; +$l['setting_minsearchword_desc'] = "Wpisz minimalnÄ… liczbÄ™ znaków w sÅ‚owie zawartym w wyszukiwanej frazie. Wpisz 0, by wyÅ‚Ä…czyć limit (i wybrać limit trzech znaków przy wyszukiwaniu sposobem standardowym lub czterech przy wyszukiwaniu \"Full Text\"). Jeżeli podasz limit mniejszy niż 4 znaki, a używasz sposobu \"Full Text\", twój wybór zostanie nadpisany przez 4."; +$l['setting_maxquotedepth'] = "Maksymalna liczba zagnieżdżonych cytatów"; +$l['setting_maxquotedepth_desc'] = "Maksymalna liczba tagów [quote] w jednym poÅ›cie. Jeżeli post zawiera ich wiÄ™cej, niż wpisana liczba w tym ustawieniu, zostanÄ… one usuniÄ™te automatycznie. Ustawienie to dziaÅ‚a tylko po naciÅ›niÄ™ciu przycisku \"Cytuj\" w widoku wÄ…tku i nie wpÅ‚ywa na napisane już posty. Użytkownik może ominąć to ograniczenie poprzez rÄ™czne wpisanie tagów [quote]. Wpisz 0, by nie ustalać takiego ograniczenia."; +$l['setting_searchhardlimit'] = "Maksymalna liczba wyników wyszukiwania"; +$l['setting_searchhardlimit_desc'] = "Podaj maksymalnÄ… liczbÄ™ wyników wyszukiwania. Wpisz 0, by nie ustalać takiego ograniczenia. Na dużych forach (powyżej 1 mln postów) wartość ta nie powinna przekroczyć 1000."; +$l['setting_smilieinserter'] = "Pole wstawiania emotikonów"; +$l['setting_smilieinserter_desc'] = "Jeżeli ta opcja bÄ™dzie wÅ‚Ä…czona, w czasie pisania postów wyÅ›wietlane bÄ™dzie pole, z którego bÄ™dzie można wybierać emotikony."; +$l['setting_smilieinsertertot'] = "Liczba wyÅ›wietlanych emotikonów"; +$l['setting_smilieinsertertot_desc'] = "Podaj liczbÄ™ emotikonów, jakie majÄ… być wyÅ›wietlane w opisywanym wyżej polu."; +$l['setting_smilieinsertercols'] = "Liczba kolumn z emotikonami"; +$l['setting_smilieinsertercols_desc'] = "Podaj liczbÄ™ kolumn, w jakie majÄ… być pogrupowane emotikony."; +$l['setting_cplanguage'] = "JÄ™zyk panelu administratora"; +$l['setting_cplanguage_desc'] = "JÄ™zyk panelu administratora."; +$l['setting_cpstyle'] = "Styl panelu administratora"; +$l['setting_cpstyle_desc'] = "DomyÅ›lny styl używany przez panel administratora. Style znajdujÄ… siÄ™ w katalogu styles. Nazwa katalogu ze stylem jest jednoczeÅ›nie nazwÄ… stylu, a plik style.css jest plikiem z jego stylami CSS."; +$l['setting_maxloginattempts'] = "Maksymalna liczba nieudanych prób logowania"; +$l['setting_maxloginattempts_desc'] = "Maksymalna liczba nieudanych prób logowania przed zablokowaniem konta administratora. Wpisz 0, by nie ustalać ograniczenia."; +$l['setting_loginattemptstimeout'] = "Czas pomiÄ™dzy nieudanymi próbami zalogowania"; +$l['setting_loginattemptstimeout_desc'] = "Czas (w minutach) jaki trzeba bÄ™dzie odczekać przed ponownÄ… próbÄ… zalogowania po wykorzystaniu powyższego limitu."; + +$l['setting_group_warning'] = "Ustawienia systemu ostrzeżeÅ„"; +$l['setting_group_warning_desc'] = "System ostrzeżeÅ„ pozwala na karanie użytkowników nieprzestrzegajÄ…cych zasad panujÄ…cych na forum. Możesz tu dostosowywać jego ustawienia do swoich potrzeb."; +$l['setting_group_mailsettings'] = "Ustawienia poczty e-mail"; +$l['setting_group_mailsettings_desc'] = "W tej sekcji masz możliwość zarzÄ…dzania systemem mailingu w MyBB, zarówno obsÅ‚ugiwanym przez funkcjÄ™ mail PHP, jak i przez zewnÄ™trzny serwer SMTP."; +$l['setting_returnemail'] = "Adres zwrotny"; +$l['setting_returnemail_desc'] = "Adres zwrotny dla e-maili wysyÅ‚anych za poÅ›rednictwem systemu forum. Pozostaw to pole puste, by użyć adresu e-mail administratora."; +$l['setting_cookieprefix'] = "Prefiks cookies"; +$l['setting_cookieprefix_desc'] = "Prefiks dla wszystkich cookies zwiÄ…zanych z MyBB. Przydatny, jeżeli chcesz zainstalować wiÄ™cej niż jednÄ… kopiÄ™ systemu MyBB w tej samej domenie, albo posiadasz inne oprogramowanie, które używa takich samych nazw cookies. Jeżeli pozostawisz to pole puste, prefiks nie bÄ™dzie używany."; +$l['setting_reportmethod_db'] = "Przechowuj w bazie danych"; +$l['setting_reportmethod_pms'] = "WysyÅ‚aj jako prywatne wiadomoÅ›ci"; +$l['setting_reportmethod_email'] = "WysyÅ‚aj jako e-mail"; +$l['setting_showlanguageselect'] = "Pokazywać pole wyboru jÄ™zyka w stopce?"; +$l['setting_showlanguageselect_desc'] = "Wybierz \"Nie\" jeÅ›li nie chcesz, by w stopce forum wyÅ›wietlane byÅ‚o pole szybkiej zmiany wersji jÄ™zykowej."; +$l['setting_maxmultipagelinks'] = "Maksymalna liczba linków przy stronicowaniu"; +$l['setting_maxmultipagelinks_desc'] = "Możesz podać maksymalnÄ… liczbÄ™ linków do wczeÅ›niejszych i dalszych stron w przypadku wyÅ›wietlania danych z podziaÅ‚em na strony."; +$l['setting_mailingaddress'] = "Adres do korespondencji"; +$l['setting_mailingaddress_desc'] = "Jeżeli posiadasz adres do korespondencji, podaj go tutaj. BÄ™dzie on wyÅ›wietlany w formularzu COPAA."; +$l['setting_faxno'] = "Numer FAX"; +$l['setting_faxno_desc'] = "Jeżeli posiadasz FAX, podaj tutaj jego numer. BÄ™dzie on wyÅ›wietlany w formularzu COPAA."; +$l['setting_seourls'] = "WÅ‚Ä…czyć linki przyjazne wyszukiwarkom?"; +$l['setting_seourls_desc'] = "Linki przyjazne wyszukiwarkom to krótsze adresy poszczególnych stron należących do forum - dziÄ™ki temu wyszukiwarki lepiej je indeksujÄ…, a użytkownicy mogÄ… Å‚atwiej dostać siÄ™ do ulubionych wÄ…tków wpisujÄ…c rÄ™cznie ich adresy. Na przykÅ‚ad, zamiast wpisywać \"showthread.php?tid=1\" można bÄ™dzie napisać po prostu \"thread1.html\". AktywujÄ…c tÄ™ opcjÄ™ musisz pamiÄ™tać o wgraniu pliku .htaccess z paczki MyBB do katalogu forum na swoim serwerze. PamiÄ™taj też, że automatyczne wykrywanie tej opcji może być zawodne na niektórych serwerach. Odwiedź MyBB Wiki, by dowiedzieć siÄ™ wiÄ™cej."; +$l['setting_seourls_auto'] = "Wykryj automatycznie"; +$l['setting_seourls_yes'] = "WÅ‚Ä…cz"; +$l['setting_seourls_no'] = "WyÅ‚Ä…cz"; +$l['setting_use_xmlhttprequest'] = "WÅ‚Ä…czyć funkcje zwiÄ…zane z XMLHttp?"; +$l['setting_use_xmlhttprequest_desc'] = "Możesz wÅ‚Ä…czyć lub wyÅ‚Ä…czyć funkcje forum wymagajÄ…ce XMLHttp."; +$l['setting_useerrorhandling'] = "Korzystaj z wbudowanego systemu obsÅ‚ugi bÅ‚Ä™dów"; +$l['setting_useerrorhandling_desc'] = "Jeżeli nie chcesz korzystać z wbudowanego w MyBB systemu obsÅ‚ugi bÅ‚Ä™dów, możesz go tutaj wyÅ‚Ä…czyć. Zaleca siÄ™ jednak pozostawienie tej opcji wÅ‚Ä…czonej."; +$l['setting_errorlogmedium'] = "Sposób zapisywania informacji o bÅ‚Ä™dach"; +$l['setting_errorlogmedium_desc'] = "Sposób, w jaki przechowywane bÄ™dÄ… informacje o bÅ‚Ä™dach."; +$l['setting_errorlogmedium_none'] = "Brak"; +$l['setting_errorlogmedium_log'] = "Zapisuj logi"; +$l['setting_errorlogmedium_email'] = "WysyÅ‚aj e-maile"; +$l['setting_errorlogmedium_both'] = "Zapisuj logi i wysyÅ‚aj e-maile"; +$l['setting_errortypemedium'] = "Typy bÅ‚Ä™dów"; +$l['setting_errortypemedium_desc'] = "Typy obsÅ‚ugiwanych bÅ‚Ä™dów."; +$l['setting_errortypemedium_warning'] = "Ostrzeżenia (warnings)"; +$l['setting_errortypemedium_error'] = "BÅ‚Ä™dy (errors)"; +$l['setting_errortypemedium_both'] = "Ostrzeżenia i bÅ‚Ä™dy"; +$l['setting_errortypemedium_none'] = "Ukryj bÅ‚Ä™dy i ostrzeżenia"; +$l['setting_errorloglocation'] = "Miejsce logowania bÅ‚Ä™dów"; +$l['setting_errorloglocation_desc'] = "Åšcieżka do pliku, w którym zapisywane bÄ™dÄ… logi bÅ‚Ä™dów."; +$l['setting_showforumviewing'] = "WyÅ›wietlać liczbÄ™ przeglÄ…dajÄ…cych dziaÅ‚?"; +$l['setting_showforumviewing_desc'] = "WyÅ›wietla liczbÄ™ użytkowników przeglÄ…dajÄ…cych każdy dziaÅ‚ w danym momencie."; +$l['setting_postlayout'] = "UkÅ‚ad posta"; +$l['setting_postlayout_desc'] = "Pozwala na wybór pomiÄ™dzy ukÅ‚adem poziomym a klasycznym. W ukÅ‚adzie klasycznym informacje o autorze posta wyÅ›wietlane sÄ… po lewej stronie treÅ›ci, w ukÅ‚adzie poziomym - wyÅ›wietlane sÄ… poziomo, nad treÅ›ciÄ… posta."; +$l['setting_postlayout_horizontal'] = "WyÅ›wietlaj posty w ukÅ‚adzie poziomym"; +$l['setting_postlayout_classic'] = "WyÅ›wietlaj posty w ukÅ‚adzie klasycznym"; +$l['setting_postmaxavatarsize'] = "Maksymalne wymiary awatara przy postach"; +$l['setting_postmaxavatarsize_desc'] = "Maksymalne wymiary awatara wyÅ›wietlanego przy postach. Jeżeli awatar bÄ™dzie zbyt duży, zostanie automatycznie pomniejszony."; +$l['setting_delayedthreadviews'] = "Opóźniona aktualizacja licznika wyÅ›wietleÅ„"; +$l['setting_delayedthreadviews_desc'] = "Jeżeli ta opcja bÄ™dzie aktywna, liczba wyÅ›wietleÅ„ wÄ…tku bÄ™dzie aktualizowana w tle przez system zaplanowanych zadaÅ„. Jeżeli nie, liczba bÄ™dzie zwiÄ™kszana natychmiast po wyÅ›wietlaniu."; +$l['setting_regtype_instant'] = "Natychmiastowa aktywacja"; +$l['setting_regtype_verify'] = "Weryfikacja e-mail"; +$l['setting_regtype_randompass'] = "WyÅ›lij losowe hasÅ‚o"; +$l['setting_regtype_admin'] = "Aktywacja przez administratora"; +$l['setting_regtype_both'] = "Aktywacja zarówno poprzez weryfikacjÄ™ e-mail, jak i administratora"; +$l['setting_allowmultipleemails'] = "Dopuszczać kilkakrotne rejestrowanie tych samych e-maili?"; +$l['setting_allowmultipleemails_desc'] = "Wybierz \"Tak\" jeżeli chcesz, by użytkownicy mogli wielokrotnie rejestrować ten sam adres e-mail."; +$l['setting_avatarresizing'] = "Sposób przeskalowywania awatarów"; +$l['setting_avatarresizing_desc'] = "Wybierz, czy chcesz, by zbyt duże awatary byÅ‚y pomniejszane automatycznie, za zgodÄ… użytkowników, albo wcale."; +$l['setting_avatarresizing_auto'] = "Automatycznie pomniejszaj"; +$l['setting_avatarresizing_user'] = "Pytaj użytkownika"; +$l['setting_avatarresizing_disabled'] = "WyÅ‚Ä…cz tÄ™ opcjÄ™"; +$l['setting_coppa'] = "COPPA"; +$l['setting_coppa_desc'] = "Jeżeli chcesz wÅ‚Ä…czyć obsÅ‚ugÄ™ COPPA na swoim forum, wybierz ustawienia poniżej."; +$l['setting_coppa_enabled'] = "WÅ‚Ä…czone - weryfikuj użytkowników poniżej 13 roku życia"; +$l['setting_coppa_deny'] = "ZabroÅ„ rejestracji użytkownikom poniżej 13 roku życia"; +$l['setting_coppa_disabled'] = "WyÅ‚Ä…cz tÄ™ opcjÄ™"; +$l['setting_allowaway'] = "Zezwolić na status \"NiedostÄ™pny\"?"; +$l['setting_allowaway_desc'] = "Czy użytkownicy majÄ… mieć możliwość ustawiania sobie statusu \"NiedostÄ™pny\" wraz z możliwoÅ›ciÄ… podania powodu nieobecnoÅ›ci i datÄ… powrotu?"; +$l['setting_postmergemins'] = "Czas Å‚Ä…czenia postów"; +$l['setting_postmergemins_desc'] = "Jeżeli ta opcja jest wÅ‚Ä…czona, posty napisane w ciÄ…gu danej liczby minut przez tego samego użytkownika w tym samym wÄ…tku bÄ™dÄ… automatycznie Å‚Ä…czone. Podaj limit czasu (w minutach) przez jaki ta opcja ma być aktywna. Podaj 0 lub pozostaw to pole puste, by wyÅ‚Ä…czyć tÄ™ opcjÄ™. DomyÅ›lnie: 60"; +$l['setting_postmergefignore'] = "DziaÅ‚y bez Å‚Ä…czenia postów"; +$l['setting_postmergefignore_desc'] = "DziaÅ‚y, oddzielone przecinkiem, w których nie bÄ™dzie dziaÅ‚ać opcja automatycznego Å‚Ä…czenia postów. W przypadku braku takich działów pozostaw to pole puste."; +$l['setting_postmergeuignore'] = "Grupy użytkowników bez Å‚Ä…czenia postów"; +$l['setting_postmergeuignore_desc'] = "Grupy użytkowników, oddzielone przecinkiem, dla których nie bÄ™dzie dziaÅ‚ać opcja automatycznego Å‚Ä…czenia postów. W przypadku braku takich grup pozostaw to pole puste."; +$l['setting_postmergesep'] = "Separator poÅ‚Ä…czonych postów"; +$l['setting_postmergesep_desc'] = "Separator oddzielajÄ…cy poÅ‚Ä…czone posty. DomyÅ›lnie: \"[hr]\""; +$l['setting_logip_no'] = "Nie zapisuj IP"; +$l['setting_logip_hide'] = "Pokazuj moderatorom i administratorom"; +$l['setting_logip_show'] = "Pokazuj wszystkim użytkownikom"; +$l['setting_attachthumbnails_yes'] = "Miniaturki"; +$l['setting_attachthumbnails_no'] = "Obrazki peÅ‚nych rozmiarów"; +$l['setting_attachthumbnails_download'] = "Linki do obrazków"; +$l['setting_threadreview'] = "WyÅ›wietlać podglÄ…d tematu?"; +$l['setting_threadreview_desc'] = "WyÅ›wietlać ostatnie posty podczas redagowania nowej odpowiedzi?"; +$l['setting_default_memberlist_sortby_regdate'] = "Daty rejestracji"; +$l['setting_default_memberlist_sortby_postnum'] = "Liczby postów"; +$l['setting_default_memberlist_sortby_username'] = "Loginu"; +$l['setting_default_memberlist_sortby_lastvisit'] = "Ostatniej wizyty"; +$l['setting_default_memberlist_order_ascending'] = "RosnÄ…co"; +$l['setting_default_memberlist_order_descending'] = "MalejÄ…co"; +$l['setting_memberlistmaxavatarsize'] = "Maksymalne rozmiary awatara na liÅ›cie użytkowników"; +$l['setting_memberlistmaxavatarsize_desc'] = "Maksymalne rozmiary awatara wyÅ›wietlanego na liÅ›cie użytkowników. Jeżeli awatar bÄ™dzie zbyt duży, zostanie automatycznie przeskalowany."; +$l['setting_enablewarningsystem'] = "WÅ‚Ä…czyć system ostrzeżeÅ„?"; +$l['setting_enablewarningsystem_desc'] = "Wybierz \"Nie\" by caÅ‚kowicie wyÅ‚Ä…czyć system ostrzeżeÅ„."; +$l['setting_allowcustomwarnings'] = "Zezwolić na podawanie wÅ‚asnych typów ostrzeżeÅ„?"; +$l['setting_allowcustomwarnings_desc'] = "Czy moderatorzy majÄ… mieć możliwość podawania wÅ‚asnych powodów i liczby punktów ostrzeżenia?"; +$l['setting_canviewownwarning'] = "Czy użytkownicy mogÄ… przeglÄ…dać wÅ‚asne ostrzeżenia?"; +$l['setting_canviewownwarning_desc'] = "Wybierz \"Tak\" jeÅ›li chcesz, by użytkownicy mogli przeglÄ…dać otrzymane ostrzeżenia w swoich panelach użytkowników oraz widzieć aktualny poziom ostrzeżeÅ„ w swoim profilu."; +$l['setting_maxwarningpoints'] = "Maksymalna liczba punktów ostrzeżeÅ„"; +$l['setting_maxwarningpoints_desc'] = "Maksymalna liczba punktów ostrzeżeÅ„, jakÄ… użytkownik może otrzymać nim jego poziom ostrzeżenia osiÄ…gnie 100%."; +$l['setting_searchtype_standard'] = "Standard"; +$l['setting_searchtype_fulltext'] = "Full Text"; +$l['setting_bbcodeinserter'] = "PodrÄ™czny edytor MyCode"; +$l['setting_bbcodeinserter_desc'] = "WÅ‚Ä…cz tÄ™ opcjÄ™ by wyÅ›wietlać podrÄ™czny edytor z przyciskami uÅ‚atwiajÄ…cymi formatowanie wypowiedzi za pomocÄ… MyCode."; +$l['setting_mail_handler'] = "Sposób wysyÅ‚ania e-maili"; +$l['setting_mail_handler_desc'] = "Sposób, w jaki MyBB ma sobie radzić z automatycznym wysyÅ‚aniem e-maili."; +$l['setting_mail_handler_mail'] = "Funkcja mail() w PHP"; +$l['setting_mail_handler_smtp'] = "ZewnÄ™trzny serwer SMTP"; +$l['setting_mail_parameters'] = "Dodatkowe parametry dla funkcji mail() w PHP"; +$l['setting_mail_parameters_desc'] = "Możesz tutaj podać dodatkowe parametry dla funkcji mail(), jeżeli używasz jej do automatycznego wysyÅ‚ania e-maili. Zobacz: wiÄ™cej informacji."; +$l['setting_smtp_host'] = "Nazwa hosta SMTP"; +$l['setting_smtp_host_desc'] = "Nazwa hosta serwera SMTP, który ma być wykorzystywany do wysyÅ‚ania e-maili.
    Wymagana tylko w przypadku, gdy wybrano wysyłanie e-maili za pomocą zewnętrznego serwera SMTP."; +$l['setting_smtp_port'] = "Port SMTP"; +$l['setting_smtp_port_desc'] = "Numer portu serwera SMTP, który ma być wykorzystywany do wysyłania e-maili.
    Wymagany tylko w przypadku, gdy wybrano wysyłanie e-maili za pomocą zewnętrznego serwera SMTP."; +$l['setting_smtp_user'] = "Login SMTP"; +$l['setting_smtp_user_desc'] = "Login wymagany do uwierzytelnienia na serwerze SMTP.
    Wymagany tylko w przypadku, gdy wybrano wysyłanie e-maili za pomocą zewnętrznego serwera SMTP."; +$l['setting_smtp_pass'] = "Hasło SMTP"; +$l['setting_smtp_pass_desc'] = "Hasło wymagane do uwierzytelnienia na serwerze SMTP.
    Wymagane tylko w przypadku, gdy wybrano wysyłanie e-maili za pomocą zewnętrznego serwera SMTP."; +$l['setting_secure_smtp'] = "Sposób szyfrowania SMTP"; +$l['setting_secure_smtp_desc'] = "Wybierz sposób szyfrowania z którego MyBB ma korzystać przy wysyłaniu e-maili.
    Wymagany tylko w przypadku, gdy wybrano wysyłanie e-maili za pomocą zewnętrznego serwera SMTP."; +$l['setting_secure_smtp_0'] = "Bez szyfrowania"; +$l['setting_secure_smtp_1'] = "Szyfrowanie SSL"; +$l['setting_secure_smtp_2'] = "Szyfrowanie TLS"; +$l['setting_mail_logging'] = "Logi e-maili"; +$l['setting_mail_logging_desc'] = "Możesz tutaj wybrać sposób, w jaki mają być zapisywane logi e-maili wysyłanych przy użyciu opcji \"Wyślij wątek znajomemu\". W niektórych krajach przechowywanie całej treści korespondencji jest nielegalne."; +$l['setting_mail_message_id'] = "Dodawać identyfikator wiadomości do nagłówków?"; +$l['setting_mail_message_id_desc'] = "Wyłączenie tej opcji na hostingach współdzielonych spowoduje rozwiązanie problemu z wiadomościami wysyłanymi przez machanizm forum trafiającymi do folderu ze spamem."; +$l['setting_mail_logging_0'] = "Wyłącz logi e-maili"; +$l['setting_mail_logging_1'] = "Zapisuj logi bez treści e-maili"; +$l['setting_mail_logging_2'] = "Zapisuj wszystko"; +$l['setting_enablepruning'] = "Włączyć automatyczne usuwanie?"; +$l['setting_enablepruning_desc'] = "Włączyć usuwanie użytkowników, którzy spełniają podane kryteria?"; +$l['setting_enableprunebyposts'] = "Włączyć usuwanie według ilości postów?"; +$l['setting_enableprunebyposts_desc'] = "Wybierz \"Tak\" jeżeli chcesz, aby użytkownicy byli usunięci po ilości postów."; +$l['setting_prunepostcount'] = "Liczba postów użytkownika, który zostanie usunięty"; +$l['setting_prunepostcount_desc'] = "Podaj liczbę postów poniżej której użytkownik zostanie usunięty."; +$l['setting_dayspruneregistered'] = "Czas po rejestracji przed usunięciem"; +$l['setting_dayspruneregistered_desc'] = "Podaj liczbę dni, jaka musi upłynąć od rejestracji zanim użytkownik zostanie usunięty"; +$l['setting_pruneunactived'] = "Usunąć nieaktywowanych użytkowników?"; +$l['setting_pruneunactived_desc'] = "Czy chcesz, aby użytkownicy, którzy nie aktywowali swojego konta zostali usunięci?"; +$l['setting_dayspruneunactivated'] = "Czas po rejestracji przed usunięciem nieaktywowanego użytkownika"; +$l['setting_dayspruneunactivated_desc'] = "Podaj liczbę dni, jaka musi upłynąć od rejestracji zanim nieaktywowany użytkownik zostanie usunięty"; +$l['setting_prunethreads'] = "Usunąć wszystkie posty/wątki użytkownika?"; +$l['setting_prunethreads_desc'] = "Czy usunąć wszystkie posty i wątki użytkownika, który zostanie usunięty?"; + +/** Ustawienia dodane w MyBB 1.6.4 i 1.6.7 **/ + +$l['setting_no_plugins'] = "Wyłączyć wszystkie pluginy?"; +$l['setting_no_plugins_desc'] = "Ustaw tę opcję na \"Tak\" jeśli chcesz, aby wszystkie pluginy na forum stały się nieaktywne, ale nie chcesz ich deaktywować lub odinstalowywać. Taki sam efekt możesz uzyskać definiując stałą NO_PLUGINS na początku pliku init.php."; +$l['setting_ip_forwarded_check'] = "Sprawdzać adres IP użytkownika w nagłówkach HTTP?"; +$l['setting_ip_forwarded_check_desc'] = "Czy chcesz, aby adres IP użytkownika był także sprawdzany w nagłówkach HTTP_X_FORWARDED_FOR lub HTTP_X_REAL_IP? Jeżeli nie wiesz, którą opcję wybrać - pozostaw domyślną, czyli \"Nie\"."; +$l['setting_showforumpagesbreadcrumb'] = "Pokazywać rozwijaną listę przy wielu stronach?"; +$l['setting_showforumpagesbreadcrumb_desc'] = "Czy chcesz pokazywać rozwijaną listę wyboru strony (w menu nawigacji), w przypadku gdy dział posiada więcej niż jedną podstronę?"; +$l['setting_readparentforums'] = "Próbować oznaczyć nadrzędny dział jako przeczytany?"; +$l['setting_readparentforums_desc'] = "Przy ustawieniu na tak, dział nadrzędny będzie za każdym razem oznaczany jako przeczytany, kiedy nie będzie w nim żadnych nieprzeczytanych postów. Należy zauważyć, że opcja ta wpływa negatywnie na wydajność forum i powinna być traktowana jako eksperymentalna."; +$l['setting_showbirthdayspostlimit'] = "Pokazywać urodziny tylko od x postów?"; +$l['setting_showbirthdayspostlimit_desc'] = "Możesz wybrać, aby informacje o urodzinach użytkownika ukazywały się od wyznaczonej liczby postów. Wpisanie 0 spowoduje wyświetlenie informacji o urodzinach dla wszystkich użytkowników."; +$l['setting_captchapublickey'] = "Klucz publiczny reCAPTCHA"; +$l['setting_captchapublickey_desc'] = "Twój publiczny klucz reCAPTCHA."; +$l['setting_captchaprivatekey'] = "Klucz prywatny reCAPTCHA"; +$l['setting_captchaprivatekey_desc'] = "Twój prywatny klucz reCAPTCHA."; +$l['setting_hiddencaptchaimage'] = "Pokazywać ukryte CAPTCHA?"; +$l['setting_hiddencaptchaimage_desc'] = "Czy chesz pokazywać ukryte pole CAPTCHA podczas rejestracji użytkownika? Ta opcja może uchronić Twoje forum przed rejestracją botów."; +$l['setting_hiddencaptchaimagefield'] = "Ukryte pole CAPTCHA"; +$l['setting_hiddencaptchaimagefield_desc'] = "Wpisz nazwę ukrytego pola CAPTCHA."; +$l['setting_posrep'] = "Zezwalać na pozytywne punkty reputacji? "; +$l['setting_posrep_desc'] = "Jeśli nie chcesz, aby użytkownicy mogli przyznawać pozytywne punkty reputacji na swoim forum, wybierz \"nie\"."; +$l['setting_neurep'] = "Zezwalać na neutralne punkty reputacji? "; +$l['setting_neurep_desc'] = "Jeśli nie chcesz, aby użytkownicy mogli przyznawać neutralne punkty reputacji na swoim forum, wybierz \"nie\"."; +$l['setting_mail_logging_0'] = "Wyłącz zapisywanie logów e-maili"; +$l['setting_mail_logging_1'] = "Zapisuj logi e-maili bez ich treści"; +$l['setting_mail_logging_2'] = "Zapisuj wszystko"; +$l['setting_captchaimage_0'] = "Bez CAPTCHA"; +$l['setting_captchaimage_1'] = "Standardowe CAPTCHA MyBB"; +$l['setting_captchaimage_2'] = "reCAPTCHA"; +$l['setting_username_method'] = "Dozwolone metody logowania"; +$l['setting_username_method_desc'] = "Wybierz, za pomocą jakich danych użytkownik może się zalogować."; +$l['setting_username_method_0'] = "Tylko za pomocą loginu"; +$l['setting_username_method_1'] = "Tylko za pomocą adresu e-mail"; +$l['setting_username_method_2'] = "Za pomocą loginu lub adresu e-mail"; +$l['setting_allowthreadratings'] = "Pozwolić na ocenanie wątków?"; +$l['setting_allowthreadratings_desc'] = "Czy chcesz, aby użytkownicy mogli oceniać wątki umieszczane na forum?"; + +/** Ustawienia dodane w wersji 1.6.9 **/ +$l['setting_seourls_archive'] = "Włączyć linki przyjazne wyszukiwarkom w wersji bez grafiki?"; +$l['setting_seourls_archive_desc'] = "To ustawienie pozwala na włączenie linków przyjaznych wyszukiwarkom w wersji forum bez grafiki. Po zmianie wartości tego ustawienia upewnij się, że wersja bez grafiki działa prawidłowo."; + +/** Ustawienia i grupy ustawień dodane w wersji 1.8 **/ + +$l['setting_group_profile'] = "Opcje profilów użytkowników"; +$l['setting_group_profile_desc'] = "Ustawienia dotyczące profili użytkowników takie jak sygnatury czy awatary."; +$l['setting_group_attachments'] = "System załączników"; +$l['setting_group_attachments_desc'] = "Ustawienia związane z systemem załączników."; + +$l['setting_contact_guests'] = "Wyłączyć formularz kontaktowy dla gości?"; +$l['setting_contact_guests_desc'] = "Czy chcesz, aby niezalogowani użytkownicy mogli uzyskiwać dostęp do formularza kontaktowego?"; +$l['setting_soft_delete'] = "Włączyć nietrwałe usuwanie?"; +$l['setting_soft_delete_desc'] = "Włączenie tej opcji pozwoli na przywracanie postów i wątków usuniętych przez użytkowników. W innym wypadku posty i wątki będą bezpowrotnie usuwane."; +$l['setting_showthemeselect'] = "Pokazywać pole wyboru stylu w stopce?"; +$l['setting_showthemeselect_desc'] = "Wybierz \"Nie\" jeśli nie chcesz, by w stopce forum wyświetlane było pole szybkiej zmiany stylu."; +$l['setting_minifycss'] = "Zmniejszać rozmiar arkuszy kaskadowych stylów (CSS)?"; +$l['setting_minifycss_desc'] = "Czy chcesz, aby rozmiar arkuszy stylów kaskadowych (CSS) były automatycznie zmniejszane w celu zaoszczędzenia transferu i przyspieszenia ładowania strony?"; +$l['setting_datetimesep'] = "Separator daty i czasu"; +$l['setting_datetimesep_desc'] = "Wpisz znak, który będzie wstawiany między datą i czasem w momencie tworzenia jednego ciągu znaków. Zazwyczaj wykorzystuje się spację lub przecinek."; +$l['setting_regtime'] = "Minimalny czas potrzebny na wypełnienie formularza rejestracji"; +$l['setting_regtime_desc'] = "Czas (w sekundach) jaki trzeba odczekać zanim możliwe będzie wysłanie formularza rejestracji. Pozwala to na zapobieżenie automatycznym rejestracjom. Wpisz 0, aby wyłączyć tę funkcję."; +$l['setting_useravatar'] = "Domyślny awatar użytkownika"; +$l['setting_useravatar_desc'] = "Jeśli użytkownik nie załaduje własnego awatara, zostanie wykorzystany ten, którego ścieżkę wpiszesz poniżej."; +$l['setting_useravatardims'] = "Wymiary domyślnego awatara"; +$l['setting_useravatardims_desc'] = "Wpisz wymiary domyślnego awatara (szerokość, a następnie wysokość). Oddziel je znakiem \"|\" (np.: 40|40)"; +$l['setting_useravatarrating'] = "Najwyższa dozwolona kategoria Gravatara"; +$l['setting_useravatarrating_desc'] = "Pozwala na wybranie kategorii Gravatara, jeśli użytkownik zdecyduje się z niego skorzystać. W przypadku, gdy Gravatar użytkownika jest wyższej kategorii niż dozwolony, zostanie wykorzystany domyślny awatar. + +
      +
    • G: awatar przeznaczony do wyÅ›wietlania na wszystkich stronach internetowych i przez wszystkie osoby (bez ograniczeÅ„ wiekowych)
    • +
    • PG: awatar może zawierać ofensywne gesty, prowokacyjnie ubrane postaci, Å‚agodne przekleÅ„stwa lub Å‚agodnÄ… przemoc (dla osób w wieku 13 lat lub wiÄ™cej)
    • +
    • R: awatar może zawierać przekleÅ„stwa, Å›redniÄ… przemoc, nagość lub przedstawiać używanie narkotyków (dla osób w wieku 16 lat lub wiÄ™cej)
    • +
    • X: może zawierać pornografiÄ™, intensywnÄ… przemoc lub inne oburzajÄ…ce treÅ›ci (dla osób w wieku 18 lat lub wiÄ™cej)
    • +
    "; +$l['setting_mycodemessagelength'] = "Czy zaliczać myCode do długości posta?"; +$l['setting_mycodemessagelength_desc'] = "Czy chcesz, by myCode był wliczany do długości posta?"; +$l['setting_polltimelimit'] = ""; +$l['setting_polltimelimit_desc'] = ""; + +$l['setting_polltimelimit'] = "Limit czasu dodawania ankiet"; +$l['setting_polltimelimit_desc'] = "Liczba godzin, po których użytkownicy przestaną mieć możliwość dodawania ankiet do swoich wątków. Wpisz 0, by nie ustalać takiego ograniczenia."; +$l['setting_enableattachments'] = "Włączyć możliwość dodawania załączników?"; +$l['setting_enableattachments_desc'] = "Jeżeli chcesz, aby użytkownicy nie mogli dodawać załączników wybierz \"Nie\"."; +$l['setting_minreplength'] = "Minimalna długość komentarza punktu reputacji"; +$l['setting_minreplength_desc'] = "Wpisz minimalną liczbę znaków jaką powinien mieć komentarz do punktu reputacji."; +$l['setting_pmquickreply'] = "Wyświetlanie formularza szybkiej odpowiedzi"; +$l['setting_pmquickreply_desc'] = "Możesz tutaj wyłączyć opcję wyświetlania formularza \"szybkiej odpowiedzi\" u dołu prywatnej wiadomości."; +$l['setting_logip'] = "Pokazywać adresy IP w prywatnych wiadomościach?"; +$l['setting_logip_desc'] = "Czy chcesz, aby adresy IP użytkowników były zapisywane w bazie danych przy wysyłaniu prywatnych wiadomości? Jeżeli tak, to wybierz, kto będzie miał do nich dostęp."; +$l['setting_logip_no'] = "Nie zapisuj IP"; +$l['setting_logip_hide'] = "Pokazuj moderatorom i administratorom"; +$l['setting_logip_show'] = "Pokazuj wszystkim użytkownikom"; +$l['setting_wolorder'] = "Sposób sortowania listy \"Kto jest online\""; +$l['setting_wolorder_desc'] = "Wybierz, czy chcesz, aby lista \"Kto jest online\" była sortowana według loginu czy czasu ostatniej aktywności. To ustawienie ma zastosowanie tylko do strony głównej i portalu."; +$l['setting_wolorder_username'] = "Według loginu (rosnąco)"; +$l['setting_wolorder_activity'] = "Według czasu ostatniej aktywności (malejąco)"; + +$l['setting_helpsearch'] = "Włączyć przeszukiwanie pomocy?"; +$l['setting_helpsearch_desc'] = "Włączenie tej opcji pozwoli użytkownikom na przeszukiwanie sekcji pomocy."; +$l['setting_jumptopagemultipage'] = "Pokazywać opcję 'skocz do strony'?"; +$l['setting_jumptopagemultipage_desc'] = "Czy pokazywać przycisk 'skocz do strony' w przypadku przekroczenia \"Maksymalnej liczby linków przy stronicowaniu\"?"; +$l['setting_statstopreferrer'] = "Pokazywać najlepszego polecającego na stronie statystyk?"; +$l['setting_statstopreferrer_desc'] = "Włączenie tej opcji spowoduje pokazywanie na stronie statystyk forum użytkownika z nawiększą liczbą poleceń. Włączenie powoduje konieczność wykonywania dodatkowego zapytania."; +$l['setting_deleteinvites'] = "Ważność starych zaproszeń do grup"; +$l['setting_deleteinvites_desc'] = "Liczba dni, po których zaproszenie do grupy dla użytkownika wygasa. Wpisz 0, aby zaproszenia nie traciły ważności."; +$l['setting_hidewebsite'] = "Ukrywaj strony wskazanym grupom"; +$l['setting_hidewebsite_desc'] = "Wybierz grupy, które nie będą mogły widzieć odnośników do stron użytkowników."; +$l['setting_hidesignatures'] = "Ukrywaj sygnatury wskazanym grupom"; +$l['setting_hidesignatures_desc'] = "Wybierz grupy, które nie będą mogły widzieć sygnatur użytkowników."; + +$l['setting_usecdn'] = "Używać CDN?"; +$l['setting_usecdn_desc'] = "Możesz włączyć używanie CDN (Content Deliver Network) aby przyspieszyć wczytywanie statycznych plików, takich jak arkusze stylów, pliki JavaScript czy obrazy. Czy chcesz włączyć tę funkcjonalność?"; +$l['setting_cdnurl'] = "Adres URL używany dla plików statycznych"; +$l['setting_cdnurl_desc'] = "Jeśli włączyłeś powyższą opcję CDN, wpisz poniżej adres URL, z którego ma być pobierana statyczna zawartość. Adres powinien być poprawny i nie zawierać końcowego ukośnika."; +$l['setting_cdnpath'] = "Ścieżka przechowywania statycznych plików"; +$l['setting_cdnpath_desc'] = "Jeśli włączyłeś powyższą opcję CDN, wpisz (opcjonalnie) pełną ścieżkę do miejsca przechowywania statycznych plików. Jest to użyteczne jedynie w przypadku korzystania z CDN typu \"push\" albo lokalnych subdomen. Adres nie powinien zawierać końcowego ukośnika."; + +$l['setting_forcelogin'] = "Zmuś użytkowników do zalogowania"; +$l['setting_forcelogin_desc'] = "Ustawienie opcję na 'Tak' spowoduje konieczność zalogowania lub rejestracji w celu dostępu do forum."; +$l['setting_securityquestion'] = "Pokazuj pytanie zabezpieczające"; +$l['setting_securityquestion_desc'] = "Czy chcesz, aby użytkownicy podczas rejestracji musieli odpowiadać na pytanie zabezpieczające?"; + +$l['setting_alloweditreason'] = "Pozwolić na zmianę powodu?"; +$l['setting_alloweditreason_desc'] = "Czy chcesz dać użytkownikom możliwość opcjonalnego wpisania powodu edycji posta?"; + +$l['setting_allowanonwarningpms'] = "Pozwolić na anonimowe PW o ostrzeżeniach?"; +$l['setting_allowanonwarningpms_desc'] = "Czy pozwolić moderatorom na wysyłanie anonimowych PW informujących o ostrzeżeniach?"; + +$l['setting_showpmip'] = "Pokazuj IP w prywatnych wiadomościach"; +$l['setting_showpmip_desc'] = "Czy chcesz pokazywać numery IP użytkowników przesyłających prywatne wiadomości (i komu chcesz je pokazywać)?"; +$l['setting_showpmip_no'] = "Nie pokazuj IP"; +$l['setting_showpmip_hide'] = "Pokazuj administratorom i moderatorom"; +$l['setting_showpmip_show'] = "Pokazuj wszystkim użytkownikom"; +$l['setting_maxpmquotedepth'] = "Maksymalna liczba zagnieżdżonych cytatów"; +$l['setting_maxpmquotedepth'] = "Maksymalna liczba zagnieżdżonych zacytowanych poprzednich wiadomości z konwersacji. W przypadku odpowiedzi na PW z zacytowaniem, wszystkie poprzednie zagnieżdżone cytowania przekraczające tę liczbę zostaną automatycznie usunięte. Uwaga - to ograniczenie działa tylko w przypadku automatycznych cytowań w odpowiedzi; nadal możliwe będzie dodawanie własnych cytatów ponad tę liczbę, ustawienie nie zmienia też treści wysłanych już dotychczas wiadomości. Ustawienie wartości 0 wyłącza całkowicie tę opcję."; + +$l['setting_portal'] = "Włącz portal"; +$l['setting_portal_desc'] = "Jeśli chcesz wyłączyć portal na swoim forum, ustaw tę opcję na 'Nie'"; +$l['setting_portal_excludediscussion'] = "Działy wyłączone z ostatnich dyskusji"; +$l['setting_portal_excludediscussion_desc'] = "Wybierz działy, które mają być wyłączone z pokazywania się na liście ostatnich dyskusji."; + +$l['setting_partialmode'] = "Podręczny edytor MyCode w ograniczonym trybie"; +$l['setting_partialmode_desc'] = "W przypadku wyboru 'Tak' poniżej, edytor zostanie uruchomiony w ograniczonym trybie. Niektóre MyCode, takie jak [quote] czy [img], będą wstawiane w polu edycji jako tekst."; +$l['setting_allowbasicmycode'] = "Pozwól na podstawowe MyCodes"; +$l['setting_allowbasicmycode_desc'] = "Ustawienie na 'Tak' pozwoli na używanie podstawowych kodów MyCode, takich jak pogrubienie, pochylenie, podkreślenie i przekreślenie tekstu oraz wstawianie poziomej linii."; +$l['setting_allowcolormycode'] = "Pozwól na MyCode zmieniania kolorów"; +$l['setting_allowcolormycode_desc'] = "Ustawienie na 'Tak' pozwoli na zmienianie kolorów tekstu za pomocą MyCode."; +$l['setting_allowsizemycode'] = "Pozwól na MyCode zmieniania rozmiaru"; +$l['setting_allowsizemycode_desc'] = "Ustawienie na 'Tak' pozwoli na zmienianie rozmiaru tekstu za pomocą MyCode."; +$l['setting_allowfontmycode'] = "Pozwól na MyCode zmieniania czcionki"; +$l['setting_allowfontmycode_desc'] = "Ustawienie na 'Tak' pozwoli na zmienianie czcionki tekstu za pomocą MyCode."; +$l['setting_allowlinkmycode'] = "Pozwól na MyCode wstawiania linków"; +$l['setting_allowlinkmycode_desc'] = "Ustawienie na 'Tak' pozwoli na wstawianie odnośników za pomocą MyCode."; +$l['setting_allowemailmycode'] = "Pozwól na MyCode wstawiania adresów e-mail"; +$l['setting_allowemailmycode_desc'] = "Ustawienie na 'Tak' pozwoli na wstawianie adresów e-mail za pomocą MyCode."; +$l['setting_allowalignmycode'] = "Pozwól na MyCode wyrównywania tekstu"; +$l['setting_allowalignmycode_desc'] = "Ustawienie na 'Tak' pozwoli na wyrównywanie tekstu za pomocą MyCode."; +$l['setting_allowlistmycode'] = "Pozwól na MyCode wstawiania list"; +$l['setting_allowlistmycode_desc'] = "Ustawienie na 'Tak' pozwoli na wstawianie list za pomocą MyCode."; +$l['setting_allowcodemycode'] = "Pozwól na MyCode wstawiania kodu"; +$l['setting_allowcodemycode_desc'] = "Ustawienie na 'Tak' pozwoli na wstawianie kodu i kolorowanie składni za pomocą MyCode."; +$l['setting_allowsymbolmycode'] = "Pozwól na MyCode wstawiania symboli"; +$l['setting_allowsymbolmycode_desc'] = "Ustawienie na 'Tak' pozwoli na wstawianie symboli (tm), (c) oraz (r) do tekstu za pomocą MyCode."; +$l['setting_allowmemycode'] = "Pozwól na MyCode używania komend"; +$l['setting_allowmemycode_desc'] = "Ustawienie na 'Tak' pozwoli na używanie komend typu /me oraz /slap w tekście za pomocą MyCode."; +$l['setting_guestimages'] = "Parsuj MyCode [img] gościom"; +$l['setting_guestimages_desc'] = "Ustawienie na 'Tak' spowoduje wyświetlanie gościom forum sparsowanych postów zawierających obrazy. W przeciwnym wypadku goście zobaczą jedynie odnośniki."; +$l['setting_guestvideos'] = "Parsuj MyCode [video] gościom"; +$l['setting_guestvideos_desc'] = "Ustawienie na 'Tak' spowoduje wyświetlanie gościom forum sparsowanych postów zawierających wideo. W przeciwnym wypadku goście zobaczą jedynie odnośniki."; + +$l['setting_contact'] = "Włącz formularz kontaktowy"; +$l['setting_contact_desc'] = "Czy chcesz włączyć dostęp do formularza kontaktowego na swoim forum?"; +$l['setting_contact_badwords'] = "Włącz filtrowanie wiadomości formularza"; +$l['setting_contact_badwords_desc'] = "Czy chcesz włączyć filtrowanie tematu oraz treści wiadomości formularza kontaktowego przez system cenzury niechcianych słów?"; +$l['setting_contact_maxsubjectlength'] = "Maksymalna długość tematu wiadomości formularza"; +$l['setting_contact_maxsubjectlength_desc'] = "Maksymalna liczba znaków w temacie umożliwiająca wysłanie wiadomości. Wpisanie 0 spowoduje całkowite zniesienie ograniczenia."; +$l['setting_contact_minmessagelength'] = "Minimalna długość treści wiadomości formularza"; +$l['setting_contact_minmessagelength_desc'] = "Minimalna liczba znaków w treści umożliwiająca wysłanie wiadomości. Wpisanie 0 spowoduje całkowite zniesienie ograniczenia."; +$l['setting_contact_maxmessagelength'] = "Maksymalna długość treści wiadomości formularza"; +$l['setting_contact_maxmessagelength_desc'] = "Maksymalna liczba znaków w treści umożliwiająca wysłanie wiadomości. Wpisanie 0 spowoduje całkowite zniesienie ograniczenia."; + +$l['setting_purgespammergroups'] = "Uprawnione grupy"; +$l['setting_purgespammergroups_desc'] = "Wybierz grupy uprawnione do korzystania z systemu usuwania spamerów."; +$l['setting_purgespammerpostlimit'] = "Limit postów"; +$l['setting_purgespammerpostlimit_desc'] = "Ta opcja uniemożliwia korzystanie z narzędzia wobec aktywnych użytkowników, posiadających liczbę postów większą od podanej poniżej. Wpisanie 0 spowoduje całkowite wyłączenie sprawdzania postów, przy czym jest to niezalecane."; +$l['setting_purgespammerbandelete'] = "Banuj lub usuwaj spamerów"; +$l['setting_purgespammerbandelete_desc'] = "Czy chcesz, aby spamerzy odnalezieni przez narzędzie byli banowani, czy usuwani?"; +$l['setting_purgespammerbandelete_ban'] = "Banuj (permanentnie)"; +$l['setting_purgespammerbandelete_delete'] = "Usuwaj"; +$l['setting_purgespammerbangroup'] = "Grupa zbanowanych użytkowników"; +$l['setting_purgespammerbangroup_desc'] = "Wpisz ID (nie nazwę) grupy użytkowników, do której mają trafiać zbanowani spamerzy. Domyślnie ustawione na 7, jako standardowy numer grupy zbanowanych użytkowników. Poprzednia opcja musi być ustawiona na 'Banuj', aby to ustawienie zadziałało prawidłowo."; +$l['setting_purgespammerbanreason'] = "Powód bana"; +$l['setting_purgespammerbanreason_desc'] = "Wpisz powód, który ma być wyświetlany po zbanowaniu spamera."; +$l['setting_purgespammerapikey'] = "Klucz API systemu Stop Forum Spam"; +$l['setting_purgespammerapikey_desc'] = "Aby korzystać z możliwości przesyłania informacji o spamerach do bazy systemu Stop Forum Spam, musisz posiadać odpowiedni klucz API. Możesz go zdobyć tutaj. Jeśli już takowy posiadasz, wstaw go w pole poniżej."; + +$l['setting_enablestopforumspam_on_register'] = "Sprawdzać rejestracje w bazie StopForumSpam.com?"; +$l['setting_enablestopforumspam_on_register_desc'] = "Czy chcesz, aby każda nowa rejestracja na forum była sprawdzana w bazie StopForumSpam.com?"; +$l['setting_stopforumspam_on_contact'] = "Sprawdzać wiadomości formularza kontaktowego od gości w bazie StopForumSpam?"; +$l['setting_stopforumspam_on_contact_desc'] = "Czy chcesz, aby adresy e-mail oraz IP gości wysyłających wiadomości za pomocą formularza kontaktowego były sprawdzane w bazie StopForumSpam?"; +$l['setting_stopforumspam_on_newreply'] = "Sprawdzać odpowiedzi gości w bazie StopForumSpam?"; +$l['setting_stopforumspam_on_newreply_desc'] = "Czy chcesz, aby loginy oraz IP gości tworzących nowe odpowiedzi były sprawdzane w bazie StopForumSpam?"; +$l['setting_stopforumspam_on_newthread'] = "Sprawdzać wątki gości w bazie StopForumSpam?"; +$l['setting_stopforumspam_on_newthread_desc'] = "Czy chcesz, aby loginy oraz IP gości tworzących nowe wątki były sprawdzane w bazie StopForumSpam?"; +$l['setting_stopforumspam_min_weighting_before_spam'] = "Minimalna ocena oznaczająca spamera"; +$l['setting_stopforumspam_min_weighting_before_spam_desc'] = "Minimalna ocena pobrana z systemu StopForumSpam decydująca o oznaczeniu użytkownika jako spamera. Liczba powinna mieścić się w przedziale od 0 do 100."; +$l['setting_stopforumspam_check_usernames'] = "Sprawdzać loginy?"; +$l['setting_stopforumspam_check_usernames_desc'] = "Czy chcesz, aby loginy użytkowników były sprawdzane w bazie StopForumSpam?"; +$l['setting_stopforumspam_check_emails'] = "Sprawdzać adresy e-mail?"; +$l['setting_stopforumspam_check_emails_desc'] = "Czy chcesz, aby adresy e-mail użytkowników były sprawdzane w bazie StopForumSpam?"; +$l['setting_stopforumspam_check_ips'] = "Sprawdzać adresy IP?"; +$l['setting_stopforumspam_check_ips_desc'] = "Czy chcesz, aby adresy IP użytkowników były sprawdzane w bazie StopForumSpam?"; +$l['setting_stopforumspam_block_on_error'] = "Blokować w przypadku błędu StopForumSpam?"; +$l['setting_stopforumspam_block_on_error_desc'] = "Czy blokować użytkownika w przypadku zwrócenia podczas pobierania informacji z API StopForumSpam błędu?"; +$l['setting_stopforumspam_log_blocks'] = "Zapisywać blokowania StopForumSpam?"; +$l['setting_stopforumspam_log_blocks_desc'] = "Czy zapisywać każde blokowanie spamera przez system StopForumSpam w logach forum?"; + +$l['setting_allowicqfield'] = "Pozwalaj na pole numeru ICQ"; +$l['setting_allowicqfield_desc'] = "Wybierz grupy użytkowników, które mogą używać pola z numerem ICQ w swoich informacjach kontaktowych."; +$l['setting_allowaimfield'] = "Pozwalaj na pole nazwy użytkownika AIM"; +$l['setting_allowaimfield_desc'] = "Wybierz grupy użytkowników, które mogą używać pola z nazwą użytkownika AIM w swoich informacjach kontaktowych."; +$l['setting_allowyahoofield'] = "Pozwalaj na pole identyfikatora Yahoo"; +$l['setting_allowyahoofield_desc'] = "Wybierz grupy użytkowników, które mogą używać pola z identyfikatorem Yahoo w swoich informacjach kontaktowych."; +$l['setting_allowskypefield'] = "Pozwalaj na pole identyfikatora Skype"; +$l['setting_allowskypefield_desc'] = "Wybierz grupy użytkowników, które mogą używać pola z identyfikatorem Skype w swoich informacjach kontaktowych."; +$l['setting_allowgooglefield'] = "Pozwalaj na pole identyfikatora Google Talk"; +$l['setting_allowgooglefield_desc'] = "Wybierz grupy użytkowników, które mogą używać pola z identyfikatorem Google Talk w swoich informacjach kontaktowych."; + +$l['setting_statsenabled'] = "Włącz stronę statystyk"; +$l['setting_statsenabled_desc'] = "Czy chcesz włączyć dostęp do strony ze statystykami forum?"; +$l['setting_statscachetime'] = "Częstotliwość odświeżania"; +$l['setting_statscachetime_desc'] = "Wpisz okres (w godzinach), co jaki odświeżane mają być składowane statystyki. Ustawienie na 0 spowoduje wyłączenie przechowywania statystyk w pamięci podręcznej."; \ No newline at end of file diff --git a/Upload/inc/languages/polish/admin/config_smilies.lang.php b/Upload/inc/languages/polish/admin/config_smilies.lang.php new file mode 100644 index 0000000..401d3cf --- /dev/null +++ b/Upload/inc/languages/polish/admin/config_smilies.lang.php @@ -0,0 +1,64 @@ +{theme}. W jego miejsce podstawiony zostanie katalog z obrazkami danego stylu."; +$l['order'] = "Kolejność"; +$l['display_order'] = "Kolejność wyświetlania"; +$l['display_order_desc'] = "Kolejność, w której ten emotikon pojawi się na liście emotikonów. Ta liczba nie powinna być taka sama jak innego emotikona."; +$l['mass_edit_show_clickable'] = "Pokazywać na liście?"; +$l['show_clickable'] = "Pokazywać na liście emotikonów?"; +$l['show_clickable_desc'] = "Czy chcesz, aby ten emotikon był pokazywany na liście emotikonów do wyboru w edytorze postów?"; +$l['include'] = "Dodać?"; +$l['path_to_images'] = "Ścieżka do obrazków"; +$l['path_to_images_desc'] = "To jest ścieżka do folderu, w którym znajdują się emotikony."; +$l['smilie_delete'] = "Usunąć?"; +$l['save_smilie'] = "Zapisz emotikon"; +$l['save_smilies'] = "Zapisz emotikony"; +$l['show_smilies'] = "Pokaż emotikony"; +$l['reset'] = "Resetuj"; + +$l['error_missing_name'] = "Nie wpisano nazwy dla tego emotikona."; +$l['error_missing_text_replacement'] = "Nie wpisano tekstu do zamiany dla tego emotikona."; +$l['error_missing_path'] = "Nie wpisano ścieżki do tego emotikona."; +$l['error_missing_path_multiple'] = "Nie wpisano ścieżki."; +$l['error_missing_order'] = "Nie wpisano kolejności wyświetlania tego emotikona."; +$l['error_duplicate_order'] = "Nie wpisano prawidłowej kolejności wyświetlania tego emotikona."; +$l['error_missing_clickable'] = "Nie wybrano czy ten emotikon ma być pokazywany na liście emotikonów"; +$l['error_no_smilies'] = "Nie ma emotikonów w podanym folderze lub wszystkie zostały już dodane."; +$l['error_no_images'] = "Nie ma żadnych obrazków w podanym katalogu."; +$l['error_none_included'] = "Nie wybrano żadnych emotikonów do dołączenia."; +$l['error_invalid_path'] = "Nie wpisano poprawnej ścieżki."; +$l['error_invalid_smilie'] = "Podany emotikon nie istnieje."; + +$l['success_smilie_added'] = "Emotikon został dodany."; +$l['success_multiple_smilies_added'] = "Wybrane emotikony zostały dodane."; +$l['success_smilie_updated'] = "Emotikon został zaktualizowany."; +$l['success_multiple_smilies_updated'] = "Emotikony zostały zaktualizowane."; +$l['success_smilie_deleted'] = "Wybrany emotikon został usunięty."; +$l['success_mass_edit_updated'] = "Emotikony zostały zaktualizowane."; + +$l['confirm_smilie_deletion'] = "Czy na pewno chcesz usunąć tego emotikona?"; diff --git a/Upload/inc/languages/polish/admin/config_spiders.lang.php b/Upload/inc/languages/polish/admin/config_spiders.lang.php new file mode 100644 index 0000000..d0b01f2 --- /dev/null +++ b/Upload/inc/languages/polish/admin/config_spiders.lang.php @@ -0,0 +1,42 @@ +Wysłanych załączników"; +$l['space_used'] = "Miejsce używane przez załączniki"; +$l['bandwidth_used'] = "Szacowane zużycie transferu przez załączniki"; +$l['average_size'] = "Średni rozmiar załącznika"; +$l['size'] = "Rozmiar"; +$l['posted_by'] = "Wysłany przez"; +$l['thread'] = "Wątek"; +$l['downloads'] = "Ilość pobrań"; +$l['date_uploaded'] = "Data wysłania"; +$l['popular_attachments'] = "5 najpopularniejszych załączników"; +$l['largest_attachments'] = "5 największych załączników"; +$l['users_diskspace'] = "5 użytkowników używających najwięcej miejsca na załączniki"; +$l['username'] = "Użytkownik"; +$l['total_size'] = "Używane miejsce"; + +// = Orphans +$l['orphan_results'] = "Wyszukiwanie nieużywanych załączników - wyniki"; +$l['orphan_attachments_search'] = "Wyszukiwanie nieużywanych załączników"; +$l['reason_orphaned'] = "Dlaczego nieużywany?"; +$l['reason_not_in_table'] = "Brak informacji w tabeli załączników"; +$l['reason_file_missing'] = "Brak załączonego pliku"; +$l['reason_thread_deleted'] = "Wątek został usunięty"; +$l['reason_post_never_made'] = "Post jeszcze nie powstał"; +$l['unknown'] = "Nieznany"; +$l['results'] = "Wyniki"; +$l['step1'] = "Krok 1"; +$l['step2'] = "Krok 2"; +$l['step1of2'] = "Krok 1 z 2 - skanowanie systemu plików"; +$l['step2of2'] = "Krok 2 z 2 - skanowanie bazy danych"; +$l['step1of2_line1'] = "Proszę czekać, system plików jest skanowany w poszukiwaniu nieużywanych załączników."; +$l['step2of2_line1'] = "Proszę czekać, baza danych jest skanowana w poszukiwaniu nieużywanych załączników."; +$l['step_line2'] = "Po zakończeniu procesu nastąpi przeniesienie do kolejnego kroku."; +$l['scanning'] = 'Skanowanie...'; + +// = Attachments / Index +$l['index_find_attachments'] = "Załączniki - szukanie"; +$l['find_where'] = "Znajdź załączniki, dla których..."; +$l['name_contains'] = "Nazwa pliku zawiera"; +$l['name_contains_desc'] = "Użyj \"*\", by zastąpić dowolny ciąg znaków. Przykład: *.zip"; +$l['type_contains'] = "Typ pliku zawiera"; +$l['forum_is'] = "Kategoria, dział, poddział"; +$l['username_is'] = "Użytkownik"; +$l['more_than'] = "większa niż"; +$l['greater_than'] = "większa niż"; +$l['is_exactly'] = "równa"; +$l['less_than'] = "mniejsza niż"; +$l['date_posted_is'] = "Data wysyłania jest"; +$l['days_ago'] = "dni temu"; +$l['file_size_is'] = "Wielkość pliku jest"; +$l['kb'] = "KB"; +$l['download_count_is'] = "Ilość pobrań jest"; +$l['display_options'] = "Opcje wyświetlania wyników"; +$l['filename'] = "nazwy pliku"; +$l['filesize'] = "rozmiaru pliku"; +$l['download_count'] = "ilości pobrań"; +$l['post_username'] = "autora postu"; +$l['asc'] = "rosnącej"; +$l['desc'] = "malejącej"; +$l['sort_results_by'] = "Sortowanie wyników według"; +$l['results_per_page'] = "Wyników na stronę"; +$l['in'] = "w kolejności"; + +// Buttons +$l['button_delete_orphans'] = "Usuń wybrane załączniki"; +$l['button_delete_attachments'] = "Usuń wybrane załączniki"; +$l['button_find_attachments'] = "Znajdź załączniki"; diff --git a/Upload/inc/languages/polish/admin/forum_management.lang.php b/Upload/inc/languages/polish/admin/forum_management.lang.php new file mode 100644 index 0000000..6989978 --- /dev/null +++ b/Upload/inc/languages/polish/admin/forum_management.lang.php @@ -0,0 +1,280 @@ +Pamiętaj jednak, że nie zmienia to uprawnień grupy - ta dalej może posiadać możliwość moderacji."; +$l['success_forum_permissions_updated'] = "Ustawienia uprawnień zostały zaktualizowane."; +$l['success_forum_updated'] = "Ustawienia działu zostały zaktualizowane."; +$l['success_moderator_updated'] = "Ustawienia moderatora zostały zaktualizowane."; +$l['success_custom_permission_cleared'] = "Niestandardowe uprawnienia zostały usunięte."; + +$l['error_invalid_forum'] = "Wybierz prawidłowy dział."; +$l['error_invalid_moderator'] = "Wybierz prawidłowego moderatora do usunięcia."; +$l['error_invalid_fid'] = "Wybrano nieprawidłowe ID działu."; +$l['error_forum_parent_child'] = "Dział nie może być jednocześnie nadrzędny i podrzędny względem innego. Wybierz inny dział nadrzędny."; +$l['error_forum_parent_itself'] = "Dział nie może być nadrzędny sam dla siebie."; +$l['error_incorrect_moderator'] = "Wybierz prawidłowego moderatora."; + +$l['confirm_moderator_deletion'] = "Czy na pewno chcesz usunąć tego moderatora z wybranego działu?"; +$l['confirm_forum_deletion'] = "Czy na pewno chcesz usunąć ten dział?"; +$l['confirm_clear_custom_permission'] = "Czy na pewno chcesz usunąć niestandardowe uprawnienia?"; + +$l['forum_type'] = "Typ działu"; +$l['forum_type_desc'] = "Wybierz typ działu, który tworzysz - dział, w którym można tworzyć wątki i pisać posty, czy kategoria, w której będą umieszczone inne działy."; +$l['category'] = "Kategorię"; +$l['title'] = "Tytuł"; +$l['description'] = "Opis"; +$l['save_forum'] = "Zapisz dział"; +$l['parent_forum'] = "Dział nadrzędny"; +$l['parent_forum_desc'] = "Dział nadrzędny dla tego, który właśnie tworzysz. Kategorie nie muszą posiadać działu nadrzędnego - w tym przypadku wybierz \"brak\"."; +$l['none'] = "brak"; +$l['display_order'] = "Kolejność wyświetlania"; + +$l['show_additional_options'] = "Wyświetl dodatkowe opcje"; +$l['hide_additional_options'] = "Ukryj dodatkowe opcje"; +$l['additional_forum_options'] = "Dodatkowe opcje działu"; +$l['forum_link'] = "Link do działu"; +$l['forum_link_desc'] = "Jeżeli chcesz, by link do działu był przekierowaniem w inne miejsce, podaj tutaj URL lokalizacji docelowej. Wypełnienie tego pola wyłączy funkcjonalność działu - nie będzie można w nim tworzyć wątków ani pisać postów. Mimo to, będzie istniała możliwość ustalenia uprawnień grupom."; +$l['forum_password'] = "Hasło działu"; +$l['forum_password_desc'] = "By lepiej zabezpieczyć dział, możesz ustalić hasło, którego podanie będzie niezbędne, by uzyskać dostęp. Uwaga: ustawienia uprawnień nadal będą brane pod uwagę."; +$l['access_options'] = "Ustawienia dostępu"; +$l['forum_is_active'] = "Dział jest aktywny?"; +$l['forum_is_active_desc'] = "Jeżeli nie, dział nie będzie wyświetlany użytkownikom."; +$l['forum_is_open'] = "Dział jest otwarty?"; +$l['forum_is_open_desc'] = "Jeżeli nie, użytkownicy nie będą mogli pisać nowych postów w tym dziale, niezależnie od przydzielonych im uprawnień."; + +$l['copy_to_new_forum'] = "Kopiuj do nowego działu"; +$l['source_forum'] = "Dział źródłowy"; +$l['source_forum_desc'] = "Dział, z którego zostaną skopiowane ustawienia i/lub uprawnienia."; +$l['destination_forum'] = "Dział docelowy"; +$l['destination_forum_desc'] = "Dział, do którego zostaną skopiowane ustawienia i/lub uprawnienia związane z działem źródłowym."; +$l['new_forum_settings'] = "Ustawienia nowego działu"; +$l['copy_settings_and_properties'] = "Kopiuj ustawienia i właściwości działu"; +$l['copy_settings_and_properties_desc'] = "Ma znaczenie jedynie wtedy, gdy dział docelowy już istnieje."; +$l['copy_user_group_permissions'] = "Kopiuj ustawienia uprawnień dla grup"; +$l['copy_user_group_permissions_desc'] = "Przytrzymaj CTRL by wybrać wiele grup."; + +$l['override_user_style'] = "Odbierz użytkownikowi możliwość wyboru stylu w tym dziale"; +$l['style_options'] = "Opcje stylu"; +$l['forum_specific_style'] = "Styl działu:"; +$l['use_default'] = "Użyj domyślnego"; +$l['dont_display_rules'] = "Nie wyświetlaj zasad dla tego działu"; +$l['display_rules_inline'] = "Wyświetlaj zasady dla tego działu na liście wątków"; +$l['display_rules_inline_new'] = "Wyświetlaj zasady dla tego działu na liście wątków oraz dla nowych wątków i postów"; +$l['display_rules_link'] = "Wyświetlaj osobny link do zasad dla tego działu"; +$l['display_method'] = "Tryb wyświetlania:"; +$l['rules'] = "Zasady:"; +$l['forum_rules'] = "Zasady dla tego działu"; +$l['name'] = "Nazwa"; +$l['username'] = "Login"; +$l['moderator_username_desc'] = "Login użytkownika, który ma zostać moderatorem"; +$l['add_user_as_moderator'] = "Dodaj użytkownika jako moderatora"; +$l['usergroup'] = "Grupa użytkowników"; +$l['add_usergroup_as_moderator'] = "Dodaj grupę użytkowników jako moderatora"; +$l['moderator_usergroup_desc'] = "Wybierz grupę, która zostanie dodana jako moderator działu"; +$l['add_usergroup_moderator'] = "Dodaj grupę użytkowników jako moderatora"; +$l['add_user_moderator'] = "Dodaj moderatora"; + +$l['default_view_options'] = "Domyślne opcje widoku"; +$l['default_date_cut'] = "Domyślny limit daty:"; +$l['default_sort_by'] = "Domyślne sortowanie wg:"; +$l['default_sort_order'] = "Domyślna kolejność:"; + +$l['board_default'] = "Użyj ustawień domyślnych forum"; + +$l['datelimit_1day'] = "Ostatni dzień"; +$l['datelimit_5days'] = "Ostatnie 5 dni"; +$l['datelimit_10days'] = "Ostatnie 10 dni"; +$l['datelimit_20days'] = "Ostatnie 20 dni"; +$l['datelimit_50days'] = "Ostatnie 50 dni"; +$l['datelimit_75days'] = "Ostatnie 75 dni"; +$l['datelimit_100days'] = "Ostatnie 100 dni"; +$l['datelimit_lastyear'] = "Ostatni rok"; +$l['datelimit_beginning'] = "Bez limitu"; + +$l['sort_by_subject'] = "Tytułu wątku"; +$l['sort_by_lastpost'] = "Daty ostatniego posta"; +$l['sort_by_starter'] = "Nicka założyciela"; +$l['sort_by_started'] = "Daty utworzenia"; +$l['sort_by_rating'] = "Oceny wątku"; +$l['sort_by_replies'] = "Liczby odpowiedzi"; +$l['sort_by_views'] = "Liczby wyświetleń"; + +$l['sort_order_asc'] = "Rosnąco"; +$l['sort_order_desc'] = "Malejąco"; + +$l['misc_options'] = "Różne opcje"; +$l['allow_html'] = "Włącz HTML w postach"; +$l['allow_mycode'] = "Włącz MyCode w postach"; +$l['allow_smilies'] = "Włącz emotikony w postach"; +$l['allow_img_code'] = "Włącz kod IMG w postach (wymaga włączonego kodu MyCode)"; +$l['allow_video_code'] = "Włącz kod [video] w postach (wymaga włączonego kodu MyCode)"; +$l['allow_post_icons'] = "Włącz możliwość wyboru ikonek postów"; +$l['allow_thread_ratings'] = "Włącz możliwość oceniania tematów"; +$l['show_forum_jump'] = "Wyświetl dział w na liście \"Skocz do...\""; +$l['use_postcounts'] = "Dodawaj posty napisane w tym dziale do liczników postów użytkowników"; +$l['use_threadcounts'] = "Dodawaj wątki napisane w tym dziale do liczników wątków użytkowników"; +$l['require_thread_prefix'] = "Wymagaj posiadania prefiksu przez każdy wątek"; + +$l['use_permissions'] = "Użyj ustawień uprawnień"; +$l['use_permissions_desc'] = "Wybierz ustawienia uprawnień, które mają być używane dla tej grupy - dziedziczone lub własne."; +$l['inherit_permissions'] = "Użyj ustawień domyślnych lub dziedziczonych z działu nadrzędnego"; +$l['custom_permissions'] = "Użyj własnych ustawień (poniższych)"; +$l['custom_permissions_for'] = "Niestandardowe uprawnienia dla"; + +$l['inherited_permission'] = "dziedziczone"; +$l['custom_permission'] = "niestandardowe"; + +$l['save_permissions'] = "Zapisz ustawienia uprawnień"; + +$l['error_missing_title'] = "Musisz podać tytuł."; +$l['error_no_parent'] = "Musisz wybrać dział nadrzędny."; +$l['error_not_empty'] = "Działy, w których znajdują się wątki, nie mogą zostać zamienione w kategorie."; +$l['error_forum_link_not_empty'] = "Działy, w których znajdują się wątki, nie mogą przekierowywać do innych stron."; + +$l['success_forum_added'] = "Dział został utworzony."; +$l['success_moderator_added'] = "Moderator został dodany."; +$l['success_forum_permissions_saved'] = "Ustawienia uprawnień zostały zaktualizowane."; +$l['success_forum_copied'] = "Dział został skopiowany."; + +$l['error_moderator_already_added'] = "Wskazany użytkownik lub wybrana grupa jest już moderatorem tego działu."; +$l['error_moderator_not_found'] = "Podany login lub wybrana grupa nie istnieje."; +$l['error_new_forum_needs_name'] = "Nie podano nazwy nowego działu."; +$l['error_invalid_source_forum'] = "Nieprawidłowy dział źródłowy."; +$l['error_invalid_destination_forum'] = "Nieprawidłowy dział docelowy."; + +$l['group_viewing'] = "Przeglądanie"; +$l['group_posting_rating'] = "Pisanie i ocenianie"; +$l['group_editing'] = "Edycja"; +$l['group_moderate'] = "Moderacja"; +$l['group_polls'] = "Ankiety"; +$l['group_misc'] = "Różne"; + +$l['viewing_field_canview'] = "Może przeglądać dział?"; +$l['viewing_field_canviewthreads'] = "Może przeglądać wątki w dziale?"; +$l['viewing_field_canonlyviewownthreads'] = "Może przeglądać tylko własne wątki?"; +$l['viewing_field_candlattachments'] = "Może pobierać załączniki?"; + +$l['posting_rating_field_canpostthreads'] = "Może tworzyć wątki?"; +$l['posting_rating_field_canpostreplys'] = "Może pisać odpowiedzi?"; +$l['posting_rating_field_canonlyreplyownthreads'] = "Może odpowiadać tylko w swoich wątkach?"; +$l['posting_rating_field_canpostattachments'] = "Może wysyłać załączniki?"; +$l['posting_rating_field_canratethreads'] = "Może oceniać tematy?"; + +$l['editing_field_caneditposts'] = "Może edytować własne posty?"; +$l['editing_field_candeleteposts'] = "Może usuwać własne posty?"; +$l['editing_field_candeletethreads'] = "Może usuwać własne wątki?"; +$l['editing_field_caneditattachments'] = "Może aktualizować własne załączniki?"; + +$l['moderate_field_modposts'] = "Nowe posty są moderowane?"; +$l['moderate_field_modthreads'] = "Nowe wątki są moderowane?"; +$l['moderate_field_modattachments'] = "Nowe załączniki są moderowane"; +$l['moderate_field_mod_edit_posts'] = "Posty po edycji są moderowane?"; + +$l['polls_field_canpostpolls'] = "Może tworzyć ankiety?"; +$l['polls_field_canvotepolls'] = "Może głosować w ankietach?"; + +$l['misc_field_cansearch'] = "Może korzystać z wyszukiwarki?"; + diff --git a/Upload/inc/languages/polish/admin/forum_moderation_queue.lang.php b/Upload/inc/languages/polish/admin/forum_moderation_queue.lang.php new file mode 100644 index 0000000..f14c613 --- /dev/null +++ b/Upload/inc/languages/polish/admin/forum_moderation_queue.lang.php @@ -0,0 +1,49 @@ +{3} zapytań. Użycie pamięci: {4}"; + +// Login page +$l['enter_username_and_password'] = "Aby kontynuować, podaj swój {1} oraz hasło."; +$l['login_username'] = 'login'; +$l['login_email'] = 'adres e-mail'; +$l['login_username_and_password'] = 'login lub adres e-mail'; +$l['mybb_admin_login'] = "Panel administratora MyBB - logowanie"; +$l['return_to_forum'] = "Wróć do forum"; +$l['please_login'] = "Zaloguj się"; +$l['username'] = "Login:"; +$l['username1'] = "Adres e-mail:"; +$l['username2'] = "Login/Adres e-mail:"; +$l['password'] = "Hasło:"; +$l['secret_pin'] = "Tajny PIN:"; +$l['login'] = "Zaloguj"; +$l['lost_password'] = "Nie pamiętam hasła"; + +$l['error_invalid_admin_session'] = "Niepoprawna sesja administratora"; +$l['error_admin_session_expired'] = "Sesja wygasła"; +$l['error_invalid_ip'] = "Twój adres IP nie pasuje do tej sesji"; +$l['error_mybb_admin_lockedout'] = "To konto zostało zablokowane"; +$l['error_mybb_admin_lockedout_message'] = "Konto zostało zablokowane po {1} nieudanych próbach logowania. Na Twój adres e-mail została wysłana wiadomość z instrukcjami jak odblokować swoje konto."; +$l['error_invalid_secret_pin'] = 'Wpisałeś niepoprawny numer PIN.'; + +$l['error_invalid_username'] = "Podany login jest niepoprawny."; +$l['error_invalid_uid'] = "Podany ID użytkownika jest niepoprawny."; +$l['error_invalid_token'] = "Podany kod aktywacyjny jest niepoprawny."; + +$l['success_logged_out'] = "Wylogowano z forum."; +$l['error_invalid_username_password'] = "Podano nieprawidłowy {1} lub hasło."; + +// Action Confirmation +$l['confirm_action'] = "Czy na pewno chcesz wykonać tę czynność?"; + +// Common words and phrases +$l['home'] = "Strona główna"; +$l['name'] = "Nazwa"; +$l['size'] = "Rozmiar"; +$l['controls'] = "Możliwości"; // pomarańczka +$l['view'] = "Podgląd"; +$l['yes'] = "Tak"; +$l['no'] = "Nie"; +$l['cancel'] = "Anuluj"; +$l['options'] = "Opcje"; +$l['proceed'] = "Kontynuuj"; +$l['ok'] = "OK"; +$l['error'] = "Błąd"; +$l['edit'] = "Edytuj"; +$l['never'] = "Nigdy"; +$l['legend'] = "Legenda"; +$l['version'] = "Wersja"; +$l['languagevar'] = "Język"; +$l['use_default'] = "Użyj domyślnych ustawień"; +$l['file'] = "Plik"; +$l['go'] = "OK"; +$l['clear'] = "Wyczyść"; +$l['unknown'] = "Nieznane"; +$l['year'] = "Rok"; +$l['year_short'] = "r"; +$l['years'] = "Lat"; +$l['years_short'] = "l"; +$l['month'] = "Miesiąc"; +$l['month_short'] = "m"; +$l['months'] = "Miesięcy"; +$l['months_short'] = "m"; +$l['week'] = "Tydzień"; +$l['week_short'] = "tydz"; +$l['weeks'] = "Tygodni"; +$l['weeks_short'] = "tyg"; +$l['day'] = "Dzień"; +$l['day_short'] = "d"; +$l['days'] = "Dni"; +$l['days_short'] = "d"; +$l['hour'] = "Godzina"; +$l['hour_short'] = "h"; +$l['hours'] = "Godzin"; +$l['hours_short'] = "h"; +$l['minute'] = "Minuta"; +$l['minute_short'] = "m"; +$l['minutes'] = "Minut"; +$l['minutes_short'] = "m"; +$l['second'] = "Sekunda"; +$l['second_short'] = "s"; +$l['seconds'] = "Sekund"; +$l['seconds_short'] = "s"; +$l['permanent'] = "Na zawsze"; +$l['all_forums'] = "Wszystkie działy"; +$l['all_groups'] = "Wszystkie grupy"; +$l['select_forums'] = "Wybierz działy"; +$l['select_groups'] = "Wybierz grupy"; +$l['forums_colon'] = "Działy:"; +$l['groups_colon'] = "Grupy:"; +$l['none'] = "Żadne"; +$l['mybb_acp'] = "MyBB ACP"; +$l['pages'] = "Stron"; +$l['previous'] = "Wstecz"; +$l['page'] = "Strona"; +$l['next'] = "Dalej"; +$l['delete'] = "Usuń"; +$l['reset'] = "Resetuj"; +$l['and'] = "i"; +$l['on'] = "Tak"; +$l['off'] = "Nie"; +$l['alt_enabled'] = "Włączone"; +$l['alt_disabled'] = "Wyłączone"; +$l['saved'] = 'Zapisano'; + +$l['rel_in'] = ""; +$l['rel_ago'] = "temu"; +$l['rel_less_than'] = "Mniej niż "; +$l['rel_time'] = "{1}{2} {3} {4}"; +$l['rel_minutes_single'] = "minuta"; +$l['rel_minutes_plural'] = "minut(y)"; +$l['rel_hours_single'] = "godzina"; +$l['rel_hours_plural'] = "godzin(y)"; + +// Parser bits +$l['quote'] = "Cytat:"; +$l['wrote'] = "napisał(a):"; +$l['code'] = "Kod:"; +$l['php_code'] = "Kod PHP:"; +$l['linkback'] = "Cytowana wypowiedź"; + +// The months of the year +$l['january'] = "Styczeń"; +$l['february'] = "Luty"; +$l['march'] = "Marzec"; +$l['april'] = "Kwiecień"; +$l['may'] = "Maj"; +$l['june'] = "Czerwiec"; +$l['july'] = "Lipiec"; +$l['august'] = "Sierpień"; +$l['september'] = "Wrzesień"; +$l['october'] = "Październik"; +$l['november'] = "Listopad"; +$l['december'] = "Grudzień"; + +// Access Denied +$l['access_denied'] = "Dostęp zabroniony"; +$l['access_denied_desc'] = "Twoje uprawnienia nie pozwalają na dostęp do tej części panelu administratora."; + +// Super Administrator required +$l['cannot_perform_action_super_admin_general'] = "Wskazana czynność może zostać wykonana tylko i wyłącznie przez super administratora.

    Jeżeli chcesz zostać super administratorem, dopisz swoje ID użytkownika w odpowiednie miejsce w pliku inc/config.php."; + +// AJAX +$l['loading_text'] = "Åadowanie
    ProszÄ™ czekać..."; + +// Time zone selection boxes +$l['timezone_gmt_minus_1200'] = "(GMT -12:00) Wyspy Marshalla"; +$l['timezone_gmt_minus_1100'] = "(GMT -11:00) Wyspa Midway, Nome"; +$l['timezone_gmt_minus_1000'] = "(GMT -10:00) Hawaje, Papeete"; +$l['timezone_gmt_minus_950'] = "(GMT -9:30) Markizy"; +$l['timezone_gmt_minus_900'] = "(GMT -9:00) Alaska"; +$l['timezone_gmt_minus_800'] = "(GMT -8:00) Czas pacyficzny (USA i Kanada)"; +$l['timezone_gmt_minus_700'] = "(GMT -7:00) Czas górski (USA i Kanada)"; +$l['timezone_gmt_minus_600'] = "(GMT -6:00) Czas Å›rodkowy (USA i Kanada)"; +$l['timezone_gmt_minus_500'] = "(GMT -5:00) Czas wschodni (USA i Kanada)"; +$l['timezone_gmt_minus_450'] = "(GMT -4:30) Caracas"; +$l['timezone_gmt_minus_400'] = "(GMT -4:00) Czas atlantycki (Kanada), La Paz, Halifax"; +$l['timezone_gmt_minus_350'] = "(GMT -3:30) Nowa Funlandia"; +$l['timezone_gmt_minus_300'] = "(GMT -3:00) Brazylia, Buenos Aires, Georgetown"; +$l['timezone_gmt_minus_200'] = "(GMT -2:00) Åšrodkowy Atlantyk, Georgia PoÅ‚udniowa i Sandwich PoÅ‚udniowy"; +$l['timezone_gmt_minus_100'] = "(GMT -1:00) Azory, Wyspy Zielonego PrzylÄ…dka"; +$l['timezone_gmt'] = "(GMT) Casablanca, Dublin, Edinburgh, Londyn, Lizbona, Monrovia"; +$l['timezone_gmt_100'] = "(GMT +1:00) Berlin, Bruksela, Kopenhaga, Madryt, Paryż, Rzym, Warszawa"; +$l['timezone_gmt_200'] = "(GMT +2:00) Ateny, StambuÅ‚, Kair, Jerozolima, PoÅ‚udniowa Afryka"; +$l['timezone_gmt_300'] = "(GMT +3:00) Kaliningrad, MiÅ„sk, Bagdad, Riad, Moskwa, Nairobi"; +$l['timezone_gmt_350'] = "(GMT +3:30) Teheran"; +$l['timezone_gmt_400'] = "(GMT +4:00) Moskwa, Abu Dhabi, Baku, Maskat, Tbilisi"; +$l['timezone_gmt_450'] = "(GMT +4:30) Kabul"; +$l['timezone_gmt_500'] = "(GMT +5:00) Islamabad, Karaczi, Taszkient"; +$l['timezone_gmt_550'] = "(GMT +5:30) Bombaj, Kalkuta, Madras, Nowe Delhi"; +$l['timezone_gmt_575'] = "(GMT +5:45) Katmandu"; +$l['timezone_gmt_600'] = "(GMT +6:00) AÅ‚ma-ata, Dhakra, Jekaterinburg"; +$l['timezone_gmt_650'] = "(GMT +6:30) Rangun"; +$l['timezone_gmt_700'] = "(GMT +7:00) Bangkok, Hanoi, Dżakarta"; +$l['timezone_gmt_800'] = "(GMT +8:00) Pekin, Hongkong, Perth, Singapur, Taipei"; +$l['timezone_gmt_900'] = "(GMT +9:00) Osaka, Sapporo, Seul, Tokio, Irkuck"; +$l['timezone_gmt_950'] = "(GMT +9:30) Adelajda, Darwin"; +$l['timezone_gmt_1000'] = "(GMT +10:00) Melbourne, Papua Nowa Gwinea, Sydney, Jakuck"; +$l['timezone_gmt_1050'] = "(GMT +10:30) Wyspa Lord Howe"; +$l['timezone_gmt_1100'] = "(GMT +11:00) Magadan, Nowa Kaledonia, Wyspy Salomona, WÅ‚adywostok"; +$l['timezone_gmt_1150'] = "(GMT +11:30) Wyspa Norfolk"; +$l['timezone_gmt_1200'] = "(GMT +12:00) Auckland, Wellington, Fidżi, Wyspa Marshalla"; +$l['timezone_gmt_1275'] = "(GMT +12:45) Wyspy Chatham"; +$l['timezone_gmt_1300'] = "(GMT +13:00) Samoa, Tonga, Tokelau"; +$l['timezone_gmt_1400'] = "(GMT +14:00) Wyspy Line"; +$l['timezone_gmt_short'] = "GMT {1}({2})"; + +// Global language strings used for log deletion pages +$l['confirm_delete_logs'] = "Czy na pewno chcesz usunąć wybrane wpisy?"; +$l['confirm_delete_all_logs'] = "Czy na pewno chcesz usunąć wszystkie wpisy?"; +$l['selected_logs_deleted'] = "Wybrane wpisy zostaÅ‚y usuniÄ™te."; +$l['all_logs_deleted'] = "Wszystkie wpisy zostaÅ‚y usuniÄ™te."; +$l['delete_selected'] = "UsuÅ„ wybrane"; +$l['delete_all'] = "UsuÅ„ wszystkie wyÅ›wietlone"; + +// Misc +$l['encountered_errors'] = "WystÄ…piÅ‚y nastÄ™pujÄ…ce problemy:"; +$l['invalid_post_verify_key'] = "Wykryto nieprawidÅ‚owy kod autoryzacji. Musisz potwierdzić chęć wykonania tej czynnoÅ›ci."; +$l['invalid_post_verify_key2'] = "Wykryto nieprawidÅ‚owy kod autoryzacji. Sprawdź czy odwiedzasz tÄ™ stronÄ™ z poprawnego odnoÅ›nika."; +$l['unknown_error'] = "WystÄ…piÅ‚ nieznany bÅ‚Ä…d."; + +// Code buttons editor language strings +$l['editor_bold'] = "Pogrubienie"; +$l['editor_italic'] = "Kursywa"; +$l['editor_underline'] = "PodkreÅ›lenie"; +$l['editor_strikethrough'] = "PrzekreÅ›lenie"; +$l['editor_subscript'] = "Indeks dolny"; +$l['editor_superscript'] = "Indeks górny"; +$l['editor_alignleft'] = "Wyrównaj do lewej"; +$l['editor_center'] = "WyÅ›rodkuj"; +$l['editor_alignright'] = "Wyrównaj do prawej"; +$l['editor_justify'] = "Wyjustuj"; +$l['editor_fontname'] = "Nazwa czcionki"; +$l['editor_fontsize'] = "Rozmiar czcionki"; +$l['editor_fontcolor'] = "Kolor czcionki"; +$l['editor_removeformatting'] = "UsuÅ„ formatowanie"; +$l['editor_cut'] = "Wytnij"; +$l['editor_copy'] = "Kopiuj"; +$l['editor_paste'] = "Wklej"; +$l['editor_cutnosupport'] = "Twoja przeglÄ…darka nie obsÅ‚uguje wycinania. Skorzystaj ze skrótu klawiszowego Ctrl/Cmd+X."; +$l['editor_copynosupport'] = "Twoja przeglÄ…darka nie obsÅ‚uguje kopiowania. Skorzystaj ze skrótu klawiszowego Ctrl/Cmd+C."; +$l['editor_pastenosupport'] = "Twoja przeglÄ…darka nie obsÅ‚uguje wklejania. Skorzystaj ze skrótu klawiszowego Ctrl/Cmd+V."; +$l['editor_pasteentertext'] = "Wklej swój tekst do poniższego pola:"; +$l['editor_pastetext'] = "Wklej tekst"; +$l['editor_numlist'] = "Lista numerowana"; +$l['editor_bullist'] = "Lista punktowana"; +$l['editor_undo'] = "Cofnij"; +$l['editor_redo'] = "Ponów"; +$l['editor_rows'] = "Wierszy:"; +$l['editor_cols'] = "Kolumn:"; +$l['editor_inserttable'] = "Wstaw tabelÄ™"; +$l['editor_inserthr'] = "Wstaw poziomÄ… liniÄ™"; +$l['editor_code'] = "Kod"; +$l['editor_php'] = "Kod PHP"; +$l['editor_width'] = "Szerokość (opcjonalnie):"; +$l['editor_height'] = "Wysokość (opcjonalnie):"; +$l['editor_insertimg'] = "Wstaw obrazek"; +$l['editor_email'] = "Adres e-mail:"; +$l['editor_insertemail'] = "Wstaw adres e-mail"; +$l['editor_url'] = "Adres URL:"; +$l['editor_insertlink'] = "Wstaw link"; +$l['editor_unlink'] = "UsuÅ„ link"; +$l['editor_more'] = "WiÄ™cej"; +$l['editor_insertemoticon'] = "Wstaw emotikon"; +$l['editor_videourl'] = "Adres URL wideo:"; +$l['editor_videotype'] = "Typ wideo:"; +$l['editor_insert'] = "Wstaw"; +$l['editor_insertyoutubevideo'] = "Wstaw wideo z serwisu YouTube"; +$l['editor_currentdate'] = "Wstaw aktualnÄ… datÄ™"; +$l['editor_currenttime'] = "Wstaw aktualny godzinÄ™"; +$l['editor_print'] = "Drukuj"; +$l['editor_viewsource'] = "Pokaż źródÅ‚o"; +$l['editor_description'] = "Opis (opcjonalnie):"; +$l['editor_enterimgurl'] = "Wprowadź adres URL obrazka:"; +$l['editor_enteremail'] = "Wprowadź adres e-mail:"; +$l['editor_enterdisplayedtext'] = "Wpisz tekst z obrazka:"; +$l['editor_enterurl'] = "Wprowadź adres URL:"; +$l['editor_enteryoutubeurl'] = "Wprowadź adres URL wideo lub jego ID:"; +$l['editor_insertquote'] = "Wstaw cytat"; +$l['editor_invalidyoutube'] = "NieprawidÅ‚owe wideo"; +$l['editor_dailymotion'] = "Dailymotion"; +$l['editor_metacafe'] = "MetaCafe"; +$l['editor_veoh'] = "Veoh"; +$l['editor_vimeo'] = "Vimeo"; +$l['editor_youtube'] = "Youtube"; +$l['editor_facebook'] = "Facebook"; +$l['editor_liveleak'] = "LiveLeak"; +$l['editor_insertvideo'] = "Wstaw wideo"; +$l['editor_maximize'] = "Maksymalizuj"; + +$l['missing_task'] = "BÅ‚Ä…d: plik zadania nie istnieje"; +$l['task_backup_cannot_write_backup'] = "BÅ‚Ä…d: zadanie kopii zapasowych bazy danych nie ma uprawnieÅ„ do zapisu w katalogu kopii zapasowych."; +$l['task_backup_ran'] = "Zadanie kopii zapasowej bazy danych zostaÅ‚o wykonane."; +$l['task_checktables_ran'] = "Zadanie sprawdzania tabel zostaÅ‚o wykonane, nie znaleziono żadnych bÅ‚Ä™dów."; +$l['task_checktables_ran_found'] = "Uwaga: Zadanie sprawdzania tabel zostaÅ‚o wykonane, znaleziono i naprawiono {1} bÅ‚Ä™dów."; +$l['task_dailycleanup_ran'] = "Zadanie codziennego oczyszczania zostaÅ‚o wykonane."; +$l['task_hourlycleanup_ran'] = "Zadanie cogodzinnego oczyszczania zostaÅ‚o wykonane."; +$l['task_logcleanup_ran'] = "Zadanie oczyszczania logów zostaÅ‚o wykonane, stare logi zostaÅ‚y wyczyszczone."; +$l['task_promotions_ran'] = "Zadanie promocji zostaÅ‚o wykonane."; +$l['task_threadviews_ran'] = "Zadanie przeliczania wyÅ›wietleÅ„ tematów zostaÅ‚o wykonane."; +$l['task_usercleanup_ran'] = "Zadanie oczyszczania użytkowników zostaÅ‚o wykonane."; +$l['task_massmail_ran'] = "Zadanie masowego mailingu zostaÅ‚o wykonane."; +$l['task_userpruning_ran'] = "Zadanie czyszczenia użytkowników zostaÅ‚o wykonane."; +$l['task_delayedmoderation_ran'] = "Zadanie opóźnionej moderacji zostaÅ‚o wykonane."; +$l['task_massmail_ran_errors'] = "WystÄ…piÅ‚ jeden lub wiÄ™cej problemów podczas wysyÅ‚ania wiadomoÅ›ci do \"{1}\": +{2}"; +$l['task_versioncheck_ran'] = "Zadanie sprawdzania wersji zostaÅ‚o uruchomione."; +$l['task_versioncheck_ran_errors'] = "Nie można poÅ‚Ä…czyć siÄ™ z MyBB w celu sprawdzenia wersji."; +$l['task_recachestylesheets_ran'] = 'ZaÅ‚adowano do pamiÄ™ci cache {1} arkuszy stylów kaskadowych.'; + +$l['massmail_username'] = "Login"; +$l['email_addr'] = "Adres e-mail"; +$l['board_name'] = "Nazwa forum"; +$l['board_url'] = "Adres forum"; + +// Unlock ACP +$l['lockout_unlock'] = "Odblokuj panel administratora"; +$l['enter_username_and_token'] = "Podaj swój login oraz kod aktywacyjny aby kontynuować."; +$l['unlock_token'] = "Kod aktywacyjny:"; +$l['unlock_account'] = "Odblokuj konto"; + +// Email message for if an admin account has been locked out +$l['locked_out_subject'] = "Zablokowane konto administratora na forum {1}"; +$l['locked_out_message'] = "{1}, + +Twoje konto administratora na forum {2} zostaÅ‚o zablokowane po {3} nieudanych próbach logowania. + +Aby odblokować swoje konto, odwiedź poniższy odnoÅ›nik. + +{4}/{5}/index.php?action=unlock&uid={7}&token={6} + +Jeżeli powyższy odnoÅ›nik nie dziaÅ‚a, przejdź do + +{4}/{5}/index.php?action=unlock + +Dane potrzebne do odblokowania konta: +Login: {1} +Kod aktywacyjny: {6} + +DziÄ™kujemy, +Ekipa {2}"; + +$l['comma'] = ", "; + +// If the language string for "Username" is too cramped in the ACP Login box +// then use this to define how much larger you want the gap to be (in px) +// $l['login_field_width'] = "0"; + diff --git a/Upload/inc/languages/polish/admin/home_credits.lang.php b/Upload/inc/languages/polish/admin/home_credits.lang.php new file mode 100644 index 0000000..6692ade --- /dev/null +++ b/Upload/inc/languages/polish/admin/home_credits.lang.php @@ -0,0 +1,14 @@ +Sprawdź aktualizacje."; diff --git a/Upload/inc/languages/polish/admin/home_dashboard.lang.php b/Upload/inc/languages/polish/admin/home_dashboard.lang.php new file mode 100644 index 0000000..02127bb --- /dev/null +++ b/Upload/inc/languages/polish/admin/home_dashboard.lang.php @@ -0,0 +1,55 @@ +Sprawdź czy używasz najnowszej wersji MyBB - od ostatniego sprawdzenia minęło wiÄ™cej niż dwa tygodnie."; +$l['new_version_available'] = "Wersja MyBB, której używasz to {1}. Najnowsza wersja to: {2}."; +$l['version_check_description'] = "Tutaj możesz sprawdzić, czy używasz najnowszej wersji skryptu oraz przeczytać najnowsze wiadomoÅ›ci prosto ze Å›wiata MyBB."; +$l['latest_mybb_announcements'] = "WiadomoÅ›ci MyBB"; +$l['no_announcements'] = "Nie ma pobranych żadnych wiadomoÅ›ci. Sprawdź aktualizacje."; +$l['your_version'] = "Twoja wersja"; +$l['latest_version'] = "Ostatnia wersja"; +$l['update_forum'] = "Zaktualizuj swojÄ… wersjÄ™ MyBB do najnowszej przechodzÄ…c na stronÄ™ MyBB."; +$l['read_more'] = "Czytaj wiÄ™cej"; + +$l['success_up_to_date'] = "Gratulacje, używasz najnowszej wersji MyBB."; + +$l['error_out_of_date'] = "Twoja wersja MyBB jest nieaktualna."; +$l['error_communication'] = "WystÄ…piÅ‚ bÅ‚Ä…d podczas poÅ‚Ä…czenia z serwerem sprawdzania wersji. Spróbuj ponownie za kilka minut."; +$l['error_fetch_news'] = "Nie udaÅ‚o siÄ™ pobrać ostatnich wiadomoÅ›ci ze strony MyBB."; + +$l['news_description'] = "Najnowsze wiadomoÅ›ci z bloga MyBB."; + +$l['admin_notes_public'] = "Poniższe notatki sÄ… widoczne dla wszystkich administratorów."; +$l['admin_notes'] = "Notatki administratorów"; +$l['save_notes'] = "Zapisz"; + +$l['success_notes_updated'] = "Notatki zostaÅ‚y zaktualizowane."; diff --git a/Upload/inc/languages/polish/admin/home_module_meta.lang.php b/Upload/inc/languages/polish/admin/home_module_meta.lang.php new file mode 100644 index 0000000..6f50119 --- /dev/null +++ b/Upload/inc/languages/polish/admin/home_module_meta.lang.php @@ -0,0 +1,24 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/languages/polish/admin/style_module_meta.lang.php b/Upload/inc/languages/polish/admin/style_module_meta.lang.php new file mode 100644 index 0000000..8ecc7ab --- /dev/null +++ b/Upload/inc/languages/polish/admin/style_module_meta.lang.php @@ -0,0 +1,15 @@ +{1}\""; +$l['search_noresults_title'] = "Nie znaleziono szablonów o tytule \"{1}\""; +$l['default_templates'] = "Szablony domyÅ›lne"; + +$l['edit_template_breadcrumb'] = "Edycja szablonu: "; + +$l['global_templates'] = "Szablony globalne"; +$l['master_templates'] = "Szablony główne"; + +$l['not_used_by_any_themes'] = "Nieużywany przez żaden styl"; +$l['used_by'] = "Używany przez: "; +$l['used_by_all_themes'] = "Używany przez wszystkie style"; + +$l['expand_templates'] = "WyÅ›wietl szablony"; +$l['edit_template_set'] = "Edytuj paczkÄ™"; +$l['delete_template_set'] = "UsuÅ„ paczkÄ™"; +$l['empty_template_set'] = "Ta paczka nie zawiera szablonów."; + +$l['inline_edit'] = "Szybka edycja"; // towyleci w rc (komentarz z tÅ‚umaczenia 1.6.x) +$l['full_edit'] = "Edytuj"; // a to sie pewnie zmieni (j.w.) +$l['revert_to_orig'] = "Przywróć oryginaÅ‚"; +$l['delete_template'] = "UsuÅ„ szablon"; +$l['edit_in'] = "Edytuj w"; + +$l['group_calendar'] = "Kalendarz -"; +$l['group_forumdisplay'] = "Widok dziaÅ‚u -"; +$l['group_index'] = "Strona główna -"; +$l['group_error'] = "Informacja o bÅ‚Ä™dzie -"; +$l['group_memberlist'] = "Lista użytkowników -"; +$l['group_multipage'] = "Stronicowanie -"; +$l['group_private'] = "Prywatne wiadomoÅ›ci -"; +$l['group_portal'] = "Portal -"; +$l['group_postbit'] = "Opis posta -"; +$l['group_posticons'] = "Ikona postu -"; +$l['group_showthread'] = "Widok wÄ…tku -"; +$l['group_usercp'] = "Panel użytkownika -"; +$l['group_online'] = "Kto jest online -"; +$l['group_forumbit'] = "Opis dziaÅ‚u -"; +$l['group_editpost'] = "Edycja posta -"; +$l['group_forumjump'] = "Skocz do... -"; +$l['group_moderation'] = "Moderacja -"; +$l['group_nav'] = "Nawigacja -"; +$l['group_search'] = "Wyszukiwarka -"; +$l['group_showteam'] = "Ekipa forum -"; +$l['group_reputation'] = "Reputacja -"; +$l['group_newthread'] = "Nowy wÄ…tek -"; +$l['group_newreply'] = "Nowa odpowiedź -"; +$l['group_member'] = "PodglÄ…d profilu -"; +$l['group_warning'] = "System ostrzeżeÅ„ -"; +$l['group_global'] = "Globalne"; +$l['group_header'] = "Nagłówek -"; +$l['group_managegroup'] = "ZarzÄ…dzanie grupami -"; +$l['group_misc'] = "Różne"; +$l['group_modcp'] = "Panel moderatora -"; +$l['group_announcement'] = "OgÅ‚oszenie -"; +$l['group_polls'] = "Ankieta -"; +$l['group_post'] = "Post -"; +$l['group_printthread'] = "Wydruk tematu -"; +$l['group_report'] = "Raport -"; +$l['group_smilieinsert'] = "Okno z emotikonami -"; +$l['group_stats'] = "Statystyki -"; +$l['group_xmlhttp'] = "XMLHTTP -"; +$l['group_footer'] = "Stopka -"; +$l['group_video'] = "MyCode wideo -"; +$l['group_sendthread'] = "WyÅ›lij wÄ…tek"; + +$l['expand'] = "RozwiÅ„"; +$l['collapse'] = "ZwiÅ„"; + +$l['save_continue'] = "Zapisz i kontynuuj edycjÄ™"; +$l['save_close'] = "Zapisz i wróć do listy"; + +$l['template_name'] = "Nazwa szablonu"; +$l['template_name_desc'] = "Nazwa szablonu. Jeżeli zmienisz jÄ… domyÅ›lnemu szablonowi, twoja wersja zostanie zapisana jako kopia o zmienionej nazwie."; +$l['template_set_desc'] = "W której paczce ma siÄ™ znajdować ten szablon?"; + +$l['template_group_prefix'] = "Prefiks grupy szablonów"; +$l['template_group_prefix_desc'] = "Prefiks którym bÄ™dÄ… poprzedzone nazwy wszystkich szablonów z tej grupy. Nie może siÄ™ pokrywać z istniejÄ…cÄ… grupÄ… szablonów. PrzykÅ‚adowo, jeżeli szablony majÄ… siÄ™ nazywać hello_world, hello_foobar i hello_foo, jako prefiks wpisz hello."; +$l['template_group_title'] = "Nazwa grupy szablonów"; +$l['template_group_title_desc'] = "Wpisz nazwÄ™ dla tej grupy szablonów. BÄ™dzie ona pokazywana na liÅ›cie szablonów. PrzykÅ‚adowo, jeżeli prefiksem grupy szablonów jest hello, możesz tu wpisać Hello."; + +$l['edit_template_group'] = "Edytuj grupÄ™ szablonów"; +$l['editing_template_group'] = "Editowanie grupy szablonów: {1}"; +$l['delete_template_group'] = "UsuÅ„ grupÄ™ szablonów"; +$l['save_template_group'] = "Zapisz grupÄ™ szablonów"; + +$l['templates_the_same'] = "Wskazane przez Ciebie szablony sÄ… identyczne."; +$l['master_updated_ins'] = "W ten sposób oznaczono różnice pomiÄ™dzy poprzedniÄ… a aktualnÄ… wersjÄ…."; +$l['master_updated_del'] = "W ten sposób oznaczono miejsca, w których usuniÄ™to dokonane przez Ciebie zmiany."; +$l['template_diff_analysis'] = "Analiza różnic w szablonach"; +$l['search_names_header'] = "Wyszukiwanie szablonów o nazwach zawierajÄ…cych \"{1}\""; + +$l['updated_template_welcome1'] = "Edycja - pozwala na modyfikacjÄ™ wybranego szablonu celem dostosowania go do nowej wersji systemu."; +$l['updated_template_welcome2'] = "Przywracanie - powoduje utratÄ™ wszelkich wprowadzonych zmian, ale pozwala na przywrócenie domyÅ›lnego wyglÄ…du szablonu w przypadku awarii."; +$l['updated_template_welcome3'] = "PodglÄ…d różnic - wyÅ›wietla wszystkie zmiany, jakich dokonano w danym szablonie."; + +$l['no_global_templates'] = "Aktualnie nie ma globalnych szablonów."; +$l['no_updated_templates'] = "Å»aden szablon nie byÅ‚ modyfikowany od czasu ostatniej aktualizacji."; + +$l['confirm_template_set_deletion'] = "Czy na pewno chcesz usunąć tÄ™ paczkÄ™ szablonów?"; +$l['confirm_template_group_delete'] = "Czy na pewno chcesz usunąć tÄ™ grupÄ™ szablonów? Nie spowoduje to usuniÄ™cia szablonów należących do tej grupy."; +$l['confirm_template_deletion'] = "Czy na pewno chcesz usunąć ten szablon?"; +$l['confirm_template_revertion'] = "Czy na pewno chcesz przywrócić ten szablon do stanu domyÅ›lnego?"; + +$l['error_security_problem'] = "W tym szablonie zostaÅ‚a wykryta potencjalna luka bezpieczeÅ„stwa. Zweryfikuj szablon lub skontaktuj siÄ™ z twórcami MyBB w celu uzyskania pomocy."; +$l['error_missing_input'] = "Upewnij siÄ™, że wprowadzono wszystkie dane potrzebne do tej operacji (tid, sid)"; +$l['error_already_exists'] = "Podany tytuÅ‚ szablonu jest już w użyciu. Podaj inny tytuÅ‚."; +$l['error_invalid_template'] = "Wybierz poprawny szablon."; +$l['error_missing_set_title'] = "Podaj nazwÄ™ paczki."; +$l['error_invalid_input'] = "Upewnij siÄ™, że podano poprawne ID szablonu."; +$l['error_invalid_set'] = "Wybierz poprawnÄ… paczkÄ™."; +$l['error_invalid_template_set'] = "Wybrano niepoprawnÄ… paczkÄ™."; +$l['error_themes_attached_template_set'] = "Ta paczka nie może zostać usuniÄ™ta - znajdujÄ… siÄ™ w niej szablony, które sÄ… aktualnie w użyciu."; +$l['error_missing_group_prefix'] = "Podaj prefiks dla grupy szablonów."; +$l['error_missing_group_title'] = "Podaj nazwÄ™ dla tej grupy szablonów."; +$l['error_duplicate_group_prefix'] = "Podany prefiks jest już w użyciu. Podaj inny prefiks."; +$l['error_missing_template_group'] = "Nie znaleziono grupy szablonów o podanej nazwie."; +$l['error_default_template_group'] = "Nie możesz edytować i usuwać domyÅ›lnych grup szablonów."; + +$l['success_template_saved'] = "Szablon zostaÅ‚ zapisany."; +$l['success_template_deleted'] = "Szablon zostaÅ‚ usuniÄ™ty."; +$l['success_template_reverted'] = "Szablon zostaÅ‚ przywrócony."; +$l['success_template_set_saved'] = "Paczka szablonów zostaÅ‚a zapisana."; +$l['success_template_set_deleted'] = "Paczka szablonów zostaÅ‚a usuniÄ™ta."; +$l['success_template_group_saved'] = "Grupa szablonów zostaÅ‚a zapisana."; +$l['success_template_group_deleted'] = "Grupa szablonów zostaÅ‚Ä… usuniÄ™ta."; diff --git a/Upload/inc/languages/polish/admin/style_themes.lang.php b/Upload/inc/languages/polish/admin/style_themes.lang.php new file mode 100644 index 0000000..cc7e146 --- /dev/null +++ b/Upload/inc/languages/polish/admin/style_themes.lang.php @@ -0,0 +1,221 @@ +Paczki szablonów, arkusze CSS i inne ustawienia sÄ… kopiowane ze stylu głównego."; + +$l['import_a_theme'] = "Importuj styl"; +$l['import_a_theme_desc'] = "Zaimportuj styl z pliku znajdujÄ…cego siÄ™ na Twoim komputerze lub pod adresem URL."; + +$l['edit_stylesheets'] = "Edytuj arkusze CSS"; +$l['edit_stylesheets_desc'] = "Edytuj arkusze CSS używane w tym stylu. Arkusze CSS okreÅ›lajÄ… wyglÄ…d czcionek, kolory i inne wizualne aspekty forum. Poniżej znajduje siÄ™ lista arkuszy zwiÄ…zanych z tym stylem."; + +$l['add_stylesheet'] = "Nowy arkusz CSS"; +$l['add_stylesheet_desc'] = "Utwórz nowy arkusz CSS zwiÄ…zany z tym stylem, by uzyskać wiÄ™kszÄ… kontrolÄ™ nad jego wyglÄ…dem. Po utworzeniu arkusza rozpoczniesz jego edycjÄ™."; + +$l['browse_themes'] = "PrzeglÄ…daj style"; +$l['browse_themes_desc'] = "PrzeglÄ…daj style z oficjalnej strony z dodatkami do MyBB, które sÄ… kompatybilne z używanÄ… przez Ciebie wersjÄ… MyBB."; + +$l['browse_all_themes'] = "PrzeglÄ…daj wszystkie style"; + +$l['export_theme'] = "Eksportuj styl"; +$l['export_theme_desc'] = "Wyeksportuj styl i przypisane do niego modyfikacje szablonów. Pozwoli to przekazać innym efekty Twojej pracy i użyć tego stylu na innym forum."; + +$l['duplicate_theme'] = "Duplikuj styl"; +$l['duplicate_theme_desc'] = "Zduplikuj jeden z obecnie zainstalowanych stylów. Może to pomóc przy tworzeniu kolejnej wersji danego stylu."; + +$l['colors_manage'] = "ZarzÄ…dzaj kolorami"; +$l['colors_attached_to'] = "koloru"; +$l['colors_setting'] = "Kolor podstawowy"; +$l['colors_setting_desc'] = "Wybierz kolor, który ma być podstawowym dla tego wariantu. ZostanÄ… użyte arkusze stylów doÅ‚Ä…czone do tego stylu."; +$l['colors_no_color_setting'] = "Brak dostÄ™pnych kolorów. Aby skorzystać z tej funkcji, utwórz poniżej listÄ™ kolorów."; +$l['colors_add'] = "ZarzÄ…dzaj kolorami"; +$l['colors_add_desc'] = "Lista kolorów dostÄ™pnych w tym stylu. Powinny być one zapisane w formacie \"kolor=nazwa\", na przykÅ‚ad blue=Niebieski. Każdy kolor powinien siÄ™ znaleźć w nowej linii."; +$l['colors_please_select'] = "Brak"; +$l['colors_add_edit_desc'] = "Wybierz kolor, do którego ma być doÅ‚Ä…czony ten arkusz stylów. Możesz wybrać wiÄ™cej niż jeden."; +$l['colors_specific_color'] = "Specific color"; + +$l['include_custom_only'] = "DoÅ‚Ä…czyć tylko zmienione elementy?"; +$l['include_custom_only_desc'] = "Jeżeli chcesz doÅ‚Ä…czyć również te elementy (arkusze CSS itd.), które sÄ… kopiowane ze stylu głównego, wybierz \"Nie\". JeÅ›li nie wybierzesz tej opcji, wyeksportowane zostanÄ… jedynie elementy charakterystyczne dla tego stylu."; +$l['include_templates'] = "DoÅ‚Ä…czyć też szablony?"; +$l['include_templates_desc'] = "Jeżeli chcesz, by wyeksportowane zostaÅ‚y również zmodyfikowane szablony, wybierz \"Tak\"."; + +$l['edit_stylesheet_simple_mode'] = "Edytuj CSS: tryb uproszczony"; +$l['edit_stylesheet_simple_mode_desc'] = "Edytuj arkusz CSS przypisany do stylu. Tryb uproszczony pozwala na edytowanie kodu CSS nie wymagajÄ…c jego znajomoÅ›ci. Wybierz element z poniższej listy, aby rozpocząć."; +$l['edit_stylesheet_advanced_mode'] = "Edytuj CSS: tryb zaawansowany"; +$l['edit_stylesheet_advanced_mode_desc'] = "Edytuj arkusz CSS przypisany do stylu jak zwykÅ‚y plik tekstowy. PeÅ‚na zawartość arkusza widoczna jest w polu poniżej."; + +$l['theme'] = "Styl"; +$l['num_users'] = "Liczba użytkowników"; +$l['edit_theme'] = "Edytuj styl"; +$l['delete_theme'] = "UsuÅ„ styl"; +$l['set_as_default'] = "Ustaw jako domyÅ›lny"; +$l['default_theme'] = "Styl domyÅ›lny"; +$l['force_on_users'] = "WymuÅ› używanie"; +$l['delete_revert'] = "UsuÅ„ lub przywróć"; + +$l['local_file'] = "Plik z dysku"; +$l['url'] = "URL"; +$l['import_from'] = "Importuj z"; +$l['import_from_desc'] = "Wybierz plik, z którego zostanie zaimportowany nowy styl. Może to być plik znajdujÄ…cy siÄ™ na Twoim dysku lub pod podanym adresem URL."; +$l['parent_theme'] = "Styl główny"; +$l['parent_theme_desc'] = "Wybierz styl, z którego zostanÄ… skopiowane paczki szablonów, arkusze CSS i inne ustawienia."; +$l['new_name'] = "Nazwa"; +$l['new_name_desc'] = "Nazwa dla importowanego stylu. Jeżeli pozostawisz to pole puste, użyta zostanie nazwa pliku ze stylem."; +$l['advanced_options'] = "Opcje zaawansowane"; +$l['ignore_version_compatibility'] = "Ignoruj kompatybilność wersji"; +$l['ignore_version_compat_desc'] = "Wybierz tÄ™ opcjÄ™, jeÅ›li styl ma zostać zainstalowany pomimo ewentualnych niezgodnoÅ›ci wersji MyBB i tej, dla której zostaÅ‚ przeznaczony."; +$l['import_stylesheets'] = "Importuj arkusze CSS"; +$l['import_stylesheets_desc'] = "Wybierz tÄ™ opcjÄ™, jeÅ›li ten styl zawiera zmodyfikowane arkusze CSS i chcesz je zainstalować."; +$l['import_templates'] = "Importuj szablony"; +$l['import_templates_desc'] = "Wybierz tÄ™ opcjÄ™, jeÅ›li ten styl zawiera zmodyfikowane szablony i chcesz je zainstalować."; +$l['import_theme'] = "Importuj styl"; + +$l['new_name_duplicate_desc'] = "Nazwa nowego stylu, który ma być duplikatem."; +$l['duplicate_stylesheets'] = "Duplikuj arkusze stylów"; +$l['duplicate_stylesheets_desc'] = "Wybierz tÄ™ opcjÄ™, jeÅ›li ten styl zawiera zmodyfikowane arkusze CSS i chcesz je doÅ‚Ä…czyć do zduplikowanego stylu."; +$l['duplicate_templates'] = "Duplikuj szablony"; +$l['duplicate_templates_desc'] = "Wybierz tÄ™ opcjÄ™, jeÅ›li ten styl zawiera zmodyfikowane szablony i chcesz je doÅ‚Ä…czyć do zduplikowanego stylu."; + +$l['create_a_theme'] = "Nowy styl"; +$l['name'] = "Nazwa"; +$l['name_desc'] = "Podaj nazwÄ™ dla nowego stylu."; +$l['display_order'] = "Kolejność"; + +$l['edit_theme_properties'] = "Edycja wÅ‚aÅ›ciwoÅ›ci stylu"; +$l['name_desc_edit'] = "Podaj nazwÄ™ dla tego stylu."; +$l['allowed_user_groups'] = "Dopuszczone grupy użytkowników"; +$l['allowed_user_groups_desc'] = "Wybierz grupy użytkowników, które majÄ… prawo używać tego stylu. Jeżeli wybierzesz \"Wszystkie grupy\", inne wskazania nie bÄ™dÄ… mieć znaczenia. Przytrzymaj klawisz CTRL i klikaj, by wybrać wiÄ™cej niż jednÄ… grupÄ™."; +$l['all_user_groups'] = "Wszystkie grupy"; +$l['template_set'] = "Paczka szablonów"; +$l['template_set_desc'] = "Wybierz paczkÄ™ szablonów, która ma być używana przez ten styl. Wybrana paczka bÄ™dzie decydować o formie (HTML) wyÅ›wietlania danych przez ten styl."; +$l['editor_theme'] = "WyglÄ…d edytora"; +$l['editor_theme_desc'] = "Wybierz wyglÄ…d edytora MyCode, który ma być używany w tym stylu. WyglÄ…dy edytorów możesz znaleźć w katalogu jscripts/editor_themes."; +$l['img_directory'] = "Katalog obrazków"; +$l['img_directory_desc'] = "Åšcieżka do katalogu, w którym przechowywane bÄ™dÄ… obrazki zwiÄ…zane z tym stylem. PamiÄ™taj, że ten wpis ma zwiÄ…zek jedynie z obrazkami używanymi w szablonach, nie w arkuszach CSS."; +$l['logo'] = "Logo forum"; +$l['logo_desc'] = "Åšcieżka do obrazka z logiem forum używanym w tym stylu (jest to obrazek, który pojawia siÄ™ u góry każdej strony)."; +$l['table_spacing'] = "Cellpadding"; +$l['table_spacing_desc'] = "OdstÄ™p zawartoÅ›ci od brzegu komórek tabel, w pikselach. Jest to wartość atrybutu cellpadding w tagu table."; +$l['inner_border'] = "Cellspacing"; +$l['inner_border_desc'] = "OdstÄ™p pomiÄ™dzy komórkami tabel, w pikselach. Jest to wartość atrybutu cellspacing w tagu table."; +$l['save_theme_properties'] = "Zapisz wÅ‚aÅ›ciwoÅ›ci stylu"; +$l['save_stylesheet_order'] = "Zapisz kolejność arkuszy stylów"; + +$l['background'] = "TÅ‚o (background)"; +$l['extra_css_atribs'] = "Dodatkowe atrybuty CSS"; +$l['color'] = "Kolor (color)"; +$l['width'] = "Szerokość (width)"; +$l['text_decoration'] = "Dekoracja tekstu (text-decoration)"; +$l['font_family'] = "Rodzaj czcionki (font-family)"; +$l['font_size'] = "Rozmiar czcionki (font-size)"; +$l['font_style'] = "Styl czcionki (font-style)"; +$l['font_weight'] = "Waga czcionki (font-weight)"; + +$l['stylesheets'] = "Arkusze CSS"; +$l['inherited_from'] = "Dziedziczone z"; +$l['attached_to'] = "DoÅ‚Ä…czane do"; +$l['attached_to_nothing'] = "NiedoÅ‚Ä…czane do żadnego pliku"; +$l['attached_to_desc'] = "Możesz sprawić, by arkusze byÅ‚y doÅ‚Ä…czane tylko do wybranych plików, czy nawet tylko podczas konkretnych czynnoÅ›ci wykonywanych w tych plikach."; +$l['actions'] = "czynnoÅ›ci"; +$l['of'] = ""; +$l['attached_to_all_pages'] = "DoÅ‚Ä…czany do wszystkich stron"; +$l['properties'] = "WÅ‚aÅ›ciwoÅ›ci"; +$l['edit_style'] = "Edytuj styl"; +$l['stylesheets_in'] = "Arkusze CSS stylu"; +$l['stylesheet_properties'] = "WÅ‚aÅ›ciwoÅ›ci arkuszy CSS"; +$l['stylesheet_inherited_default'] = "Ten arkusz jest aktualnie dziedziczony od {1}. Jeżeli dokonasz jakichÅ› zmian, zostanie on skopiowany i przestanie być dziedziczony."; +$l['stylesheet_inherited'] = "Ten arkusz jest aktualnie dziedziczony od {1}. Jeżeli dokonasz jakichÅ› zmian, zostanie on skopiowany i przestanie być dziedziczony. Wyedytuj ten arkusz z poziomu stylu {1} by zachować dziedziczenie."; +$l['globally'] = "Do wszystkich"; +$l['specific_files'] = "Do wybranych plików"; +$l['specific_actions'] = "Do wybranych czynnoÅ›ci"; +$l['specific_actions_desc'] = "Kody czynnoÅ›ci, oddzielone przecinkami"; +$l['file'] = "Plik"; +$l['add_another'] = "Dodaj"; +$l['edit_stylesheet_properties_for'] = "Edytuj wÅ‚aÅ›ciwoÅ›ci arkusza"; +$l['file_name'] = "Nazwa pliku"; +$l['file_name_desc'] = "Nazwa arkusza, zwykle z rozszerzeniem .css"; +$l['save_stylesheet_properties'] = "Zapisz wÅ‚aÅ›ciwoÅ›ci arkusza"; +$l['saved'] = "Zapisano"; +$l['editing'] = "Edytowanie"; +$l['selector'] = "Selektor"; +$l['save_changes'] = "Zapisz zmiany"; +$l['save_changes_and_close'] = "Zapisz zmiany i zamknij"; +$l['save_changes_js'] = "Czy chcesz najpierw zapisać zmiany?"; +$l['delete_confirm_js'] = "Czy ma pewno chcesz to usunąć?"; +$l['import_stylesheet_from'] = "Importuj z innego arkusza w tym stylu"; +$l['write_own'] = "Wpisz podanÄ… przeze mnie zawartość"; +$l['save_stylesheet'] = "Zapisz arkusz"; +$l['add_stylesheet_to'] = "Dodaj arkusz do"; + +$l['full_stylesheet_for'] = "Zawartość arkusza"; + +$l['recommended_themes_for_mybb'] = "Zalecane style dla MyBB {1}"; +$l['browse_results_for_mybb'] = "PrzeglÄ…daj wyniki dla MyBB {1}"; +$l['search_for_themes'] = "Szukaj stylów"; +$l['search'] = "Szukaj"; +$l['download'] = "Pobierz"; +$l['created_by'] = "Autor"; + +$l['error_invalid_stylesheet'] = "Wybrano nieprawidÅ‚owy arkusz."; +$l['error_invalid_theme'] = "Wybrano nieprawidÅ‚owy styl."; +$l['error_missing_name'] = "Podaj nazwÄ™ stylu."; +$l['error_missing_url'] = "Podaj prawidÅ‚owy adres pliku do zaimportowania."; +$l['error_theme_already_exists'] = "Podana nazwa stylu jest już zajÄ™ta. Wpisz innÄ… nazwÄ™."; +$l['error_theme_security_problem'] = "W stylu zostaÅ‚a znaleziona potencjalna luka bezpieczeÅ„stwa, wiÄ™c nie zostaÅ‚ zaimportowany. Skontaktuj siÄ™ z autorem stylu bÄ…dź ekipÄ… MyBB w celu uzyskania pomocy."; + +$l['error_local_file'] = "Nie udaÅ‚o siÄ™ otworzyć pliku z dysku. Sprawdź, czy taki plik istnieje, i spróbuj ponownie."; +$l['error_uploadfailed'] = "WysyÅ‚anie nie powiodÅ‚o siÄ™. Spróbuj ponownie."; +$l['error_uploadfailed_detail'] = "Szczegóły bÅ‚Ä™du: "; +$l['error_uploadfailed_php1'] = "PHP zwróciÅ‚o: WysyÅ‚any plik przekroczyÅ‚ rozmiar ustalony w dyrektywie upload_max_filesize w php.ini. Skontaktuj siÄ™ w tej sprawie z administratorem serwera."; +$l['error_uploadfailed_php2'] = "WysyÅ‚any plik przekroczyÅ‚ dopuszczalny rozmiar pliku."; +$l['error_uploadfailed_php3'] = "Plik zostaÅ‚ tylko częściowo wysÅ‚any."; +$l['error_uploadfailed_php4'] = "Plik nie zostaÅ‚ wysÅ‚any."; +$l['error_uploadfailed_php6'] = "PHP zwróciÅ‚o: Brak folderu tymczasowego. Skontaktuj siÄ™ w tej sprawie z administratorem serwera."; +$l['error_uploadfailed_php7'] = "PHP zwróciÅ‚o: Zapis na dysk nieudany. Skontaktuj siÄ™ w tej sprawie z administratorem serwera."; +$l['error_uploadfailed_phpx'] = "PHP zwróciÅ‚o kod bÅ‚Ä™du: {1}. Skontaktuj siÄ™ w tej sprawie z administratorem serwera."; +$l['error_uploadfailed_lost'] = "Nie znaleziono pliku na serwerze."; +$l['error_uploadfailed_nocontents'] = "MyBB nie znalazÅ‚o danych dotyczÄ…cych stylu w przesÅ‚anym pliku. Upewnij siÄ™, czy plik nie jest uszkodzony."; +$l['error_invalid_version'] = "Ten styl zostaÅ‚ utworzony dla innej wersji MyBB. Zaznacz opcjÄ™ \"Ignoruj kompatybilność wersji\" by zignorować ten bÅ‚Ä…d."; +$l['error_missing_stylesheet_name'] = "Podaj nazwÄ™ dla tego arkusza."; +$l['error_missing_stylesheet_extension'] = "Arkusz stylów musi mieć poprawne rozszerzenie, na przykÅ‚ad {1}.css"; +$l['error_invalid_parent_theme'] = "Wybrany styl nadrzÄ™dny nie istnieje. Wybierz prawidÅ‚owy styl."; +$l['error_invalid_templateset'] = "Wybrana paczka szablonów nie istnieje. Wybierz prawidÅ‚owÄ… paczkÄ™."; +$l['error_invalid_editortheme'] = "Wybrany wyglÄ…d edytora nie istnieje. Wybierz prawidÅ‚owy wyglÄ…d."; +$l['error_inheriting_stylesheets'] = "Nie możesz usunąć tego stylu, bo niektóre spoÅ›ród innych stylów dziedziczÄ… od niego arkusze CSS."; +$l['error_cannot_parse'] = "MyBB nie potrafi przystosować tego arkusza CSS do edycji w trybie uproszczonym. DostÄ™pny jest jedynie tryb zaawansowany."; +$l['error_communication_problem'] = "WystÄ…piÅ‚ bÅ‚Ä…d podczas komunikacji z serwerem stylów dla MyBB. Spróbuj ponownie za kilka minut."; +$l['error_no_results_found'] = "Wyszukiwanie z podanymi sÅ‚owami kluczowymi nie zwróciÅ‚o żadnych wyników."; +$l['error_no_color_picked'] = "Nie wybrano kolorów, do których ma być doÅ‚Ä…czony ten arkusz CSS."; +$l['error_no_display_order'] = "WystÄ…piÅ‚ bÅ‚Ä…d podczas sprawdzania kolejnoÅ›ci wyÅ›wietlania arkuszy CSS. OdÅ›wież stronÄ™ i spróbuj ponownie."; + +$l['success_duplicated_theme'] = "Wybrany styl zostaÅ‚ zduplikowany."; +$l['success_imported_theme'] = "Wybrany styl zostaÅ‚ zaimportowany."; +$l['success_theme_created'] = "Styl zostaÅ‚ utworzony."; +$l['success_theme_deleted'] = "Wybrany styl zostaÅ‚ usuniÄ™ty."; +$l['success_stylesheet_properties_updated'] = "WÅ‚aÅ›ciwoÅ›ci wybranego arkusza CSS zostaÅ‚y zaktualizowane."; +$l['success_stylesheet_updated'] = "Wybrany arkusz CSS zostaÅ‚ zaktualizowany."; +$l['success_stylesheet_deleted'] = "Wybrany arkusz CSS zostaÅ‚ usuniÄ™ty lub przywrócony."; +$l['success_theme_set_default'] = "Wybrany styl staÅ‚ siÄ™ domyÅ›lnym."; +$l['success_theme_forced'] = "Wszyscy użytkownicy zostali zmuszeni do używania tego stylu."; +$l['success_theme_properties_updated'] = "WÅ‚aÅ›ciwoÅ›ci wybranego stylu zostaÅ‚y zaktualizowane."; +$l['success_stylesheet_added'] = "Arkusz CSS zostaÅ‚ utworzony."; +$l['success_stylesheet_order_updated'] = "Kolejność wyÅ›wietlania arkuszy CSS zostaÅ‚a zaktualizowana."; + +$l['confirm_theme_deletion'] = "Czy na pewno chcesz usunąć ten styl?"; +$l['confirm_stylesheet_deletion'] = "Czy na pewno chcesz usunąć lub przywrócić ten arkusz CSS?"; +$l['confirm_theme_forced'] = "Czy na pewno chcesz wymusić używanie tego stylu przez wszystkich użytkowników?"; + +$l['theme_info_fetch_error'] = 'WystÄ…piÅ‚ problem podczas pobierania informacji o stylu.'; +$l['theme_info_save_error'] = 'WystÄ…piÅ‚ problem podczas zapisywania informacji o stylu.'; + +$l['saving'] = 'Zapisywanie...'; + diff --git a/Upload/inc/languages/polish/admin/tools_adminlog.lang.php b/Upload/inc/languages/polish/admin/tools_adminlog.lang.php new file mode 100644 index 0000000..de6451b --- /dev/null +++ b/Upload/inc/languages/polish/admin/tools_adminlog.lang.php @@ -0,0 +1,292 @@ + Zauważ, że ten proces nie odróżnia zmian dokonanych przez Ciebie i uszkodzenia plików. Rozważ nadpisanie plików oznaczonych jako uszkodzone."; + +$l['error_communication'] = "WystÄ…piÅ‚ problem z komunikacjÄ… z serwerem MyBB. Spróbuj ponownie za kilka minut."; +$l['file'] = "Plik"; +$l['no_corrupt_files_found'] = "Nie znaleziono uszkodzonych plików."; +$l['found_problems'] = "Wykryte problemy"; +$l['no_problems_found'] = "Nie wykryto żadnych problemów"; +$l['changed'] = "Zmodyfikowany"; +$l['missing'] = "UsuniÄ™ty"; +$l['status'] = "Status"; diff --git a/Upload/inc/languages/polish/admin/tools_mailerrors.lang.php b/Upload/inc/languages/polish/admin/tools_mailerrors.lang.php new file mode 100644 index 0000000..61efa07 --- /dev/null +++ b/Upload/inc/languages/polish/admin/tools_mailerrors.lang.php @@ -0,0 +1,31 @@ +(wymaga serwera MySQL w wersji 5.5.3 lub nowszego)"; +$l['not_available'] = "NiedostÄ™pne"; +$l['all_tables'] = "Wszystkie tabele"; +$l['convert_now'] = "Konwertuj"; +$l['totals'] = "Ogólne"; +$l['attachments'] = "ZaÅ‚Ä…czniki"; +$l['total_database_size'] = "Rozmiar bazy danych"; +$l['attachment_space_used'] = "Miejsce używane przez zaÅ‚Ä…czniki"; +$l['total_cache_size'] = "Rozmiar pamiÄ™ci podrÄ™cznej"; +$l['estimated_attachment_bandwidth_usage'] = "Szacowane zużycie transferu przez zaÅ‚Ä…czniki"; +$l['max_upload_post_size'] = "Maksymalny rozmiar wysyÅ‚ki / rozmiar POST"; +$l['average_attachment_size'] = "Åšredni rozmiar zaÅ‚Ä…cznika"; +$l['stats'] = "Statystyki"; +$l['task'] = "Zadanie"; +$l['run_time'] = "Data wykonania"; +$l['next_3_tasks'] = "NastÄ™pne 3 zadania"; +$l['no_tasks'] = "Nie ma uruchomionych zadaÅ„."; +$l['backup_time'] = "Data utworzenia"; +$l['no_backups'] = "Nie ma kopii zapasowych bazy danych."; +$l['existing_db_backups'] = "Kopie zapasowe bazy danych"; +$l['writable'] = "Zapis możliwy"; +$l['not_writable'] = "Zapis niemożliwy"; +$l['please_chmod_777'] = "ZmieÅ„ CHMOD na 777."; +$l['chmod_info'] = "Dostosuj ustawienia CHMOD plików na serwerze do wymagaÅ„ okreÅ›lonych poniżej."; +$l['file'] = "Plik"; +$l['location'] = "Lokalizacja"; +$l['settings_file'] = "Plik ustawieÅ„"; +$l['config_file'] = "Plik konfiguracji"; +$l['file_upload_dir'] = "Katalog zaÅ‚Ä…czników"; +$l['avatar_upload_dir'] = "Katalog wysyÅ‚anych awatarów"; +$l['language_files'] = "Pliki tÅ‚umaczeÅ„"; +$l['backup_dir'] = "Katalog kopii bazy danych"; +$l['cache_dir'] = "Katalog pamiÄ™ci podrÄ™cznej"; +$l['themes_dir'] = "Katalog stylów"; +$l['chmod_files_and_dirs'] = "Uprawnienia CHMOD dla plików i katalogów"; + +$l['notice_process_long_time'] = "Proces konwersji może potrwać nawet kilka godzin, zależnie od rozmiaru bazy forum i iloÅ›ci tabel."; +$l['notice_mb4_warning'] = "ObsÅ‚uga 4-bajtowego kodowania UTF-8 wymaga serwera MySQL w wersji 5.5.3 lub nowszego. Nie bÄ™dzie możliwe zaimportowanie bazy danych na serwerze, który jest w wersji niższej niż 5.5.3."; + +$l['check_templates'] = "Zweryfikuj szablony"; +$l['check_templates_desc'] = "Sprawdź, czy wszystkie zainstalowane szablony nie majÄ… znanych luk bezpieczeÅ„stwa."; +$l['check_templates_title'] = "Zweryfikuj bezpieczeÅ„stwo szablonów"; +$l['check_templates_info'] = "Ten proces sprawdzi szablony pod kÄ…tem znanych luk bezpieczeÅ„stwa, które mogÄ… mieć wpÅ‚yw na silnik forum lub serwer. Może on potrwać trochÄ™ czasu, jeżeli posiadasz dużo zainstalowanych stylów. +

    Aby rozpocząć proces weryfikacji, naciśnij przycisk \"Kontynuuj\" poniżej."; +$l['check_templates_info_desc'] = "Poniższe szablony mogą zawierać znane luki bezpieczeństwa. Zweryfikuj je poniżej."; +$l['full_edit'] = "Pełna edycja"; + +$l['error_chmod'] = "plików lub katalogów nie spełnia wymagań CHMOD."; +$l['error_invalid_table'] = "Taka tabela nie istnieje."; +$l['error_db_encoding_not_set'] = "Twoje MyBB nie zostało jeszcze skonfigurowane, by używać tego narzędzia. Tutaj: href=\"http://docs.mybb.com/Utf8_setup.html\">Dokumentacja MyBB możesz dowiedzieć się jak to zrobić."; +$l['error_not_supported'] = "Twoja baza danych nie umożliwia użycia narzędzia konwersji do UTF-8."; +$l['error_invalid_input'] = "Podczas sprawdzania szablonów wystąpił błąd. Spróbuj ponownie lub skontaktuj się z twórcami MyBB w celu uzyskania pomocy."; +$l['error_master_templates_altered'] = "Główne szablony MyBB zostały zmodyfikowane. Skontaktuj się z twórcami MyBB w celu uzyskania pomocy jak odwrócić zmiany."; +$l['error_utf8mb4_version'] = "Używana przez ciebie wersja serwera MySQL nie wspiera 4-bajtowego kodowania UTF-8."; + + +$l['warning_multiple_encodings'] = "Nie jest zalecane używanie wielu sposobów kodowania znaków w bazie danych. Może to spowodować dziwne zachowanie skryptu lub błędy serwera MySQL."; +$l['warning_utf8mb4_config'] = "Dla pełnej obsługi 4-bajtowego kodowania UTF-8 konieczna jest zmiana wartości \$config['database']['encoding'] = 'utf8'; na \$config['database']['encoding'] = 'utf8mb4'; w pliku inc/config.php."; + +$l['success_templates_checked'] = "Szablony zostały sprawdzone - nie odnaleziono luk bezpieczeństwa."; +$l['success_all_tables_already_converted'] = "Wszystkie tabele zostały przekonwertowane lub już były w formacie UTF-8."; +$l['success_table_converted'] = "Tabela \"{1}\" została przekonwertowana do formatu UTF-8."; +$l['success_chmod'] = "Wszystkie pliki i katalogi mają odpowiednie uprawnienia CHMOD."; diff --git a/Upload/inc/languages/polish/admin/tools_tasks.lang.php b/Upload/inc/languages/polish/admin/tools_tasks.lang.php new file mode 100644 index 0000000..e08e7cf --- /dev/null +++ b/Upload/inc/languages/polish/admin/tools_tasks.lang.php @@ -0,0 +1,76 @@ +UWAGA: Chcesz aktywować zadanie, które powinno być uruchamiane tylko i wyłącznie za pomocą cron (zobacz Dokumentację MyBB - po angielsku). Kontynuować?"; +$l['no_tasks'] = "Nie ma zaplanowanych zadań na tym forum."; diff --git a/Upload/inc/languages/polish/admin/tools_warninglog.lang.php b/Upload/inc/languages/polish/admin/tools_warninglog.lang.php new file mode 100644 index 0000000..32e82e2 --- /dev/null +++ b/Upload/inc/languages/polish/admin/tools_warninglog.lang.php @@ -0,0 +1,52 @@ +
    Aby móc ją wykonać, dodaj swój identyfikator użytkownika do pliku inc/config.php.'; +$l['error_delete_no_uid'] = 'Nie wpisano identyfikatora uprawnień użytkownika/grupy'; +$l['error_delete_invalid_uid'] = 'Nie wpisano prawidłowego identyfikatora uprawnień użytkownika/grupy'; + +$l['success_perms_deleted'] = 'Uprawnienia dla użytkownika/grupy zostały cofnięte.'; + +$l['confirm_perms_deletion'] = "Czy na pewno chcesz cofnąć uprawnienia temu użytkownikowi/tej grupie?"; +$l['confirm_perms_deletion2'] = "Czy na pewno chcesz cofnąć uprawnienia temu użytkownikowi?"; diff --git a/Upload/inc/languages/polish/admin/user_banning.lang.php b/Upload/inc/languages/polish/admin/user_banning.lang.php new file mode 100644 index 0000000..32ed6a9 --- /dev/null +++ b/Upload/inc/languages/polish/admin/user_banning.lang.php @@ -0,0 +1,64 @@ +*"; +$l['autocomplete_enabled'] = "W tym polu aktywne jest autouzupełnianie."; +$l['ban_reason'] = "Powód bana"; +$l['ban_group'] = "Grupa zbanowanych*"; +$l['ban_group_desc'] = "W celu nadania bana dla tego użytkownika musi zostać przeniesiony do grupy zbanowanych."; +$l['ban_time'] = "Długość bana *"; + +//= Index +$l['user'] = "Użytkownik"; +$l['moderation'] = "Moderacja"; +$l['ban_lifts_on'] = "Ban zostanie zniesiony"; +$l['time_left'] = "Pozostało"; +$l['permenantly'] = "nigdy"; +$l['na'] = "Niedostępne"; +$l['for'] = "na okres:"; +$l['bannedby_x_on_x'] = "{1}
    Zbanowany przez {2} w dniu {3} ";// Usunięto w celach testowych{4} +$l['lift'] = "Usuń"; +$l['no_banned_users'] = "W tym momencie nie masz zbanowanych użytkowników."; +$l['prune_threads_and_posts'] = "Usuń wątki i posty"; + +// Buttons +$l['ban_user'] = "Zbanuj użytkownika"; +$l['update_ban'] = "Aktualizuj bana"; +$l['search_user'] = 'Szukaj użytkownika'; diff --git a/Upload/inc/languages/polish/admin/user_group_promotions.lang.php b/Upload/inc/languages/polish/admin/user_group_promotions.lang.php new file mode 100644 index 0000000..f257ac2 --- /dev/null +++ b/Upload/inc/languages/polish/admin/user_group_promotions.lang.php @@ -0,0 +1,91 @@ +Wpisz \"{username}\" zamiast loginu."; +$l['user_title'] = "Domyślny tytuł użytkownika"; +$l['user_title_desc'] = "Jeżeli użytkownik nie poda własnego tytułu użytkownika, zostanie wyświetlony podany tutaj tytuł. Jeżeli pozostawisz to pole puste, tytuł użytkownika oraz obrazek gwiazdki zostaną odziedziczone z konfiguracji elementu \"Tytuły użytkowników\""; +$l['do_not_copy_permissions'] = "Nie kopiuj uprawnień z innej grupy"; +$l['copy_permissions_from'] = "Skopiuj ustawienia uprawnień z..."; +$l['copy_permissions_from_desc'] = "Jeżeli chcesz, ustawienia uprawnień mogą zostać skopiowane z istniejącej już grupy użytkowników - wystarczy, że wybierzesz tę grupę."; +$l['save_user_group'] = "Zapisz grupę"; +$l['list_users'] = "Lista użytkowników"; + +$l['general'] = "Ogólne"; +$l['forums_posts'] = "Działy i posty"; +$l['users_permissions'] = "Użytkownicy i uprawnienia"; +$l['misc'] = "Różne"; +$l['mod_cp'] = "Panel moderatora"; +$l['stars'] = "Liczba gwiazdek"; +$l['star_image'] = "Obrazek gwiazdki"; +$l['user_stars'] = "Gwiazdki"; +$l['user_stars_desc'] = "Podaj liczbę gwiazdek i ścieżkę do obrazka, aby określić sposób, w jaki będą one wyświetlane dla tej grupy użytkowników. Jeżeli chcesz używać różnych obrazków dla poszczególnych stylów, wpisz {theme} by zastąpić ścieżkę do katalogu obrazków aktualnie używanego stylu. Liczba gwiazdek zostanie użyta, kiedy pole \"Domyślny tytuł użytkownika\" nie jest puste."; +$l['group_image'] = "Obrazek grupy"; +$l['group_image_desc'] = "Możesz wybrać obrazek, który będzie pokazywany przy każdym poście napisanym przez członków tej grupy. Wpisz {lang} by zastąpić nazwę aktualnie używanego języka."; +$l['general_options'] = "Ogólne opcje"; +$l['member_list'] = "Pokazuj użytkowników z tej grupy na liście użytkowników"; +$l['forum_team'] = "Wyświetlaj tę grupę na stronie \"Ekipa forum\""; +$l['is_banned_group'] = "Jest to grupa zbanowana
    Jeżeli określisz grupę jako \"zbanowaną\", to będziesz mógł banować użytkowników przez przeniesienie ich do tej grupy."; +$l['publicly_joinable_options'] = "Opcje dołączania"; +$l['user_joinable'] = "Użytkownicy mogą swobodnie dołączać i opuszczać grupę"; +$l['moderate_join_requests'] = "Wszystkie dołączenia do grupy muszą zostać zatwierdzone.
    Użytkownicy muszą mieć możliwość swobodnego dołączania i opuszczania grupy, aby działało to ustawienie."; +$l['invite_only'] = "Aby dołączyć do tej grupy należy otrzymać zaproszenie.
    Użytkownicy muszą mieć możliwość swobodnego dołączania i opuszczania grupy, aby działało to ustawienie."; +$l['can_set_as_display_group'] = "Użytkownicy mogą ustawiać tę grupę jako swoją grupę wyświetlaną
    Jeżeli \"Tak\", to użytkownicy będą mogli wybrać ustawienia wyświetlania tej grupy (tytuł użytkownika, gwiazdki, format loginu, obrazek grupy) jako swoje ustawienia wyświetlania."; +$l['moderation_administration_options'] = "Opcje moderacji i administracji"; +$l['is_super_mod'] = "Użytkownicy tej grupy są super moderatorami"; +$l['can_access_mod_cp'] = "Użytkownicy tej grupy mają dostęp do panelu moderatora"; +$l['can_access_admin_cp'] = "Użytkownicy tej grupy mają dostęp do panelu administratora"; +$l['viewing_options'] = "Opcje przeglądania"; +$l['can_view_board'] = "Mogą przeglądać forum?"; +$l['can_view_threads'] = "Mogą przeglądać wątki?"; +$l['can_search_forums'] = "Mogą przeszukiwać działy?"; +$l['can_view_profiles'] = "Mogą przeglądać profile użytkowników?"; +$l['can_download_attachments'] = "Mogą pobierać załączniki?"; +$l['can_view_board_closed'] = "Mogą przeglądać forum gdy jest zamknięte?"; +$l['posting_rating_options'] = "Opcje postów i oceniania"; +$l['moderation_options'] = "Opcje moderacji"; +$l['mod_new_posts'] = "Moderować nowe posty?"; +$l['mod_new_threads'] = "Moderować nowe wątki?"; +$l['mod_new_attachments'] = "Moderować nowe załączniki?"; +$l['mod_after_edit'] = "Moderować posty po edycji?"; +$l['can_post_threads'] = "Mogą tworzyć nowe wątki?"; +$l['can_post_replies'] = "Mogą odpowiadać w istniejących wątkach?"; +$l['can_rate_threads'] = "Mogą oceniać wątki?"; +$l['poll_options'] = "Opcje ankiet"; +$l['max_posts_per_day'] = "Maksymalna liczba postów na dzień"; +$l['max_posts_per_day_desc'] = "Ta opcja pozwala na ograniczenie liczby postów na dzień. Jeżeli nie chcesz ustalać limitu, wpisz 0."; +$l['can_post_polls'] = "Mogą tworzyć ankiety?"; +$l['can_vote_polls'] = "Mogą głosować w ankietach?"; +$l['can_undo_votes'] = "Mogą cofać swoje głosy w ankietach?"; +$l['attachment_options'] = "Opcje załączników"; +$l['can_post_attachments'] = "Mogą wysyłać załączniki?"; +$l['attach_quota'] = "Limit miejsca na załączniki:"; +$l['attach_quota_desc'] = "Możesz ustalić limit miejsca do wykorzystania na załączniki dla użytkowników z tej grupy. Jeżeli nie chcesz ustalać limitu, wpisz 0."; +$l['editing_deleting_options'] = "Opcje edycji i usuwania"; +$l['can_edit_posts'] = "Mogą edytować własne posty?"; +$l['can_delete_posts'] = "Mogą usuwać własne posty?"; +$l['can_delete_threads'] = "Mogą usuwać własne wątki?"; +$l['can_edit_attachments'] = "Mogą aktualizować własne załączniki?"; +$l['account_management'] = "Zarządzanie kontem"; +$l['edit_time_limit'] = "Ograniczenie czasu na edycję"; +$l['edit_time_limit_desc'] = "Jeżeli chcesz ograniczyć czasowo możliwość edytowania postów przez użytkowników z tej grupy (jeśli pozwalają im na to ustawienia grupy) wprowadź tutaj, przez jaki czas mają oni mieć taką możliwość (w minutach). Jeżeli nie chcesz ustalać limitu, wpisz 0."; +$l['can_be_reported'] = "Mogą być zgłaszani przez innych?"; +$l['can_access_usercp'] = "Mają dostęp do paneli użytkowników?"; +$l['can_change_username'] = "Mogą zmieniać swoje loginy?"; +$l['can_change_website'] = "Mogą zmieniać swoją stronę WWW?"; +$l['can_use_usertitles'] = "Mogą używać własnych tytułów użytkownika?"; +$l['can_upload_avatars'] = "Mogą wysyłać awatary?"; +$l['can_use_signature'] = "Mogą posiadać własną sygnaturę?"; +$l['can_use_signature_posts'] = "Mogą posiadać własną sygnaturę po napisaniu określonej liczby postów?"; +$l['required_posts'] = "Minimalna liczba postów wymagana do dodania sygnatury:"; +$l['required_posts_desc'] = "Podaj ile postów użytkownik musi napisać, zanim będzie mógł posiadać własną sygnaturę. Wpisz 0, aby każdy użytkownik tej grup mógł ustawić sygnaturę."; +$l['uses_no_follow'] = "Czy linki w sygnaturze powinny mieć włączony atrybut nofollow?"; +$l['reputation_system'] = "System reputacji"; +$l['can_use_pms'] = "Mogą używać prywatnych wiadomości?"; +$l['can_send_pms'] = "Mogą wysyłać prywatne wiadomości?"; +$l['can_track_pms'] = "Mogą śledzić wysłane prywatne wiadomości?"; +$l['can_deny_reciept'] = "Mogą odmówić potwierdzenia odbioru?"; +$l['can_override_pms'] = "Mogą wysyłać prywatne wiadomości do użytkowników, którzy mają wyłączony system PW?"; +$l['message_quota'] = "Limit wiadomości"; +$l['message_quota_desc'] = "Maksymalna liczba prywatnych wiadomości przechowywanych przez użytkowników z tej grupy. Podaj 0 by nie wprowadzać takiego limitu."; +$l['max_recipients'] = "Maksymalna liczba odbiorców na wiadomość"; +$l['max_recipients_desc'] = "Maksymalna liczba odbiorców, których można przypisać do pojedynczej prywatnej wiadomości. Podaj 0 by nie wprowadzać takiego limitu."; +$l['show_reputations'] = "Pokazywać wskaźnik reputacji dla tych użytkowników?"; +$l['can_give_reputation'] = "Mogą dawać punkty reputacji innym użytkownikom?"; +$l['points_to_award_take'] = "Liczba punktów do dodania/odjęcia:"; +$l['points_to_award_take_desc'] = "Liczba punktów, które zostaną dodane lub odjęte użytkownikowi w wyniku oceny przez użytkownika tej grupy."; +$l['max_reputations_daily'] = "Maksymalna liczba ocen na dzień:"; +$l['max_reputations_daily_desc'] = "Podaj, ile razy maksymalnie użytkownicy tej grupy mogą ocenić innych użytkowników na dzień. Podaj 0 by nie wprowadzać takiego limitu."; +$l['max_reputations_perthread'] = "Maksymalna liczba ocen na wątek:"; +$l['max_reputations_perthread_desc'] = "Podaj, ile razy maksymalnie użytkownik może ocenić danego użytkownika w jednym wątku. Podaj 0 by nie wprowadzać takiego limitu."; +$l['max_reputations_peruser'] = "Maksymalna liczba ocen na użytkownika:"; +$l['max_reputations_peruser_desc'] = "Podaj, ile razy maksymalnie użytkownicy tej grupy mogą ocenić jednego użytkownika na dzień. Podaj 0 by nie wprowadzać takiego limitu."; +$l['warning_system'] = "System ostrzeżeń"; +$l['can_send_warnings'] = "Mogą dodawać ostrzeżenia innym użytkownikom?"; +$l['can_receive_warnings'] = "Mogą otrzymywać ostrzeżenia od innych użytkowników?"; +$l['warnings_per_day'] = "Maksymalna liczba ostrzeżeń na dzień:"; +$l['private_messaging'] = "Prywatne wiadomości"; +$l['calendar'] = "Kalendarz"; +$l['can_view_calendar'] = "Mogą przeglądać kalendarz?"; +$l['can_post_events'] = "Mogą dodawać wydarzenia do kalendarza?"; +$l['can_bypass_event_moderation'] = "Mogą dodawać wydarzenia do kalendarza bez oczekiwania na moderację?"; +$l['can_moderate_events'] = "Mogą moderować wydarzenia kalendarza?"; +$l['whos_online'] = "\"Kto jest online\""; +$l['can_view_whos_online'] = "Mogą przeglądać listę \"Kto jest online\"?"; +$l['can_view_invisible'] = "Widzą niewidocznych użytkowników?"; +$l['can_view_ips'] = "Mogą przeglądać adresy IP na liście \"Kto jest online\"?"; +$l['can_view_member_list'] = "Mogą przeglądać listę użytkowników?"; +$l['show_in_birthday_list'] = "Mogą być wyświetlani na liście użytkowników obchodzących urodziny?"; +$l['can_email_users'] = "Mogą wysyłać wątki do znajomych i wysyłać e-maile do użytkowników?"; +$l['can_email_users_override'] = "Mogą wysyłać e-maile do użytkowników, nawet gdy nadawca znajduje się na liście ignorowanych przez adresata?"; +$l['max_emails_per_day'] = "Maksymalna liczba e-maili dziennie:"; +$l['max_emails_per_day_desc'] = "Maksymalna liczba e-maili jakie użytkownicy z tej grupy mogą wysłać przy użyciu opcji \"Wyślij wątek do znajomego\" i \"E-mail do użytkownika\". Podaj 0 by nie wprowadzać takiego limitu."; +$l['email_flood_time'] = "Opóźnienie pomiędzy wysyłanymi e-mailami"; +$l['email_flood_time_desc'] = "Liczba minut, jaką musi odczekać użytkownik po wysłaniu e-maila, aby móc wysłać kolejnego. Podaj 0 by nie wprowadzać takiego limitu."; +$l['forum_post_options'] = "Działy i posty"; +$l['user_options'] = "Użytkownicy"; +$l['can_manage_announce'] = "Może zarządzać ogłoszeniami?
    Zauważ, że moderatorzy muszą być przypisani przynajmniej do jednego działu, aby mogli zarządzać ogłoszeniami."; +$l['can_manage_mod_queue'] = "Może zarządzać kolejką moderacji?
    Zauważ, że moderatorzy muszą być przypisani przynajmniej do jednego działu, aby mogli zarządzać kolejką moderacji."; +$l['can_manage_reported_content'] = "Może zarządzać zgłoszeniami?
    Zauważ, że moderatorzy muszą być przypisani przynajmniej do jednego działu, aby mogli zarządzać zgłoszeniami."; +$l['can_view_mod_logs'] = "Może przeglądać wpisy w logach moderatorów?
    Zauważ, że moderatorzy muszą być przypisani przynajmniej do jednego działu, aby mogli przeglądać logi moderatorów."; +$l['can_edit_profiles'] = "Może edytować profile?
    Zauważ, że moderatorzy działów nie mogą edytować profili administratorów i super moderatorów, niezależnie od wartości tego ustawienia."; +$l['can_ban_users'] = "Może banować użytkowników?
    Zauważ, że moderatorzy działów nie mogą banować administratorów i super moderatorów, niezależnie od wartości tego ustawienia."; +$l['can_view_warnlogs'] = "Może przeglądać logi ostrzeżeń?"; +$l['can_use_ipsearch'] = "Może wyszukiwać po adresach IP?"; + +$l['outstanding_join_request'] = "oczekujących wniosków o przyjęcie"; + +$l['no_join_requests'] = "Aktualnie nie ma żadnych nierozpatrzonych wniosków o przyjęcie do grupy."; +$l['no_assigned_leaders'] = "Nie przypisano żadnych liderów tej grupie. By wybrać nowego lidera, wypełnij poniższy formularz."; + +$l['error_missing_title'] = "Nie nadano nazwy nowej grupie użytkowników."; +$l['error_invalid_user_group'] = "Wybrano niepoprawną grupę."; +$l['error_invalid_join_request'] = "Wybrano niepoprawny wniosek."; +$l['error_invalid_username'] = "Podany login jest nieprawidłowy."; +$l['error_already_leader'] = "Ten użytkownik jest już liderem tej grupy."; +$l['error_invalid_group_leader'] = "Podano nieprawidłowego lidera."; +$l['error_missing_namestyle_username'] = "Format wyświetlania loginu musi zawierać ciąg znaków {username}"; +$l['error_disallowed_namestyle_username'] = "W formacie loginu nie można używać tagów script, meta ani base."; +$l['error_default_group_delete'] = "Nie można usunąć domyślnej grupy"; +$l['error_cannot_have_both_types'] = "Nie można dodać grupy, w której dołączenie będzie możliwe przez zaproszenie oraz poprzez zatwierdzanie zgłoszeń. Wybierz tylko jedną z opcji."; + +$l['success_group_created'] = "Nowa grupa użytkowników została utworzona."; +$l['success_group_updated'] = "Wybrana grupa użytkowników została zaktualizowana."; +$l['success_group_deleted'] = "Wybrana grupa użytkowników została usunięta."; +$l['success_groups_disporder_updated'] = "Kolejność grup została zaktualizowana."; +$l['success_join_request_approved'] = "Wybrany wniosek został przyjęty. Użytkownik został dodany do grupy."; +$l['success_join_request_denied'] = "Wybrany wniosek został odrzucony."; +$l['success_selected_requests_approved'] = "Wybrane wnioski zostały przyjęte. Użytkownicy zostali dodani do grupy."; +$l['success_selected_requests_denied'] = "Wybrane wnioski zostały odrzucone."; +$l['success_user_made_leader'] = "został nowym liderem grupy użytkowników."; +$l['success_group_leader_updated'] = "Wybrany lider grupy został zaktualizowany."; +$l['success_group_leader_deleted'] = "Wybrany użytkownik przestał być liderem grupy."; + +$l['confirm_group_deletion'] = "Czy na pewno chcesz usunąć tę grupę użytkowników?"; +$l['confirm_group_leader_deletion'] = "Czy na pewno chcesz usunąć tego lidera grupy?"; diff --git a/Upload/inc/languages/polish/admin/user_mass_mail.lang.php b/Upload/inc/languages/polish/admin/user_mass_mail.lang.php new file mode 100644 index 0000000..aa2ceb1 --- /dev/null +++ b/Upload/inc/languages/polish/admin/user_mass_mail.lang.php @@ -0,0 +1,120 @@ +Informacja: To nie jest system awansów dla użytkowników.
    "; + +$l['error_missing_title'] = "Nie wpisano nazwy tytułu użytkownika"; +$l['error_missing_posts'] = "Nie wpisano minimalnej liczby postów, za którą ma być przyznawany tytuł"; +$l['error_cannot_have_same_posts'] = "Inny tytuł wymaga takiej samej liczby postów. Wprowadź inną liczbę postów."; +$l['error_invalid_user_title'] = "Wpisano niepoprawny tytuł użytkownika"; + +$l['success_user_title_created'] = "Tytuł użytkownika został utworzony"; +$l['success_user_title_updated'] = "Tytuł użytkownika został zaktualizowany."; +$l['success_user_title_deleted'] = "Tytuł użytkownika został usunięty."; + +$l['title_to_assign'] = "Przypisywany tytuł"; +$l['title_to_assign_desc'] = "Ten tytuł będzie znajdował się pod loginem użytkownika, jeżeli użytkownik nie ustawi własnego."; +$l['minimum_posts'] = "Minimalna ilość postów"; +$l['minimum_posts_desc'] = "Minimalna ilość postów, powyżej której przydzielany będzie ten tytuł."; +$l['number_of_stars'] = "Liczba gwiazdek"; +$l['number_of_stars_desc'] = "Wpisz liczbę gwiazdek wyświetlanych pod loginem użytkownika. Podaj 0, aby nie pokazywać gwiazdek."; +$l['star_image'] = "Obrazek gwiazdki"; +$l['star_image_desc'] = "Jeżeli dla tego tytułu użytkownika będą pokazywane gwiazdki, podaj ścieżkę do obrazka gwiazdki. Jeżeli pozostawisz to pole puste, wyświetlony zostanie obrazek gwiazdki dla grupy, do której należy użytkownik. Użyj {theme} zamiast ścieżki do katalogu ze stylem."; +$l['save_user_title'] = "Zapisz tytuł użytkownika"; +$l['edit_user_title'] = "Edytuj tytuł użytkownika"; +$l['edit_user_title_desc'] = "Edytuj tytuł użytkownika."; +$l['user_title_deletion_confirmation'] = "Czy na pewno chcesz usunąć ten tytuł użytkownika?"; +$l['manage_user_titles'] = "Tytuły użytkowników"; +$l['user_title'] = "Tytuł użytkownika"; +$l['no_user_titles'] = "Nie zdefiniowano żadnych tytułów użytkowników."; diff --git a/Upload/inc/languages/polish/admin/user_users.lang.php b/Upload/inc/languages/polish/admin/user_users.lang.php new file mode 100644 index 0000000..d3c3ee6 --- /dev/null +++ b/Upload/inc/languages/polish/admin/user_users.lang.php @@ -0,0 +1,409 @@ +Pamiętaj, że tego procesu nie można cofnąć."; +$l['edit_user'] = "Edytuj użytkownika"; +$l['edit_user_desc'] = "Zmodyfikuj profil użytkownika, jego ustawienia i sygnaturę, obejrzyj jego statystyki i inne strony zawierające szereg informacji z nim związanych."; +$l['show_referrers'] = "Pokaż zaproszonych"; +$l['show_referrers_desc'] = "Przeglądaj listę osób zaproszonych na to forum przez wybranego użytkownika. Pamiętaj o możliwości wyboru widoku listy."; +$l['show_ip_addresses'] = "Pokaż adresy IP"; +$l['show_ip_addresses_desc'] = "Przeglądaj informacje o adresach IP użytych przez tego użytkownika do rejestracji i do pisania postów."; +$l['manage_users'] = "Zarządzaj użytkownikami"; +$l['manage_users_desc'] = "Masowe zarządzanie użytkownikami ułatwia wykonywanie popularnych zadań."; +$l['inline_edit'] = "Zaznaczonych użytkowników:"; +$l['inline_activate'] = "Aktywuj"; +$l['inline_ban'] = "Zbanuj"; +$l['inline_usergroup'] = "Zmień grupę użytkowników"; +$l['inline_delete'] = "Usuń"; +$l['inline_prune'] = "Usuń posty użytkowników"; +$l['inline_activated'] = "{1} użytkowników zostało aktywowanych."; +$l['inline_activated_more'] = "{1} z zaznaczonych użytkowników aktywowało już swoje konto."; +$l['inline_activated_failed'] = "Wszyscy zaznaczeni użytkownicy zostali aktywowani."; +$l['ban_time'] = "Znieś bana po*"; +$l['ban_reason'] = "Powód"; +$l['mass_ban'] = "Masowe banowanie użytkowników"; +$l['important'] = "Ważne"; +$l['mass_ban_info'] = "Ta akcja zostanie zastosowana na {1} użytkownikach. Kontynuuj tylko wtedy, jeżeli na pewno chcesz zbanować tych użytkowników."; +$l['ban_users'] = "Zbanuj użytkowników"; +$l['users_banned'] = "{1} użytkowników zostało zbanowanych."; +$l['confirm_multilift'] = "Czy na pewno chcesz usunąć bany dla zaznaczonych użytkowników?"; +$l['success_ban_lifted'] = "Bany dla {1} użytkowników zostały usunięte."; +$l['edit_ban'] = "Edytuj bana"; +$l['lift_ban'] = "Usuń bana"; +$l['lift_bans'] = "Usuń bany"; +$l['confirm_multidelete'] = "Czy na pewno chcesz usunąć {1} zaznaczonych użytkowników? Ta czynność nie może zostać cofnięta."; +$l['users_deleted'] = "{1} użytkowników zostało usuniętych."; +$l['mass_prune_info'] = "Ta akcja zostanie zastosowana na {1} użytkownikach. Jeżeli będziesz kontynuować, opcja ta usunie wszystkie posty użytkownika starsze niż okres wybrany z listy poniżej.

    Miej na uwadze fakt, że jeżeli użytkownik napisał pierwszy post w wątku, cały wątek zostanie usunięty."; +$l['mass_prune_posts'] = "Masowe czyszczenie postów"; +$l['manual_date'] = "Podaj własną datę"; +$l['relative_date'] = "lub wybierz z listy"; +$l['multi_selected_dates'] = "Wybrano własną datę i datę z listy. Wybierz jedną z nich i spróbuj ponownie."; +$l['incorrect_date'] = "Podana data jest niepoprawna. Podaj właściwą datę lub pozostaw pole puste i wybierz okres z listy."; +$l['prune_complete'] = "Czyszczenie zakończone."; +$l['prune_fail'] = "Nie znaleziono postów dla wybranych użytkowników. Żadne posty nie zostały usunięte."; +$l['no_prune_option'] = "Podaj datę lub wybierz opcję aby kontynuować."; +$l['prune_posts'] = "Wyczyść posty"; +$l['delete_posts'] = "Usuń posty"; +$l['usergroup_info'] = "Ta akcja zostanie zastosowana na {1} użytkownikach. Poprzez wybranie opcji poniżej główna / dodatkowa / wyświetlana grupa użytkownika zostanie nadpisana."; +$l['mass_usergroups'] = "Masowa zmiana grup użytkowników"; +$l['success_mass_usergroups'] = "Użytkownicy zostali zaktualizowani."; +$l['alter_usergroups'] = "Zapisz zmiany"; +$l['no_usergroup_changed'] = "Żadnemu z zaznaczonych użytkowników grupa nie została zmieniona."; +$l['no_set_option'] = "Nie wybrano poprawnej daty. Wybierz opcję z listy lub wprowadź poprawną datę."; +$l['select_an_option'] = "wybierz"; + +$l['month_1'] = "Styczeń"; +$l['month_2'] = "Luty"; +$l['month_3'] = "Marzec"; +$l['month_4'] = "Kwiecień"; +$l['month_5'] = "Maj"; +$l['month_6'] = "Czerwiec"; +$l['month_7'] = "Lipiec"; +$l['month_8'] = "Sierpień"; +$l['month_9'] = "Wrzesień"; +$l['month_10'] = "Październik"; +$l['month_11'] = "Listopad"; +$l['month_12'] = "Grudzień"; + +$l['option_1'] = "starsze niż miesiąc"; +$l['option_2'] = "starsze niż 3 miesiące"; +$l['option_3'] = "starsze niż 6 miesięcy"; +$l['option_4'] = "starsze niż rok"; +$l['option_5'] = "starsze niż półtora roku"; +$l['option_6'] = "starsze niż 2 lata"; + +$l['error_avatartoobig'] = "Wybrany awatar jest zbyt duży. Maksymalne rozmiary to {1}x{2} (szer. x wys.)"; +$l['error_invalidavatarurl'] = "Podano nieprawidłowy adres URL do awatara. Podaj poprawny adres."; +$l['error_invalid_user'] = "Wybrano niepoprawnego użytkownika."; +$l['error_no_perms_super_admin'] = "Nie masz uprawnień do edycji tego konta, bo nie jesteś super administratorem."; +$l['error_invalid_user_source'] = "Podane konto źródłowe nie istnieje"; +$l['error_invalid_user_destination'] = "Podane konto docelowe nie istnieje"; +$l['error_cannot_merge_same_account'] = "Konto źródłowe nie może być jednocześnie docelowym"; +$l['error_no_users_found'] = "Nie znaleziono użytkowników spełniających podane kryteria. Zmień kryteria wyszukiwania i spróbuj ponownie."; +$l['error_invalid_admin_view'] = "Wybrano nieprawidłowy widok."; +$l['error_missing_view_title'] = "Nie podano nazwy dla widoku."; +$l['error_no_view_fields'] = "Nie wybrano pól, które mają być wyświetlane w tym widoku"; +$l['error_invalid_view_perpage'] = "Podano nieprawidłową liczbę wyników na stronę"; +$l['error_invalid_view_sortby'] = "Podano nieprawidłowe pole, wg którego lista ma być sortowana"; +$l['error_invalid_view_sortorder'] = "Wybrano nieprawidłowy porządek sortowania"; +$l['error_invalid_view_delete'] = "Wybrano nieprawidłowy widok do usunięcia"; +$l['error_cannot_delete_view'] = "Musisz posiadać przynajmniej jeden widok."; +$l['error_inline_no_users_selected'] = "Nie zaznaczono użytkowników. Wybierz kilku użytkowników i spróbuj ponownie."; +$l['error_cannot_delete_user'] = "Nie można usunąć tego użytkownika."; +$l['error_no_referred_users'] = "Wybrany użytkownik nie posiada żadnych poleconych użytkowników."; + +$l['user_deletion_confirmation'] = "Czy na pewno usunąć tego użytkownika?"; + +$l['success_coppa_activated'] = "Użytkownik wymagający weryfikacji COPPA został aktywowany."; +$l['success_activated'] = "Użytkownik został aktywowany."; +$l['success_user_created'] = "Konto użytkownika zostało utworzone."; +$l['success_user_updated'] = "Konto użytkownika zostało zaktualizowane."; +$l['success_user_deleted'] = "Konto użytkownika zostało usunięte."; +$l['success_merged'] = "został połączony z"; +$l['succuss_view_set_as_default'] = "Widok został ustawiony jako domyślny"; +$l['success_view_created'] = "Widok został utworzony"; +$l['success_view_updated'] = "Widok został zaktualizowany"; +$l['success_view_deleted'] = "Widok został usunięty"; + +$l['confirm_view_deletion'] = "Czy na pewno usunąć ten widok?"; + +$l['warning_coppa_user'] = "

    Ostrzeżenie: Ten użytkownik wymaga weryfikacji COPAA. Kliknij, by aktywować konto

    "; + +$l['required_profile_info'] = "Wymagane informacje"; +$l['password'] = "Hasło"; +$l['confirm_password'] = "Potwierdź hasło"; +$l['email_address'] = "Adres e-mail"; +$l['use_primary_user_group'] = "Używaj głównej grupy"; +$l['primary_user_group'] = "Główna grupa użytkowników"; +$l['additional_user_groups'] = "Dodatkowe grupy użytkowników"; +$l['additional_user_groups_desc'] = "Przytrzymaj CTRL klikając, by wybrać wiele pozycji"; +$l['display_user_group'] = "Wyświetlana grupa użytkowników"; +$l['save_user'] = "Zapisz użytkownika"; + +$l['overview'] = "Ogólne"; +$l['profile'] = "Profil"; +$l['account_settings'] = "Ustawienia"; +$l['signature'] = "Sygnatura"; +$l['avatar'] = "Awatar"; +$l['mod_options'] = "Opcje moderatora"; +$l['general_account_stats'] = "Ogólne informacje"; +$l['local_time'] = "Czas lokalny"; +$l['local_time_format'] = "{1}, {2}"; +$l['posts'] = "Postów"; +$l['age'] = "Wiek"; +$l['posts_per_day'] = "Postów na dzień"; +$l['percent_of_total_posts'] = "Procent ogólnej liczby postów"; +$l['user_overview'] = "Ogólne informacje"; + +$l['new_password'] = "Nowe hasło"; +$l['new_password_desc'] = "wypełnij tylko w przypadku zmiany"; +$l['confirm_new_password'] = "Potwierdź nowe hasło"; + +$l['optional_profile_info'] = "Dodatkowe informacje"; +$l['custom_user_title'] = "Własny tytuł użytkownika"; +$l['custom_user_title_desc'] = "Jeżeli to pole pozostanie puste, użyty zostanie domyślny tytuł grupy"; +$l['website'] = "Strona WWW"; +$l['icq_number'] = "Numer ICQ"; +$l['aim_handle'] = "Nazwa użytkownika AIM"; +$l['yahoo_messanger_handle'] = "Identyfikator Yahoo"; +$l['skype_handle'] = "Identyfikator Skyp:"; +$l['google_handle'] = "Identyfikator Google Talk"; +$l['birthday'] = "Data urodzenia"; + +$l['away_information'] = "Dostępność"; +$l['away_status'] = "Status:"; +$l['away_status_desc'] = "Pozwala na wpisanie wiadomości informującej o nieobecności."; +$l['im_away'] = "Niedostępny"; +$l['im_here'] = "Dostępny"; +$l['away_reason'] = "Powód nieobecności:"; +$l['away_reason_desc'] = "Pozwala Ci na wpisanie krótkiego powodu nieobecności (maksymalnie 200 znaków)."; +$l['return_date'] = "Data powrotu:"; +$l['return_date_desc'] = "Wpisz tu datę powrotu, o ile ją znasz."; +$l['error_acp_return_date_past'] = "Nie możesz się cofnąć w czasie!"; + +$l['hide_from_whos_online'] = "Ukryj na liście Kto jest online"; +$l['login_cookies_privacy'] = "Logowanie, cookies i prywatność"; +$l['recieve_admin_emails'] = "Otrzymuj e-maile od administracji"; +$l['hide_email_from_others'] = "Ukryj adres e-mail przed innymi użytkownikami"; +$l['recieve_pms_from_others'] = "Otrzymuj prywatne wiadomości od innych użytkowników"; +$l['recieve_pms_from_buddy'] = "Otrzymuj prywatne wiadomości tylko od osób z listy znajomych"; +$l['alert_new_pms'] = "Informuj o nowych prywatnych wiadomościach"; +$l['email_notify_new_pms'] = "Informuj e-mailem o nowych prywatnych wiadomościach"; +$l['default_thread_subscription_mode'] = "Domyślny sposób subskrypcji tematów"; +$l['do_not_subscribe'] = "Nie subskrybuj"; +$l['no_email_notification'] = "Bez powiadamiania e-mailem"; +$l['instant_email_notification'] = "Powiadomienie e-mail"; +$l['messaging_and_notification'] = "Prywatne wiadomości i e-maile"; +$l['use_default'] = "Użyj domyślnego"; +$l['date_format'] = "Formatowanie daty"; +$l['time_format'] = "Formatowanie czasu"; +$l['time_zone'] = "Strefa czasowa"; +$l['daylight_savings_time_correction'] = "Zmiany czasu"; +$l['automatically_detect'] = "Automatycznie wykryj zmiany czasu"; +$l['always_use_dst_correction'] = "Używaj czasu letniego"; +$l['never_use_dst_correction'] = "Używaj czasu zimowego"; +$l['date_and_time_options'] = "Opcje daty i czasu"; +$l['show_threads_last_day'] = "Pokazuj wątki z ostatniego dnia"; +$l['show_threads_last_5_days'] = "Pokazuj wątki z ostatnich 5 dni"; +$l['show_threads_last_10_days'] = "Pokazuj wątki z ostatnich 10 dni"; +$l['show_threads_last_20_days'] = "Pokazuj wątki z ostatnich 20 dni"; +$l['show_threads_last_50_days'] = "Pokazuj wątki z ostatnich 50 dni"; +$l['show_threads_last_75_days'] = "Pokazuj wątki z ostatnich 75 dni"; +$l['show_threads_last_100_days'] = "Pokazuj wątki z ostatnich 100 dni"; +$l['show_threads_last_year'] = "Pokazuj wątki z ostatniego roku"; +$l['show_all_threads'] = "Pokazuj wszystkie wątki"; +$l['threads_per_page'] = "Wątków na stronę"; +$l['default_thread_age_view'] = "Wyświetlanie wątków"; +$l['forum_display_options'] = "Opcje wyświetlania działów"; +$l['show_classic_postbit'] = "Pokazuj posty w układzie klasycznym"; +$l['display_images'] = "Pokazuj obrazki w postach"; +$l['display_videos'] = "Pokazuj wideo w postach"; +$l['display_users_sigs'] = "Pokazuj sygnatury użytkowników"; +$l['display_users_avatars'] = "Pokazuj awatary użytkowników"; +$l['show_quick_reply'] = "Wyświetl pole szybkiej odpowiedzi na końcu wątku"; +$l['posts_per_page'] = "Postów na stronę"; +$l['default_thread_view_mode'] = "Domyślny tryb wyświetlania wątków"; +$l['linear_mode'] = "Standardowy"; +$l['threaded_mode'] = "Drzewo"; +$l['thread_view_options'] = "Opcje wyświetlania wątków"; +$l['show_redirect'] = "Pokazuj strony przekierowań"; +$l['show_code_buttons'] = "Wyświetlaj przyciski formatowania MyCode"; +$l['source_editor'] = "Edytor powinien domyślnie pracować w trybie edycji kodu"; +$l['theme'] = "Styl"; +$l['board_language'] = "Język forum"; +$l['other_options'] = "Inne opcje"; +$l['signature_desc'] = "Opcje formatowania: MyCode {1}, emotikony {2}, kod IMG {3}, HTML {4}"; +$l['enable_sig_in_all_posts'] = "Wyświetlaj sygnaturę przy wszystkich postach"; +$l['disable_sig_in_all_posts'] = "Nie wyświetlaj sygnatury przy żadnych postach"; +$l['do_nothing'] = "Nie zmieniaj ustawień wyświetlania sygnatury"; +$l['signature_preferences'] = "Ustawienia sygnatury"; +$l['suspend_sig'] = "Wyłącz sygnaturę"; +$l['suspend_sig_box'] = "Wyłącz sygnaturę tego użytkownika"; +$l['suspend_sig_perm'] = "Wyłączona na zawsze."; +$l['suspend_sig_info'] = "Jeżeli sygnatura użytkownika zostanie wyłączona, użytkownik nie będzie mógł jej edytować ani nie będzie ona pokazywana pod postami i w profilu użytkownika"; +$l['suspend_sig_extend'] = "Podaj nowy czas, aby zmienić datę wyłączenia ograniczenia bądź odznacz tę opcję aby teraz wyłączyć ograniczenie."; +$l['suspend_expire_info'] = "Wygasa {1}"; +$l['suspend_never_expire'] = "Wyłączenie sygnatury użytkownika {1} nie zostanie nigdy wyłączone."; +$l['suspend_sig_error'] = "Podano nieprawidłowy okres wyłączenia sygnatury użytkownika. Podaj prawidłową datę."; + +$l['moderate_posts'] = "Moderuj posty użytkownika"; +$l['moderate_posts_info'] = "Moderuj nowe posty użytkownika {1}."; +$l['moderate_for'] = "Moderuj przez:"; +$l['moderated_perm'] = "

    Posty tego użytkownika będą cały czas moderowane.
    Podaj nowy czas, aby zmienić datę wyłączenia ograniczenia bądź odznacz tę opcję aby teraz wyłączyć ograniczenie.

    "; +$l['moderate_length'] = "

    Posty będą moderowane do {1}.
    Podaj nowy czas, aby zmienić datę wyłączenia ograniczenia bądź odznacz tę opcję aby teraz wyłączyć ograniczenie.

    "; + +$l['suspend_posts'] = "Odbierz możliwość pisania"; +$l['suspend_posts_info'] = "Odbierz użytkownikowi {1} możliwość pisania postów."; +$l['suspend_for'] = "Odbierz na:"; +$l['suspended_perm'] = "

    Użytkownik na zawsze nie może pisać postów.
    Podaj nowy czas, aby zmienić datę wyłączenia ograniczenia bądź odznacz tę opcję aby teraz wyłączyć ograniczenie.

    "; +$l['suspend_length'] = "

    Użytkownik nie będzie mógł pisać postów do {1}.
    Podaj nowy czas, aby zmienić datę wyłączenia ograniczenia bądź odznacz tę opcję aby teraz wyłączyć ograniczenie.

    "; + +$l['suspendsignature_error'] = "Wybrano wyłączenie użytkownikowi sygnatury, ale nie podano poprawnego okresu czasowego. Podaj poprawny czas, aby zmienić datę wyłączenia ograniczenia bądź odznacz tę opcję aby teraz wyłączyć ograniczenie."; +$l['moderateposting_error'] = "Wybrano włączenie moderowania postów użytkownika, ale nie podano poprawnego okresu czasowego. Podaj poprawny czas, aby zmienić datę wyłączenia ograniczenia bądź odznacz tę opcję aby teraz wyłączyć ograniczenie."; +$l['suspendposting_error'] = "Wybrano odebranie użytkownikowi możliwości pisania postów, ale nie podano poprawnego okresu czasowego. Podaj poprawny czas, aby zmienić datę wyłączenia ograniczenia bądź odznacz tę opcję aby teraz wyłączyć ograniczenie."; +$l['suspendmoderate_error'] = "Wybrano odebranie użytkownikowi możliwości pisania postów lub włączenia ich moderowania. Wybierz tylko jeden z typów kary."; + +$l['expire_length'] = "Długość ograniczenia:"; +$l['expire_hours'] = "godzin(y)"; +$l['expire_days'] = "dni)"; +$l['expire_weeks'] = "tygodnie"; +$l['expire_months'] = "miesiące"; +$l['expire_never'] = "nigdy"; +$l['expire_permanent'] = "na zawsze"; + +$l['username'] = "Login"; +$l['email'] = "E-mail"; +$l['primary_group'] = "Główna grupa"; +$l['additional_groups'] = "Dodatkowe grupy"; +$l['registered'] = "Zarejestrowany"; +$l['last_active'] = "Ostatnio aktywny"; +$l['post_count'] = "Liczba postów"; +$l['thread_count'] = "Liczba wątków"; +$l['reputation'] = "Reputacja"; +$l['warning_level'] = "Poziom ostrzeżeń"; +$l['registration_ip'] = "IP rejestracji"; +$l['last_known_ip'] = "Ostatnio używane IP"; +$l['registration_date'] = "Data rejestracji"; +$l['info_on_ip'] = "Informacje o tym adresie IP"; + +$l['current_avatar'] = "Aktualny awatar"; +$l['user_current_using_uploaded_avatar'] = "Ten użytkownik aktualnie korzysta z awatara wysłanego na serwer."; +$l['user_currently_using_remote_avatar'] = "Ten użytkownik aktualnie korzysta ze zdalnie podlinkowanego awatara."; +$l['max_dimensions_are'] = "Maksymalne rozmiary awatara to"; +$l['avatar_max_size'] = "Awatar nie może być większy niż"; +$l['remove_avatar'] = "Usunąć aktualny awatar?"; +$l['avatar_desc'] = "Zarządzaj awatarem tego użytkownika. Awatary to małe obrazki, które - umieszczone pod loginami użytkowników - pozwalają na ich szybką identyfikację."; +$l['avatar_auto_resize'] = "Jeśli awatar jest zbyt duży, zostanie on automatycznie pomniejszony"; +$l['attempt_to_auto_resize'] = "Pomniejszyć, jeżeli awatar okaże się zbyt duży?"; +$l['specify_custom_avatar'] = "Wybierz własny awatar"; +$l['upload_avatar'] = "Wyślij awatar na serwer"; +$l['or_specify_avatar_url'] = "lub podaj jego adres URL/Gravatara"; + +$l['user_notes'] = "Notatki użytkownika"; + +$l['ip_addresses'] = "Adresy IP"; +$l['ip_address'] = "Adres IP"; +$l['show_users_regged_with_ip'] = "Wyświetl użytkowników, którzy zarejestrowali się z tego IP"; +$l['show_users_posted_with_ip'] = "Wyświetl użytkowników, którzy pisali z tego IP"; +$l['ban_ip'] = "Zbanuj ten adres IP"; +$l['ip_address_for'] = "Adresy IP użytkownika"; + +$l['source_account'] = "Konto źródłowe"; +$l['source_account_desc'] = "Jest to konto, które zostanie dołączone do konta docelowego. W wyniku procesu łączenia to konto przestanie istnieć."; +$l['destination_account'] = "Konto docelowe"; +$l['destination_account_desc'] = "Jest to konto, do którego zostanie dołączone konto źródłowe. Będzie istnieć nadal po przeprowadzeniu tego procesu."; +$l['merge_user_accounts'] = "Połącz konta"; + +$l['display_options'] = "Opcje wyświetlania"; +$l['ascending'] = "Rosnąco"; +$l['descending'] = "Malejąca"; +$l['sort_results_by'] = "Sortuj wyniki wg"; +$l['in'] = "w"; +$l['results_per_page'] = "Wyników na stronę"; +$l['display_results_as'] = "Wyświetl wyniki jako"; +$l['business_card'] = "Wizytówki"; +$l['views'] = "Widoki"; +$l['views_desc'] = "Zarządzaj istniejącymi i twórz nowe tryby wyświetlania (widoki), dzięki czemu uzyskasz łatwiejszy dostęp do interesujących Cię danych."; +$l['manage_views'] = "Zarządzaj widokami"; +$l['none'] = "brak"; +$l['search'] = "Znajdź"; + +$l['view_profile'] = "Zobacz profil"; +$l['edit_profile_and_settings'] = "Edytuj profil i ustawienia"; +$l['ban_user'] = "Zbanuj użytkownika"; +$l['approve_coppa_user'] = "Aktywacja COPPA"; +$l['approve_user'] = "Aktywuj użytkownika"; +$l['delete_user'] = "Usuń użytkownika"; +$l['show_referred_users'] = "Pokaż zaproszonych"; +$l['show_attachments'] = "Pokaż załączniki"; +$l['table_view'] = "Widok tabelaryczny"; +$l['card_view'] = "Widok wizytówek"; + +$l['find_users_where'] = "Znajdź użytkowników, których..."; +$l['username_contains'] = "Login zawiera"; +$l['email_address_contains'] = "Adres e-mail zawiera"; +$l['is_member_of_groups'] = "Grupa użytkowników to"; +$l['website_contains'] = "Strona WWW zawiera"; +$l['icq_number_contains'] = "Numer ICQ zawiera"; +$l['aim_handle_contains'] = "Identyfikator AIM zawiera"; +$l['yahoo_contains'] = "Identyfikator Yahoo! zawiera"; +$l['skype_contains'] = "Identyfikator Skype zawiera"; +$l['google_contains'] = "Identyfikator Google Talk zawiera"; +$l['signature_contains'] = "Sygnatura zawiera"; +$l['user_title_contains'] = "Własny tytuł użytkownika zawiera"; +$l['greater_than'] = "większa niż"; +$l['is_exactly'] = "równa"; +$l['less_than'] = "mniejsza niż"; +$l['post_count_is'] = "Liczba postów"; +$l['thread_count_is'] = "Liczba wątków"; +$l['reg_ip_matches'] = "Adres IP rejestracji to"; +$l['wildcard'] = "użyj * by zastąpić dowolny oktet adresu IP, np. 1.2.*.*"; +$l['posted_with_ip'] = "Jednym z adresów IP postowania jest"; +$l['custom_profile_fields_match'] = "Gdzie jedno z dodatkowych pól jest równe"; +$l['is_not_blank'] = " nie jest puste"; +$l['or'] = "lub"; +$l['reg_in_x_days'] = "Zarejestrował się w ciągu ostatnich"; +$l['days'] = "dni"; + +$l['view'] = "Widok"; +$l['create_new_view'] = "Nowy widok"; +$l['create_new_view_desc'] = "Utwórz nowy tryb wyświetlania (widok), dzięki czemu uzyskasz łatwiejszy dostęp do interesujących Cię danych."; +$l['view_manager'] = "Menedżer widoków"; +$l['set_as_default_view'] = "Ustawić jako domyślny?"; +$l['enabled'] = "Wyświetlane"; +$l['disabled'] = "Ukryte"; +$l['fields_to_show'] = "Wyświetlane pola"; +$l['fields_to_show_desc'] = "Wybierz pola, które mają być wyświetlane w tym widoku"; +$l['edit_view'] = "Edytuj widok"; +$l['edit_view_desc'] = "Zmodyfikuj listę pól do pokazania, kryteria wyszukiwania oraz opcje sortowania."; +$l['private'] = "Prywatny"; +$l['private_desc'] = "Ten widok będzie dostępny tylko dla Ciebie"; +$l['public'] = "Publiczny"; +$l['public_desc'] = "Wszyscy inni administratorzy będą mogli korzystać z tego widoku"; +$l['visibility'] = "Widoczność"; +$l['save_view'] = "Zapisz widok"; +$l['created_by'] = "Utworzony przez"; +$l['default'] = "Domyślny"; +$l['this_is_a_view'] = "To jest widok {1}"; +$l['set_as_default'] = "Ustaw jako domyślny"; +$l['delete_view'] = "Usuń widok"; +$l['default_view_desc'] = "Standardowy widok MyBB. Nie może zostać usunięty ani zmodyfikowany."; +$l['public_view_desc'] = "Publiczny widok dostępny dla wszystkich administratorów."; +$l['private_view_desc'] = "Prywatny widok dostępny tylko dla Ciebie."; +$l['table'] = "Tabela"; +$l['title'] = "Nazwa"; + +$l['view_title_1'] = "Wszyscy użytkownicy"; + +$l['emailsubject_activateaccount'] = "Account Activation at {1}"; +$l['email_adminactivateaccount'] = "{1}, + +Administrator aktywował Twoje konto na forum \"{2}\". + +Aby kontynuować, przejdź do: + +{3} + +Możesz się teraz zalogować, używając danych podanych podczas rejestracji. + +Dziękujemy, +Ekipa {2}"; + +$l['ipaddress_misc_info'] = "Informacje dot. adresu IP: '{1}'"; +$l['ipaddress_host_name'] = "Nazwa hosta:"; +$l['ipaddress_location'] = "Lokalizacja (na podstawie danych z bazy GeoIP):"; diff --git a/Upload/inc/languages/polish/announcements.lang.php b/Upload/inc/languages/polish/announcements.lang.php new file mode 100644 index 0000000..cf888ac --- /dev/null +++ b/Upload/inc/languages/polish/announcements.lang.php @@ -0,0 +1,16 @@ +Kliknij tutaj, by zobaczyć wersję z pełnym formatowaniem."; +$l['archive_nopermission'] = "Nie masz uprawnień do przeglądania tego zasobu."; +$l['error_nothreads'] = "Aktualnie nie ma wątków w tym dziale."; +$l['error_unapproved_thread'] = "Ten wątek nie został zatwierdzony. Odwiedź wersję z pełnym formatowaniem aby zobaczyć jego treść."; +$l['archive_not_found'] = "

    BÅ‚Ä…d 404

    Określony dokument (plik) nie został znaleziony na serwerze."; +$l['error_mustlogin'] = "To forum wymaga zalogowania od wszystkich swoich użytkowników."; \ No newline at end of file diff --git a/Upload/inc/languages/polish/calendar.lang.php b/Upload/inc/languages/polish/calendar.lang.php new file mode 100644 index 0000000..dcae967 --- /dev/null +++ b/Upload/inc/languages/polish/calendar.lang.php @@ -0,0 +1,144 @@ +Prywatne: tylko Ty będziesz widzieć wydarzenie (o ile jesteś zarejestrowanym użytkownikiem)."; +$l['delete_option'] = "Usuń: wydarzenie zostanie usunięte."; +$l['post_event'] = "Nowe wydarzenie"; +$l['day_view'] = "Podgląd dnia"; +$l['birthday'] = "osoba ma urodziny"; +$l['birthdays'] = "osób ma urodziny"; +$l['event_author'] = "Autor:"; +$l['edit_event'] = "Aktualizuj wydarzenie"; +$l['view_event'] = "Pokaż wydarzenie"; +$l['no_events'] = "Z tym dniem nie są związane żadne wydarzenia.

    Kliknij, by dodać wydarzenie.

    "; +$l['years_old'] = "{1} l."; +$l['alt_edit'] = "Edytuj to wydarzenie"; +$l['alt_delete'] = "Usuń to wydarzenie"; +$l['moderator_options'] = "Opcje moderatora"; +$l['approve_event'] = "Zatwierdź wydarzenie"; +$l['unapprove_event'] = "Ukryj wydarzenie"; +$l['move_event'] = "Przenieś wydarzenie"; +$l['repeats_every_day'] = "Powtarza się codziennie"; +$l['repeats_every_x_days'] = "Powtarza się co {1} dni"; +$l['repeats_on_weekdays'] = "Powtarza się od poniedziałku do piątku"; +$l['every_week_on_days'] = "Powtarza się co tydzień w {1}"; +$l['every_week'] = "Powtarza się co tydzień"; +$l['every_x_weeks_on_days'] = "Powtarza się co {1} tygodni(e) w
    {2}"; +$l['every_x_weeks'] = "Powtarza siÄ™ co {1} tygodni(e)"; +$l['every_month_on_day'] = "Powtarza siÄ™ {1} dnia
    każdego miesiąca"; +$l['every_x_months_on_day'] = "Powtarza się {1} dnia miesiąca
    co {2} miesięcy"; +$l['every_month_on_weekday'] = "Powtarza się w: {1} {2}
    każdego miesiąca"; +$l['every_x_months_on_weekday'] = "Powtarza się w: {1} {2}
    co {3} miesięcy"; +$l['weekday_occurance_1'] = "1."; +$l['weekday_occurance_2'] = "2."; +$l['weekday_occurance_3'] = "3."; +$l['weekday_occurance_4'] = "4."; +$l['weekday_occurance_last'] = "ost."; +$l['every_year_on_day'] = "Powtarza się co roku w{1} {2}"; +$l['every_x_years_on_day'] = "Powtarza się co {3} lat(a) w {1} {2}"; +$l['every_year_on_weekday'] = "Powtarza się każdego roku ({1} {2} w {3})."; +$l['every_x_year_on_weekday'] = "Powtarza się co {4} lat(a) ({1} {2} w {3})"; +$l['delete_event'] = "Usuń wydarzenie"; +$l['delete_q'] = "Usunąć?"; +$l['delete_1'] = "By usunąć to wydarzenie, zaznacz pole po lewej i kliknij przycisk po prawej."; +$l['delete_2'] = "Uwaga: ta decyzja będzie nieodwracalna."; +$l['delete_now'] = "Usuń teraz"; +$l['jump_to_calendar'] = "Przejdź do kalendarza:"; +$l['select_calendar'] = "Kalendarz:"; +$l['type_single'] = "Jednodniowe wydarzenie"; +$l['type_ranged'] = "Kilkudniowe lub powtarzające się wydarzenie"; +$l['enter_time'] = "Godzina:"; +$l['start_time'] = "Początek:"; +$l['end_time'] = "Koniec:"; +$l['timezone'] = "Strefa czasowa:"; +$l['ignore_timezone'] = "Ignoruj strefę czasową: wydarzenie zostanie wyświetlone przy użyciu ustawień strefy czasowej przeglądającego."; +$l['repeats'] = "Powtarzanie:"; +$l['does_not_repeat'] = "nie powtarza się"; +$l['repeats_daily'] = "codziennie / co kilka dni"; +$l['repeats_weekdays'] = "od poniedziałku do piątku"; +$l['repeats_weekly'] = "co tydzień / kilka tygodni"; +$l['repeats_every'] = "Powtarza się co"; +$l['day_or_days'] = "dni"; +$l['week_or_weeks_on'] = "tygodni w"; +$l['repeats_monthly'] = "co miesiąc / kilka miesięcy"; +$l['repeats_yearly'] = "co roku / kilka lat"; +$l['repeats_on_day'] = "Powtarza się w dniu numer "; +$l['of_every'] = "co"; +$l['month_or_months'] = "miesięcy"; +$l['repeats_on_the'] = "Powtarza się w "; +$l['day_of_every'] = "dzień co"; +$l['repeats_on'] = "Powtarza się "; +$l['every'] = "co"; +$l['year_or_years'] = "lat"; +$l['of'] = ""; +$l['move_to_calendar'] = "Przenieś do kalendarza:"; +$l['weekly_overview'] = "Podgląd tygodnia"; +$l['previous_week'] = "Poprzedni tydzień"; +$l['next_week'] = "Następny tydzień"; +$l['first'] = "1."; +$l['second'] = "2."; +$l['third'] = "3."; +$l['fourth'] = "4."; +$l['last'] = "ost."; +$l['all_day'] = "cały dzień"; +$l['starts'] = "Początek: "; +$l['finishes'] = "Koniec: "; + +$l['error_incorrectday'] = "Podana data jest niepoprawna. Wprowadź inną datę."; +$l['error_invalidevent'] = "Wybrane wydarzenie nie istnieje."; +$l['invalid_calendar'] = "Wybrany kalendarz nie istnieje. Czy na pewno adres jest poprawny?"; +$l['redirect_eventdeleted'] = "Wydarzenie zostało usunięte.
    Teraz nastąpi przeniesienie do kalendarza."; +$l['redirect_eventupdated'] = "Wydarzenie zostało zaktualizowane.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_eventadded'] = "Wydarzenie zostało dodane.
    Teraz nastąpi przeniesienie do tego wydarzenia."; +$l['redirect_eventadded_moderation'] = "Wydarzenie zostało dodane, ale wymaga zatwierdzenia przez moderatora zanim zostanie opublikowane.
    Teraz nastąpi przeniesienie do kalendarza."; +$l['redirect_eventunapproved'] = "Wydarzenie zostało ukryte.
    Teraz nastąpi przeniesienie do tego wydarzenia."; +$l['redirect_eventapproved'] = "Wydarzenie zostało zaakceptowane.
    Teraz nastąpi przeniesienie do tego wydarzenia."; +$l['redirect_eventmoved'] = "Wydarzenie zostało przeniesione.
    Teraz nastÄ…pi przeniesienie do tego wydarzenia."; diff --git a/Upload/inc/languages/polish/contact.lang.php b/Upload/inc/languages/polish/contact.lang.php new file mode 100644 index 0000000..341fba2 --- /dev/null +++ b/Upload/inc/languages/polish/contact.lang.php @@ -0,0 +1,30 @@ +
    Jeżeli nie pamiętasz swojego hasła, kliknij tutaj, by wygenerować nowe."; +$l['logindata_invalidpwordusernameemail'] = "Wprowadzono nieprawidłowy adres e-mail i/lub hasło.

    Jeżeli nie pamiętasz swojego hasła, kliknij tutaj, by wygenerować nowe."; +$l['logindata_invalidpwordusernamecombo'] = "Wprowadzono nieprawidłowy login i/lub hasło albo adres e-mail i/lub hasło.

    Jeżeli nie pamiętasz swojego hasła, kliknij tutaj, by wygenerować nowe."; + +$l['logindata_regimageinvalid'] = "Wprowadzony kod z obrazka jest nieprawidłowy. Przepisz kod identyczny jak ten na obrazku."; +$l['logindata_regimagerequired'] = "Uzupełnij kod weryfikujący aby kontynuować proces logowania. Przepisz kod identyczny jak ten na obrazku."; diff --git a/Upload/inc/languages/polish/datahandler_pm.lang.php b/Upload/inc/languages/polish/datahandler_pm.lang.php new file mode 100644 index 0000000..c55fe6d --- /dev/null +++ b/Upload/inc/languages/polish/datahandler_pm.lang.php @@ -0,0 +1,22 @@ +
    Możesz dodać maksymalnie {1} ostrzeżeń dziennie.'; +$l['warnings_error_invalid_user'] = "Wybrany użytkownik nie istnieje."; +$l['warnings_error_invalid_post'] = "Wybrany post nie istnieje."; +$l['warnings_error_cannot_warn_self'] = "Nie możesz przyznać ostrzeżenia sam sobie."; +$l['warnings_error_user_reached_max_warning'] = "Nie można przyznać ostrzeżenia temu użytkownikowi, ponieważ osiągnął już ich maksymalny poziom."; +$l['warnings_error_no_note'] = "Nie wpisano żadnych notatek administracyjnych."; +$l['warnings_error_invalid_type'] = "Wybrano nieprawidłowy typ ostrzeżenia."; +$l['warnings_error_cant_custom_warn'] = "Nie posiadasz uprawnień do przyznawania użytkownikom własnych ostrzeżeń."; +$l['warnings_error_no_custom_reason'] = "Nie wpisano powodu własnego ostrzeżenia."; +$l['warnings_error_invalid_custom_points'] = "Wpisano nieprawidłową liczbę punktów ostrzeżeń dla użytkownika. Wybrana liczba musi być większa od 0 i mniejsza niż {1}."; +$l['warnings_error_invalid_expires_period'] = "Wpisano nieprawidłowy okres przedawnienia."; \ No newline at end of file diff --git a/Upload/inc/languages/polish/editpost.lang.php b/Upload/inc/languages/polish/editpost.lang.php new file mode 100644 index 0000000..7bb1430 --- /dev/null +++ b/Upload/inc/languages/polish/editpost.lang.php @@ -0,0 +1,55 @@ +Uwaga: jeśli ten post jest pierwszym w wątku, to wraz z nim zostanie usunięty cały wątek!"; +$l['subject'] = "Temat"; +$l['your_message'] = "Treść"; +$l['post_options'] = "Opcje posta:"; +$l['editreason'] = "Powód edycji:"; +$l['options_sig'] = "Sygnatura: pod postem pojawi się Twoja sygnatura (o ile jesteś zarejestrowanym użytkownikiem)."; +$l['options_emailnotify'] = "Powiadomienie: kiedy ktoś odpowie, otrzymasz powiadomienie e-mailem (o ile jesteś zarejestrowanym użytkownikiem)."; +$l['options_disablesmilies'] = "Wyłącz emotikony: w tym poście emotikony nie będą widoczne."; +$l['preview_post'] = "Podgląd"; +$l['update_post'] = "Aktualizuj post"; +$l['poll'] = "Ankieta"; +$l['poll_desc'] = "Możesz dodać ankietę do wątku."; +$l['poll_check'] = "Chcę dodać ankietę"; +$l['num_options'] = "Liczba odpowiedzi:"; +$l['max_options'] = "(maksymalnie {1})"; +$l['delete_now'] = "Usuń"; +$l['edit_time_limit'] = "Nie możesz edytować tego posta. Możesz edytować posty tylko przez pierwsze {1} minut po ich napisaniu."; +$l['no_prefix'] = "Bez prefiksu"; + +$l['redirect_nodelete'] = "Post nie został usunięty - nie zaznaczono pola \"Usunąć?\"."; +$l['redirect_norestore'] = "Post nie został przywrócony - nie zaznaczono pola \"Przywrócić\"."; +$l['redirect_postedited'] = "Post został wyedytowany.
    "; +$l['redirect_postedited_redirect'] = "Teraz nastąpi przeniesienie do wątku."; +$l['redirect_postedited_poll'] = "Post został wyedytowany.
    Postanowiono dodać ankietę do tego posta, więc teraz nastąpi przeniesienie do strony tworzenia ankiety."; +$l['error_invalidpost'] = "Post nie istnieje. Sprawdź czy post istnieje i spróbuj ponownie."; +$l['redirect_threaddeleted'] = "Wątek został usunięty.
    Teraz nastąpi przeniesienie na forum."; +$l['redirect_postdeleted'] = "Post został usunięty.
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_threadrestored'] = "Wątek został przywrócony.
    Teraz nastąpi przeniesienie do działu."; +$l['redirect_postrestored'] = "Post został przywrócony.
    Teraz nastÄ…pi przeniesienie do wÄ…tku."; +$l['redirect_threadclosed'] = "Nie możesz edytować postów - wÄ…tek zostaÅ‚ zamkniÄ™ty przez moderatora."; +$l['redirect_post_moderation'] = "Każda edycja posta przed publikacjÄ… musi zostać zatwierdzona przez moderatora. Teraz nastÄ…pi przeniesienie do wÄ…tku."; +$l['redirect_thread_moderation'] = "Każda edycja wÄ…tku przed publikacjÄ… musi zostać zatwierdzona przez moderatora. Teraz nastÄ…pi przeniesienie na stronÄ™ głównÄ… forum."; +$l['error_already_delete'] = "Wybrany post zostaÅ‚ już usuniÄ™ty."; + +$l['thread_deleted'] = "UsuniÄ™to wÄ…tek"; +$l['post_deleted'] = "UsuniÄ™to post"; +$l['thread_soft_deleted'] = "Nietrwale usuniÄ™to wÄ…tek"; +$l['post_soft_deleted'] = "Nietrwale usuniÄ™to post"; +$l['thread_restored'] = "Przywrócono wÄ…tek"; +$l['post_restored'] = "Przywrócono post"; + +$l['error_already_deleted'] = 'Wybrany post zostaÅ‚ już usuniÄ™ty.'; diff --git a/Upload/inc/languages/polish/forumdisplay.lang.php b/Upload/inc/languages/polish/forumdisplay.lang.php new file mode 100644 index 0000000..1283eb9 --- /dev/null +++ b/Upload/inc/languages/polish/forumdisplay.lang.php @@ -0,0 +1,100 @@ +PoddziaÅ‚y:"; +$l['asc'] = "rosn."; +$l['desc'] = "mal."; +$l['forum_announcements'] = "OgÅ‚oszenia"; +$l['sticky_threads'] = "PrzypiÄ™te wÄ…tki"; +$l['normal_threads'] = "ZwykÅ‚e wÄ…tki"; +$l['icon_dot'] = "Zawiera posty napisane przez Ciebie."; +$l['icon_no_new'] = "Brak nowych postów."; +$l['icon_new'] = "Nowe posty."; +$l['icon_hot'] = " Popularny wÄ…tek"; +$l['icon_lock'] = " ZamkniÄ™ty wÄ…tek"; +$l['attachment_count'] = "Ten wÄ…tek zawiera 1 zaÅ‚Ä…cznik."; +$l['attachment_count_multiple'] = "Ten wÄ…tek zawiera {1} zaÅ‚Ä…czników."; +$l['rss_discovery_forum'] = "Ostatnie wÄ…tki w {1}"; +$l['forum_unapproved_posts_count'] = "Aktualnie jest {1} ukrytych postów w tym dziale."; +$l['forum_unapproved_post_count'] = "Aktualnie jest 1 ukryty post w tym dziale."; +$l['forum_unapproved_threads_count'] = "Aktualnie jest {1} ukrytych wÄ…tków w tym dziale."; +$l['forum_unapproved_thread_count'] = "Aktualnie jest 1 ukryty wÄ…tek w tym dziale."; +$l['thread_unapproved_posts_count'] = "Aktualnie jest {1} ukrytych postów w tym wÄ…tku."; +$l['thread_unapproved_post_count'] = "Aktualnie jest 1 ukryty post w tym wÄ…tku."; +$l['page_selected'] = "Wybrano wszystkie {1} wÄ…tki na tej stronie."; +$l['all_selected'] = "Wybrano wszystkie {1} wÄ…tki w tym dziale."; +$l['select_all'] = "Zaznacz wszystkie {1} wÄ…tki w tym dziale."; +$l['clear_selection'] = "Wyczyść zaznaczenie."; + +$l['error_containsnoforums'] = "DziaÅ‚, który aktualnie przeglÄ…dasz, nie zawiera poddziałów."; + +$l['inline_edit_description'] = '(Kliknij i przytrzymaj, aby edytować)'; diff --git a/Upload/inc/languages/polish/global.lang.php b/Upload/inc/languages/polish/global.lang.php new file mode 100644 index 0000000..d463442 --- /dev/null +++ b/Upload/inc/languages/polish/global.lang.php @@ -0,0 +1,553 @@ +Witaj, {1}. Ostatnia wizyta: {2}"; +$l['welcome_guest'] = "Witaj!"; +$l['welcome_current_time'] = "Aktualny czas: {1}"; + +$l['moved_prefix'] = "Przeniesiony:"; +$l['poll_prefix'] = "Ankieta:"; + +$l['forumbit_announcements'] = "OgÅ‚oszenia"; +$l['forumbit_stickies'] = "PrzypiÄ™te wÄ…tki"; +$l['forumbit_forum'] = "DziaÅ‚"; +$l['forumbit_threads'] = "WÄ…tków"; +$l['forumbit_posts'] = "Postów"; +$l['forumbit_lastpost'] = "Ostatni post"; +$l['forumbit_moderated_by'] = "Moderowane przez:"; +$l['new_posts'] = "DziaÅ‚ zawiera nowe posty"; +$l['no_new_posts'] = "DziaÅ‚ nie zawiera nowych postów"; +$l['click_mark_read'] = "Kliknij, aby zaznaczyć ten dziaÅ‚ jako przeczytany"; +$l['forum_locked'] = "DziaÅ‚ jest zablokowany"; +$l['forum_redirect'] = "DziaÅ‚ zawierajÄ…cy przekierowanie"; +$l['lastpost_never'] = "Nigdy"; +$l['viewing_one'] = " (1 przeglÄ…dajÄ…cy)"; +$l['viewing_multiple'] = " ({1} przeglÄ…dajÄ…cych)"; +$l['by'] = "przez"; +$l['more_subforums'] = "i {1} wiÄ™cej."; + +$l['password_required'] = "Wymagane hasÅ‚o"; +$l['forum_password_note'] = "Aby dostać siÄ™ do tego dziaÅ‚u należy podać hasÅ‚o."; +$l['enter_password_below'] = "Wpisz hasÅ‚o w poniższe pole:"; +$l['verify_forum_password'] = "Sprawdź hasÅ‚o"; +$l['wrong_forum_password'] = "Wprowadzone hasÅ‚o jest niepoprawne. Spróbuj ponownie."; + +$l['reset_button'] = "Wyczyść"; +$l['username'] = "Login:"; +$l['username1'] = "Adres e-mail:"; +$l['username2'] = "Login/Adres e-mail:"; +$l['password'] = "HasÅ‚o:"; +$l['login_username'] = "Login"; +$l['login_username1'] = "Adres e-mail"; +$l['login_username2'] = "Login/Adres e-mail"; +$l['login_password'] = "HasÅ‚o"; +$l['lost_password'] = "Nie pamiÄ™tam hasÅ‚a"; +$l['remember_me'] = "ZapamiÄ™taj mnie"; +$l['remember_me_desc'] = "Jeżeli to pole zostanie zaznaczone, wszystkie wpisane dane zostanÄ… zapamiÄ™tane na tym komputerze. W przeciwnym wypadku dane te zostanÄ… wyczyszczone po zamkniÄ™ciu przeglÄ…darki."; + +$l['month_1'] = "StyczeÅ„"; +$l['month_2'] = "Luty"; +$l['month_3'] = "Marzec"; +$l['month_4'] = "KwiecieÅ„"; +$l['month_5'] = "Maj"; +$l['month_6'] = "Czerwiec"; +$l['month_7'] = "Lipiec"; +$l['month_8'] = "SierpieÅ„"; +$l['month_9'] = "WrzesieÅ„"; +$l['month_10'] = "Październik"; +$l['month_11'] = "Listopad"; +$l['month_12'] = "GrudzieÅ„"; + +$l['sunday'] = "Niedziela"; +$l['monday'] = "PoniedziaÅ‚ek"; +$l['tuesday'] = "Wtorek"; +$l['wednesday'] = "Åšroda"; +$l['thursday'] = "Czwartek"; +$l['friday'] = "PiÄ…tek"; +$l['saturday'] = "Sobota"; +$l['short_monday'] = "Pon"; +$l['short_tuesday'] = "Wt"; +$l['short_wednesday'] = "Åšr"; +$l['short_thursday'] = "Czw"; +$l['short_friday'] = "Pt"; +$l['short_saturday'] = "So"; +$l['short_sunday'] = "N"; + +$l['yes'] = "Tak"; +$l['no'] = "Nie"; + +$l['and'] = "i"; +$l['date'] = "Data"; + +$l['nobody'] = "Nikt"; + +$l['attachments'] = "ZaÅ‚Ä…czniki"; +$l['attachments_desc'] = "Możesz zaÅ‚Ä…czyć jeden lub wiÄ™cej zaÅ‚Ä…czników. Wybierz plik i kliknij \"Dodaj zaÅ‚Ä…cznik\", aby wysÅ‚ać go na serwer."; +$l['remove_attachment'] = "UsuÅ„"; +$l['approve_attachment'] = "Zatwierdź"; +$l['unapprove_attachment'] = "Ukryj"; +$l['insert_attachment_post'] = "Wstaw do posta"; +$l['new_attachment'] = "Nowy zaÅ‚Ä…cznik:"; +$l['add_attachment'] = "Dodaj zaÅ‚Ä…cznik"; +$l['update_attachment'] = "Aktualizuj zaÅ‚Ä…cznik"; +$l['post_preview'] = "PodglÄ…d posta"; +$l['change_user'] = "zmieÅ„ użytkownika"; +$l['post_icon'] = "Ikona posta"; +$l['no_post_icon'] = "bez ikony"; +$l['thread_subscription_method'] = "Subskrypcja wÄ…tku:"; +$l['thread_subscription_method_desc'] = "Wybierz sposób powiadamiania i subskrypcji tego wÄ…tku. (tylko dla zarejestrowanych)"; +$l['no_subscribe'] = "Nie subskrybuj wÄ…tku"; +$l['no_subscribe_notification'] = "Subskrybuj wÄ…tek, ale nie wysyÅ‚aj powiadomieÅ„ o nowej odpowiedzi"; +$l['instant_email_subscribe'] = "Subskrybuj wÄ…tek i wysyÅ‚aj powiadomienia e-mail o nowej odpowiedzi"; +$l['instant_pm_subscribe'] = "Subskrybuj wÄ…tek i wysyÅ‚aj powiadomienia poprzez prywatnÄ… wiadomość o nowej odpowiedzi"; + +$l['today'] = "Dzisiaj"; +$l['yesterday'] = "Wczoraj"; +$l['error'] = "Informacja"; + +$l['multipage_pages'] = "Strony ({1}):"; +$l['multipage_last'] = "Ostatnia"; +$l['multipage_first'] = "Pierwsza"; +$l['multipage_next'] = "NastÄ™pna"; +$l['multipage_previous'] = "Poprzednia"; +$l['multipage_link_start'] = " ..."; +$l['multipage_link_end'] = "... "; +$l['multipage_jump'] = "Idź do strony"; + +$l['editor_bold'] = "Pogrubienie"; +$l['editor_italic'] = "Kursywa"; +$l['editor_underline'] = "PodkreÅ›lenie"; +$l['editor_strikethrough'] = "PrzekreÅ›lenie"; +$l['editor_subscript'] = "Indeks dolny"; +$l['editor_superscript'] = "Indeks górny"; +$l['editor_alignleft'] = "Wyrównaj do lewej"; +$l['editor_center'] = "WyÅ›rodkuj"; +$l['editor_alignright'] = "Wyrównaj do prawej"; +$l['editor_justify'] = "Wyjustuj"; +$l['editor_fontname'] = "Nazwa czcionki"; +$l['editor_fontsize'] = "Rozmiar czcionki"; +$l['editor_fontcolor'] = "Kolor czcionki"; +$l['editor_removeformatting'] = "UsuÅ„ formatowanie"; +$l['editor_cut'] = "Wytnij"; +$l['editor_copy'] = "Kopiuj"; +$l['editor_paste'] = "Wklej"; +$l['editor_cutnosupport'] = "Twoja przeglÄ…darka nie obsÅ‚uguje wycinania. Skorzystaj ze skrótu klawiszowego Ctrl/Cmd+X."; +$l['editor_copynosupport'] = "Twoja przeglÄ…darka nie obsÅ‚uguje kopiowania. Skorzystaj ze skrótu klawiszowego Ctrl/Cmd+C."; +$l['editor_pastenosupport'] = "Twoja przeglÄ…darka nie obsÅ‚uguje wklejania. Skorzystaj ze skrótu klawiszowego Ctrl/Cmd+V."; +$l['editor_pasteentertext'] = "Wklej swój tekst do poniższego pola:"; +$l['editor_pastetext'] = "Wklej tekst"; +$l['editor_numlist'] = "Lista numerowana"; +$l['editor_bullist'] = "Lista punktowana"; +$l['editor_undo'] = "Cofnij"; +$l['editor_redo'] = "Ponów"; +$l['editor_rows'] = "Wierszy:"; +$l['editor_cols'] = "Kolumn:"; +$l['editor_inserttable'] = "Wstaw tabelÄ™"; +$l['editor_inserthr'] = "Wstaw poziomÄ… liniÄ™"; +$l['editor_code'] = "Kod"; +$l['editor_php'] = "Kod PHP"; +$l['editor_width'] = "Szerokość (opcjonalnie):"; +$l['editor_height'] = "Wysokość (opcjonalnie):"; +$l['editor_insertimg'] = "Wstaw obrazek"; +$l['editor_email'] = "Adres e-mail:"; +$l['editor_insertemail'] = "Wstaw adres e-mail"; +$l['editor_url'] = "Adres URL:"; +$l['editor_insertlink'] = "Wstaw link"; +$l['editor_unlink'] = "UsuÅ„ link"; +$l['editor_more'] = "WiÄ™cej"; +$l['editor_insertemoticon'] = "Wstaw emotikon"; +$l['editor_videourl'] = "Adres URL wideo:"; +$l['editor_videotype'] = "Typ wideo:"; +$l['editor_insert'] = "Wstaw"; +$l['editor_insertyoutubevideo'] = "Wstaw wideo z serwisu YouTube"; +$l['editor_currentdate'] = "Wstaw aktualnÄ… datÄ™"; +$l['editor_currenttime'] = "Wstaw aktualny godzinÄ™"; +$l['editor_print'] = "Drukuj"; +$l['editor_viewsource'] = "Pokaż źródÅ‚o"; +$l['editor_description'] = "Opis (opcjonalnie):"; +$l['editor_enterimgurl'] = "Wprowadź adres URL obrazka:"; +$l['editor_enteremail'] = "Wprowadź adres e-mail:"; +$l['editor_enterdisplayedtext'] = "Wpisz tekst z obrazka:"; +$l['editor_enterurl'] = "Wprowadź adres URL:"; +$l['editor_enteryoutubeurl'] = "Wprowadź adres URL wideo lub jego ID:"; +$l['editor_insertquote'] = "Wstaw cytat"; +$l['editor_invalidyoutube'] = "NieprawidÅ‚owe wideo"; +$l['editor_dailymotion'] = "Dailymotion"; +$l['editor_metacafe'] = "MetaCafe"; +$l['editor_veoh'] = "Veoh"; +$l['editor_vimeo'] = "Vimeo"; +$l['editor_youtube'] = "Youtube"; +$l['editor_facebook'] = "Facebook"; +$l['editor_liveleak'] = "LiveLeak"; +$l['editor_insertvideo'] = "Wstaw wideo"; +$l['editor_maximize'] = "Maksymalizuj"; + + +$l['quote'] = "Cytat:"; +$l['wrote'] = "napisaÅ‚(a):"; +$l['code'] = "Kod:"; +$l['php_code'] = "Kod PHP:"; +$l['posted_image'] = "[Obrazek: {1}]"; +$l['posted_video'] = "[Wideo: {1}]"; +$l['linkback'] = "Cytowany post"; + +$l['at'] = "na"; +$l['na'] = "N/A"; +$l['guest'] = "Gość"; +$l['unknown'] = "Nieznany"; +$l['never'] = "Nigdy"; +$l['postbit_posts'] = "Liczba postów:"; +$l['postbit_threads'] = "Liczba wÄ…tków:"; +$l['postbit_group'] = "Grupa:"; +$l['postbit_joined'] = "DoÅ‚Ä…czyÅ‚:"; +$l['postbit_status'] = "Status:"; +$l['postbit_attachments'] = "ZaÅ‚Ä…czone pliki"; +$l['postbit_attachment_size'] = "Rozmiar:"; +$l['postbit_attachment_downloads'] = "PobraÅ„:"; +$l['postbit_attachments_images'] = "Obrazki"; +$l['postbit_attachments_thumbnails'] = "Miniatury"; +$l['postbit_unapproved_attachments'] = "{1} ukrytych zaÅ‚Ä…czników."; +$l['postbit_unapproved_attachment'] = "1 ukryty zaÅ‚Ä…cznik."; +$l['postbit_status_online'] = "Online"; +$l['postbit_status_offline'] = "Offline"; +$l['postbit_status_away'] = "NiedostÄ™pny"; +$l['postbit_edited'] = "Ten post byÅ‚ ostatnio modyfikowany: {1} przez"; +$l['postbit_editreason'] = "Powód edycji"; +$l['postbit_ipaddress'] = "Adres IP:"; +$l['postbit_ipaddress_logged'] = "zapisano"; +$l['postbit_post'] = "Post:"; +$l['postbit_reputation'] = "Reputacja:"; +$l['postbit_reputation_add'] = "Przyznaj punkt reputacji za ten post"; +$l['postbit_website'] = "Odwiedź stronÄ™ użytkownika"; +$l['postbit_email'] = "WyÅ›lij wiadomość do użytkownika"; +$l['postbit_find'] = "Znajdź wszystkie posty użytkownika"; +$l['postbit_report'] = "ZgÅ‚oÅ› post do moderatora"; +$l['postbit_quote'] = "Odpowiedz cytujÄ…c ten post"; +$l['postbit_qdelete_post'] = "UsuÅ„ ten post"; +$l['postbit_qdelete_thread'] = "UsuÅ„ ten wÄ…tek"; +$l['postbit_qrestore_post'] = "Przywróć ten post"; +$l['postbit_qrestore_thread'] = "Przywróć ten wÄ…tek"; +$l['postbit_profile'] = "Pokaż profil użytkownika"; +$l['postbit_pm'] = "WyÅ›lij prywatnÄ… wiadomość"; +$l['postbit_edit'] = "Edytuj ten post"; +$l['postbit_multiquote'] = "Dodaj do odpowiedzi jako cytat"; +$l['postbit_quick_edit'] = "Szybka edycja"; +$l['postbit_full_edit'] = "PeÅ‚na edycja"; +$l['postbit_show_ignored_post'] = "Pokaż post"; +$l['postbit_currently_ignoring_user'] = "Zawartość posta zostaÅ‚a ukryta, ponieważ {1} jest na liÅ›cie ignorowanych."; +$l['postbit_warning_level'] = "Poziom ostrzeżeÅ„:"; +$l['postbit_warn'] = "Dodaj ostrzeżenie za ten post"; +$l['postbit_purgespammer'] = "UsuÅ„ spamera"; + +$l['postbit_button_reputation_add'] = 'Dodaj punkt reputacji'; +$l['postbit_button_website'] = 'Strona WWW'; +$l['postbit_button_email'] = 'E‑mail'; +$l['postbit_button_find'] = 'Szukaj'; +$l['postbit_button_report'] = 'ZgÅ‚oÅ›'; +$l['postbit_button_quote'] = 'Odpowiedz'; +$l['postbit_button_qdelete'] = 'UsuÅ„'; +$l['postbit_button_qrestore'] = 'Przywróć'; +$l['postbit_button_profile'] = 'Profil'; +$l['postbit_button_pm'] = 'PW'; +$l['postbit_button_warn'] = 'Ostrzeż'; +$l['postbit_button_edit'] = 'Edytuj'; +$l['postbit_button_multiquote'] = 'Cytuj'; +$l['postbit_button_reply_pm'] = 'Odpowiedz'; +$l['postbit_button_reply_all'] = 'Odpowiedz wszystkim'; +$l['postbit_button_forward'] = 'PrzeÅ›lij dalej'; +$l['postbit_button_delete_pm'] = 'UsuÅ„'; +$l['postbit_button_purgespammer'] = "UsuÅ„ spamera"; + +$l['forumjump'] = "Skocz do:"; +$l['forumjump_select'] = "Wybierz:"; +$l['forumjump_pms'] = "Prywatne wiadomoÅ›ci"; +$l['forumjump_usercp'] = "Panel użytkownika"; +$l['forumjump_wol'] = "Kto jest online"; +$l['forumjump_search'] = "Szukaj..."; +$l['forumjump_home'] = "Strona główna forum"; + +$l['redirect'] = "Teraz nastÄ…pi przeniesienie"; +$l['unknown_error'] = "WystÄ…piÅ‚ nieznany bÅ‚Ä…d."; +$l['post_fetch_error'] = 'WystÄ…piÅ‚ bÅ‚Ä…d podczas wczytywania postów.'; + +$l['smilieinsert'] = "Emotikony"; +$l['smilieinsert_getmore'] = "wiÄ™cej"; +$l['on'] = "wÅ‚Ä…czone"; +$l['off'] = "wyÅ‚Ä…czone"; +$l['unread_report'] = "Notatka dla moderatora: jest jeden nowy raportowany post."; +$l['unread_reports'] = "Notatka dla moderatora: sÄ… nowe raportowane posty ({1})."; +$l['pending_joinrequest'] = "Notatka dla lidera grupy: jest jedno zgÅ‚oszenie do grupy, której jesteÅ› liderem."; +$l['pending_joinrequests'] = "Notatka dla lidera grupy: jest {1} zgÅ‚oszeÅ„ do grupy, której jesteÅ› liderem."; + +$l['year'] = "Rok"; +$l['year_short'] = "r"; +$l['years'] = "Lat"; +$l['years_short'] = "l"; +$l['month'] = "MiesiÄ…c"; +$l['month_short'] = "m-c"; +$l['months'] = "MiesiÄ™cy"; +$l['months_short'] = "m-cy"; +$l['week'] = "TydzieÅ„"; +$l['week_short'] = "tydz"; +$l['weeks'] = "Tygodni"; +$l['weeks_short'] = "tyg"; +$l['day'] = "DzieÅ„"; +$l['day_short'] = "d"; +$l['days'] = "Dni"; +$l['days_short'] = "d"; +$l['hour'] = "Godzina"; +$l['hour_short'] = "godz"; +$l['hours'] = "Godzin"; +$l['hours_short'] ="godz"; +$l['minute'] = "Minuta"; +$l['minute_short'] ="min"; +$l['minutes'] = "Minut"; +$l['minutes_short'] = "min"; +$l['second'] = "Sekunda"; +$l['second_short'] ="s"; +$l['seconds'] = "Sekund"; +$l['seconds_short'] = "s"; + +$l['rel_in'] = "W ciÄ…gu "; +$l['rel_ago'] = "temu"; +$l['rel_less_than'] = "Mniej niż "; +$l['rel_time'] = "{1} {2} {3} {4}"; +$l['rel_minutes_single'] = "minutÄ™"; +$l['rel_minutes_plural'] = "minut(y)"; +$l['rel_hours_single'] = "godzinÄ™"; +$l['rel_hours_plural'] = "godzin(y)"; + +$l['permanent'] = "Na zawsze"; +$l['save_draft'] = "Zapisz szkic"; +$l['go'] = "OK"; +$l['bbclosed_warning'] = "Forum jest aktualnie zamkniÄ™te."; +$l['banned_warning'] = "Twoje konto jest zbanowane."; +$l['banned_warning2'] = "Powód bana"; +$l['banned_warning3'] = "Ban zostanie zniesiony"; +$l['banned_lifted_never'] = "nigdy"; +$l['banned_email_warning'] = "Używasz adresu email, który nie zostaÅ‚ dozwolony na tym forum. ZmieÅ„ adres email, aby móc kontynuować."; +$l['powered_by'] = "Polskie tÅ‚umaczenie © 2007-".date("Y")." Polski Support MyBB
    Silnik forum"; +$l['copyright'] = "Copyright"; +$l['attach_quota'] = "Aktualnie używasz {1} (przydzielone miejsce: {2})"; +$l['view_attachments'] = "[Pokaż moje załączniki]"; +$l['unlimited'] = "nieograniczone"; + +$l['click_hold_edit'] = "(Kliknij i przytrzymaj, aby edytować)"; + +$l['guest_count'] = "1 gość"; +$l['guest_count_multiple'] = "{1} gości"; + +$l['size_yb'] = "YB"; +$l['size_zb'] = "ZB"; +$l['size_eb'] = "EB"; +$l['size_pb'] = "PB"; +$l['size_tb'] = "TB"; +$l['size_gb'] = "GB"; +$l['size_mb'] = "MB"; +$l['size_kb'] = "KB"; +$l['size_bytes'] = "bajtów"; + +$l['slaps'] = "rzuca w"; +$l['with_trout'] = "zgniłymi jajami."; + +$l['mybb_engine'] = "Silnik MyBB"; +$l['quickdelete_confirm'] = "Czy na pewno chcesz usunąć ten post?"; +$l['quickrestore_confirm'] = "Czy na pewno chcesz przywrócić ten post?"; +$l['newpm_notice_one'] = "Masz jedną nieprzeczytaną prywatną wiadomość od {1}, zatytułowaną {4}"; +$l['newpm_notice_multiple'] = "Liczba nowych nieprzeczytanych prywatnych wiadomości: {1}. Ostatnia z nich to wiadomość od {2}, zatytułowana {5}"; +$l['deleteevent_confirm'] = "Czy na pewno chcesz usunąć to wydarzenie?"; +$l['removeattach_confirm'] = "Czy na pewno chcesz usunąć zaznaczone załączniki?"; + +$l['latest_threads'] = "Najnowsze wątki"; + +$l['folder_inbox'] = "Odebrane"; +$l['folder_sent_items'] = "Wysłane"; +$l['folder_drafts'] = "Szkice"; +$l['folder_trash'] = "Usunięte"; +$l['folder_untitled'] = "Bez nazwy"; + +$l['standard_mod_tools'] = "Standardowe narzędzia"; +$l['custom_mod_tools'] = "Niestandardowe narzędzia"; + +$l['error_loadlimit'] = "Serwer jest zbyt obciążony. Wróć później, gdy serwer będzie mniej obciążony."; +$l['error_boardclosed'] = "Forum jest aktualnie zamknięte. Poniżej znajduje się powód podany przez administratora."; +$l['error_banned'] = "Twoje konto zostało zbanowane. Nie możesz pisać postów ani czytać wątków. Skontaktuj się z administratorem."; +$l['error_cannot_upload_php_post'] = "Wysyłanie pliku nie powiodło się - rozmiar pliku przekracza limit określony w konfiguracji PHP (post_max_size). Kliknij przycisk \"Wstecz\"."; +$l['error_database_repair'] = "MyBB automatycznie naprawia uszkodzoną tabelę bazy danych."; + +$l['unknown_user_trigger'] = "Wystąpił nieznany błąd."; +$l['warnings'] = "Wystąpiły następujące problemy:"; + +$l['ajax_loading'] = "Wczytywanie
    Proszę czekać..."; +$l['saving_changes'] = "Zapisywanie zmian..."; +$l['refresh'] = "Odśwież"; +$l['select_language'] = "Wybierz język"; +$l['select_theme'] = "Wybierz styl"; + +$l['invalid_post_code'] = "Niepoprawny kod autoryzacji. Czy na pewno próbujesz uruchomić tę funkcję w poprawny sposób? Spróbuj ponownie."; +$l['invalid_captcha'] = "Aby kontynuować, przepisz dokładnie kod z obrazka."; +$l['invalid_captcha_verify'] = "Wprowadzony kod z obrazka jest nieprawidłowy. Spróbuj ponownie."; +$l['invalid_captcha_transmit'] = "Wystąpił błąd. Spróbuj ponownie."; +$l['captcha_fetch_failure'] = 'Wystąpił błąd podczas wczytywania nowego kodu.'; +$l['question_fetch_failure'] = 'Wystąpił błąd podczas wczytywania nowego pytania'; +$l['invalid_ayah_result'] = "Test \"Are you Human\" nie został ukończony. Spróbuj ponownie."; + +$l['timezone_gmt_minus_1200'] = "(GMT -12:00) Wyspy Marshalla"; +$l['timezone_gmt_minus_1100'] = "(GMT -11:00) Wyspa Midway, Nome"; +$l['timezone_gmt_minus_1000'] = "(GMT -10:00) Hawaje, Papeete"; +$l['timezone_gmt_minus_950'] = "(GMT -9:30) Markizy"; +$l['timezone_gmt_minus_900'] = "(GMT -9:00) Alaska"; +$l['timezone_gmt_minus_800'] = "(GMT -8:00) Czas pacyficzny (USA i Kanada)"; +$l['timezone_gmt_minus_700'] = "(GMT -7:00) Czas górski (USA i Kanada)"; +$l['timezone_gmt_minus_600'] = "(GMT -6:00) Czas środkowy (USA i Kanada)"; +$l['timezone_gmt_minus_500'] = "(GMT -5:00) Czas wschodni (USA i Kanada)"; +$l['timezone_gmt_minus_450'] = "(GMT -4:30) Caracas"; +$l['timezone_gmt_minus_400'] = "(GMT -4:00) Czas atlantycki (Kanada), La Paz, Halifax"; +$l['timezone_gmt_minus_350'] = "(GMT -3:30) Nowa Funlandia"; +$l['timezone_gmt_minus_300'] = "(GMT -3:00) Brazylia, Buenos Aires, Georgetown"; +$l['timezone_gmt_minus_200'] = "(GMT -2:00) Środkowy Atlantyk, Georgia Południowa i Sandwich Południowy"; +$l['timezone_gmt_minus_100'] = "(GMT -1:00) Azory, Wyspy Zielonego Przylądka"; +$l['timezone_gmt'] = "(GMT) Casablanca, Dublin, Edinburgh, Londyn, Lizbona, Monrovia"; +$l['timezone_gmt_100'] = "(GMT +1:00) Berlin, Bruksela, Kopenhaga, Madryt, Paryż, Rzym, Warszawa"; +$l['timezone_gmt_200'] = "(GMT +2:00) Ateny, Stambuł, Kair, Jerozolima, Południowa Afryka"; +$l['timezone_gmt_300'] = "(GMT +3:00) Kaliningrad, Mińsk, Bagdad, Riad, Moskwa, Nairobi"; +$l['timezone_gmt_350'] = "(GMT +3:30) Teheran"; +$l['timezone_gmt_400'] = "(GMT +4:00) Moskwa, Abu Dhabi, Baku, Maskat, Tbilisi"; +$l['timezone_gmt_450'] = "(GMT +4:30) Kabul"; +$l['timezone_gmt_500'] = "(GMT +5:00) Islamabad, Karaczi, Taszkient"; +$l['timezone_gmt_550'] = "(GMT +5:30) Bombaj, Kalkuta, Madras, Nowe Delhi"; +$l['timezone_gmt_575'] = "(GMT +5:45) Katmandu"; +$l['timezone_gmt_600'] = "(GMT +6:00) Ałma-ata, Dhakra, Jekaterinburg"; +$l['timezone_gmt_650'] = "(GMT +6:30) Rangun"; +$l['timezone_gmt_700'] = "(GMT +7:00) Bangkok, Hanoi, Dżakarta"; +$l['timezone_gmt_800'] = "(GMT +8:00) Pekin, Hongkong, Perth, Singapur, Taipei"; +$l['timezone_gmt_900'] = "(GMT +9:00) Osaka, Sapporo, Seul, Tokio, Irkuck"; +$l['timezone_gmt_950'] = "(GMT +9:30) Adelajda, Darwin"; +$l['timezone_gmt_1000'] = "(GMT +10:00) Melbourne, Papua Nowa Gwinea, Sydney, Jakuck"; +$l['timezone_gmt_1050'] = "(GMT +10:30) Wyspa Lord Howe"; +$l['timezone_gmt_1100'] = "(GMT +11:00) Magadan, Nowa Kaledonia, Wyspy Salomona, Władywostok"; +$l['timezone_gmt_1150'] = "(GMT +11:30) Wyspa Norfolk"; +$l['timezone_gmt_1200'] = "(GMT +12:00) Auckland, Wellington, Fidżi, Wyspa Marshalla"; +$l['timezone_gmt_1275'] = "(GMT +12:45) Wyspy Chatham"; +$l['timezone_gmt_1300'] = "(GMT +13:00) Samoa, Tonga, Tokelau"; +$l['timezone_gmt_1400'] = "(GMT +14:00) Wyspy Line"; +$l['timezone_gmt_short'] = "GMT {1}({2})"; + +$l['missing_task'] = "Błąd: plik zadań nie istnieje"; +$l['task_backup_cannot_write_backup'] = "Błąd: zadanie tworzenia kopii zapasowej bazy danych nie może zostać wykonane - nie ma uprawnień do zapisywania w katalogu kopii zapasowych."; +$l['task_backup_ran'] = "Zadanie tworzenia kopii zapasowej bazy danych zostało wykonane."; +$l['task_checktables_ran'] = "Zadanie sprawdzania tabel zostało wykonane. Nie znaleziono żadnych uszkodzonych tabel."; +$l['task_checktables_ran_found'] = "Uwaga: Zadanie sprawdzania tabel bazy danych zostało wykonane. Naprawiono {1} tabel."; +$l['task_dailycleanup_ran'] = "Zadanie codziennego oczyszczania zostało wykonane."; +$l['task_hourlycleanup_ran'] = "Zadanie cogodzinnego oczyszczania zostało wykonane."; +$l['task_logcleanup_ran'] = "Zadanie czyszczenia logów zostało wykonane. Usunięto wszystkie przestarzałe wpisy."; +$l['task_promotions_ran'] = "Zadanie przydzielania awansów zostało wykonane."; +$l['task_threadviews_ran'] = "Zadanie przeliczania wyświetleń wątków zostało wykonane."; +$l['task_usercleanup_ran'] = "Zadanie oczyszczania statusu użytkowników zostało wykonane."; +$l['task_massmail_ran'] = "Zadanie masowego wysyłania wiadomości e-mail zostało wykonane."; +$l['task_userpruning_ran'] = "Zadanie czyszczenia użytkowników zostało wykonane."; +$l['task_delayedmoderation_ran'] = "Zadanie opóźnionej moderacji zostało wykonane."; +$l['task_massmail_ran_errors'] = "Wystąpił jeden lub kilka błędów podczas wysyłania wiadomości do \"{1}\": +{2}"; +$l['task_versioncheck_ran'] = "Sprawdzenie nowej wersji zostało wykonane pomyślnie."; +$l['task_versioncheck_ran_errors'] = "Nie można połączyć się z serwerami MyBB, aby sprawdzić dostępność nowej wersji."; +$l['task_recachestylesheets_ran'] = 'Zaktualizowano pamięć podręczną {1} arkuszy stylów kaskadowych.'; + +$l['dismiss_notice'] = "Usuń tę notatkę"; + +$l['next'] = "Dalej"; +$l['previous'] = "Wstecz"; +$l['delete'] = "Usuń"; + +$l['massmail_username'] = "Nick"; +$l['email_addr'] = "Adres email"; +$l['board_name'] = "Nazwa forum"; +$l['board_url'] = "Adres forum"; + +$l['comma'] = ", "; + +$l['debug_generated_in'] = "Wygenerowano w ciągu {1}"; +$l['debug_weight'] = "({1}% PHP / {2}% {3})"; +$l['debug_sql_queries'] = "Liczba zapytań SQL: {1}"; +$l['debug_server_load'] = "Obciążenie serwera: {1}"; +$l['debug_memory_usage'] = "Zużycie pamięci: {1}"; +$l['debug_advanced_details'] = "Szczegóły"; + +$l['error_emailflooding_1_second'] = "Przed wysłaniem kolejnej wiadomości e-mail musisz odczekać następującą liczbę minut: {1}. Odczekaj 1 sekundę i spróbuj ponownie."; +$l['error_emailflooding_seconds'] = "Przed wysłaniem kolejnej wiadomości e-mail musisz odczekać następującą liczbę minut: {1}. Odczekaj {2} sekund(y) i spróbuj ponownie."; +$l['error_emailflooding_1_minute'] = "Przed wysłaniem kolejnej wiadomości e-mail musisz odczekać następującą liczbę minut: {1}. Odczekaj 1 minutę i spróbuj ponownie."; +$l['error_emailflooding_minutes'] = "Przed wysłaniem kolejnej wiadomości e-mail musisz odczekać następującą liczbę minut: {1}. Odczekaj {2} minut(y) i spróbuj ponownie."; +$l['error_invalidfromemail'] = "Nie wprowadzono prawidłowego adresu e-mail nadawcy."; +$l['error_noname'] = "Nie wprowadzono prawidłowej nazwy nadawcy."; +$l['your_email'] = "Twój adres e-mail:"; +$l['email_note'] = "Wprowadź tu swój adres e-mail."; +$l['your_name'] = "Twoje imię:"; +$l['name_note'] = "Wprowadź tu swoje imię lub pseudonim."; + +$l['january'] = "styczeń"; +$l['february'] = "luty"; +$l['march'] = "marzec"; +$l['april'] = "kwiecień"; +$l['may'] = "maj"; +$l['june'] = "czerwiec"; +$l['july'] = "lipiec"; +$l['august'] = "sierpień"; +$l['september'] = "wrzesień"; +$l['october'] = "październik"; +$l['november'] = "listopad"; +$l['december'] = "grudzień"; + +$l['moderation_forum_attachments'] = "Nowe załaczniki z tego działu muszą zostać zaakceptowane przed moderatora."; +$l['moderation_forum_posts'] = "Nowe posty z tego działu muszą zostać zaakceptowane przed moderatora."; +$l['moderation_user_posts'] = "Nowe posty twojego autorstwa muszą zostać zaakceptowane przed moderatora."; +$l['moderation_forum_thread'] = "Nowe wątki z tego działu muszą zostać zaakceptowane przed moderatora."; +$l['moderation_forum_edits'] = "Edycje postów z tego działu muszą zostać zaakceptowane przed moderatora."; +$l['moderation_forum_edits_quick'] = "Nowe wątki z tego działu muszą zostać zaakceptowane przed moderatora."; +$l['awaiting_message_single'] = "Użytkownik oczekuje na aktywację. Aby przeprowadzić aktywację, przejdź do ACP."; +$l['awaiting_message_plural'] = "Użytkowników oczekujących na aktywację: {1}. Aby przeprowadzić aktywację, przejdź do ACP."; + +$l['select2_match'] = "Dostępny jest jeden wynik. Wciśnij enter, aby go wybrać."; +$l['select2_matches'] = "Dostępnych wyników: {1}. Użyj strzałek w dół i w górę, aby nawigować."; +$l['select2_nomatches'] = "Nic nie znaleziono"; +$l['select2_inputtooshort_single'] = "Wpisz co najmniej jeden znak"; +$l['select2_inputtooshort_plural'] = "Wpisz {1} lub więcej znaków"; +$l['select2_inputtoolong_single'] = "Usuń jeden znak"; +$l['select2_inputtoolong_plural'] = "Usuń {1} znaki/znaków"; +$l['select2_selectiontoobig_single'] = "Możesz wybrać tylko jednen wynik"; +$l['select2_selectiontoobig_plural'] = "Możesz wybrać tylko {1} wyniki/wyników"; +$l['select2_loadmore'] = "Wczytywanie większej ilości wyników"; +$l['select2_searching'] = "Wyszukiwanie"; + +$l['stopforumspam_error_decoding'] = 'Wystąpił błąd podczas przetwarzania danych z StopForumSpam.com.'; +$l['stopforumspam_error_retrieving'] = 'Wystąpił błąd podczas pobierania danych z StopForumSpam.com.'; diff --git a/Upload/inc/languages/polish/helpdocs.lang.php b/Upload/inc/languages/polish/helpdocs.lang.php new file mode 100644 index 0000000..05a5974 --- /dev/null +++ b/Upload/inc/languages/polish/helpdocs.lang.php @@ -0,0 +1,71 @@ +
    Po rejestracji możesz pisać wiadomości, ustawiać opcje dotyczące wyglądu i zarządzać swoim profilem. +

    Do korzystania z niektórych funkcji wymagana jest rejestracja - są to: subskrypcje, zmienianie stylów, dostęp do prywatnego notatnika, pisanie prywatnych wiadomości do innych użytkowników."; + +// Help Document 2 +$l['d2_name'] = "Aktualizowanie profilu"; +$l['d2_desc'] = "Zmienianie ustawień w profilu"; +$l['d2_document'] = "Po rejestracji na forum, możesz zmieniać informacje osobiste w profilu, takie jak: komunikatory, hasło, lub - jeśli potrzeba - adres e-mail. Wszystkie z tych informacji i ustawień można ustawić w [panelu użytkownika] znajdującym się u góry po prawej. Następnie kliknij [Edytuj profil] i aktualizuj swoje ustawienia. Pamiętaj o kliknięciu w przycisk [Zatwierdź], aby zmiany zostały zachowane."; + +// Help Document 3 +$l['d3_name'] = "Ciasteczka w MyBB"; +$l['d3_desc'] = "MyBB używa ciasteczek do przechowywania Twoich informacji o zalogowaniu"; +$l['d3_document'] = "MyBulletinBoard tworzy ciasteczka (cookies), w których przechowuje informacje o zalogowaniu. +

    Ciasteczka to małe pliki przechowywane na Twoim komputerze; ciasteczka utworzone przez daną stronę działają tylko na tej stronie. +

    Ciasteczka MyBB sprawdzają kiedy ostatnio i czy w ogóle przeczytano poszczególne wątki. +

    Aby wyczyścić wszystkie ciasteczka, kliknij tutaj."; + +// Help Document 4 +$l['d4_name'] = "Logowanie i wylogowywanie"; +$l['d4_desc'] = "Jak się zalogować i wylogować"; +$l['d4_document'] = "Gdy się zalogujesz, ciasteczka na komputerze zostaną ustawione tak, aby można było przeglądać forum jako zalogowany użytkownik bez ciągłej potrzeby logowania. Wylogowanie czyści ciasteczka dotyczące logowania. +

    Aby się zalogować, kliknij [Logowanie] u góry, pod nawigacją. Aby się wylogować, kliknij [Wyloguj] w tym samym miejscu. Wyczyszczenie ciasteczek w Twojej przeglądarce da ten sam efekt."; + +// Help Document 5 +$l['d5_name'] = "Pisanie nowego wątku"; +$l['d5_desc'] = "Rozpoczynanie wątku na forum"; +$l['d5_document'] = "Jeśli chcesz utworzyć nowy wątek na forum, wybierz dział w którym chcesz go napisać, a następnie kliknij na przycisk [Nowy wątek]. Jeśli zobaczysz komunikat \"Nie masz uprawnień\" oznacza to, że nie masz uprawnień do pisania w danym dziale."; + +// Help Document 6 +$l['d6_name'] = "Odpowiadanie w wątku"; +$l['d6_desc'] = "Odpowiadanie na forum"; +$l['d6_document'] = "Wybierz wątek, w którym chcesz odpowiedzieć. Kliknij na przycisk [Odpowiedz] znajdujący się u góry ekranu. Pamiętaj również, że administrator mógł nałożyć restrykcje, więc możliwe, że nie będziesz mieć możliwości odpowiadania w niektórych działach. +

    Moderator może usunąć wątek, w którym przez określony czas nie będzie odpowiedzi."; + + +// Help Document 7 +$l['d7_name'] = "MyCode"; +$l['d7_desc'] = "Wszystko o MyCode"; +$l['d7_document'] = "Możesz używać MyCode - to uproszczona wersja HTML. +


    [b]Pogrubiony tekst[/b]
       Pogrubiony tekst +

    [i]Kursywa[/i]
       Kursywa +

    [u]Podkreślenie[/u]
       PodkreÅ›lenie +

    [s]Przekreślenie[/s]
       PrzekreÅ›lenie +


    [url]http://www.przykladowy.adres.pl/[/url]
       http://www.przykladowy.adres.pl/ +

    [url=http://www.strona.pl/]Tytuł[/url]
       TytuÅ‚ +

    [email]mojemail@serwer.pl[/email]
       mojemail@serwer.pl +

    [email=mojemail@serwer.pl]Napisz do mnie![/email]
       Napisz do mnie! +

    [email=mojemail@serwer.pl?subject=temat]e-mail z tematem[/email]
       email z tematem +


    [quote]Cytat[/quote]
       Cytat +

    [code]kod[/code]
       kod +


    [img]http://www.php.net/images/php.gif[/img]
        +

    [img=50x50]http://www.php.net/images/php.gif[/img]
        +


    [color=red]Czerwony kolor[/color]
       Czerwony kolor +

    [size=medium]Rozmiar medium[/size]
       Rozmiar medium +

    [font=Tahoma]Czcionka Tahoma[/font]
       Czcionka Tahoma +


    [align=center]Wycentrowany[/align]

    Wycentrowany
    +

    [align=right]Wyrównany do prawej[/align]

    Wyrównany do prawej
    +


    [list]
    [*]Punkt #1
    [*]Punkt #2
    [*]Punkt #3
    [/list]

    • Punkt #1
    • Punkt #2
    • Punkt #3
    • +
    +

    Możesz również ustalić typ punktowania - dostępne typy: liczbowy [list=1] i alfabetyczny [list=a].

    "; diff --git a/Upload/inc/languages/polish/helpsections.lang.php b/Upload/inc/languages/polish/helpsections.lang.php new file mode 100644 index 0000000..f9c6e4a --- /dev/null +++ b/Upload/inc/languages/polish/helpsections.lang.php @@ -0,0 +1,15 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/languages/polish/index.lang.php b/Upload/inc/languages/polish/index.lang.php new file mode 100644 index 0000000..79aa5ee --- /dev/null +++ b/Upload/inc/languages/polish/index.lang.php @@ -0,0 +1,42 @@ +{1}."; +$l['stats_mostonline'] = "NajwiÄ™cej użytkowników online - {1} - byÅ‚o {2} o {3}."; +$l['whos_online'] = "Kto jest online"; +$l['complete_list'] = "Szczegóły"; +$l['online_online_plural'] = "użytkowników aktywnych"; +$l['online_online_singular'] = "użytkownik aktywny"; +$l['online_member_plural'] = "zarejestrowanych"; +$l['online_member_singular'] = "zarejestrowany"; +$l['online_anon_plural'] = "niewidocznych"; +$l['online_anon_singular'] = "niewidoczny"; +$l['online_guest_plural'] = "goÅ›ci"; +$l['online_guest_singular'] = "gość"; +$l['online_note'] = "{1} {2} w ciÄ…gu ostatnich {3} minut: {4} {5} (w tym {6} {7}) oraz {8} {9}."; +$l['subforums'] = "PoddziaÅ‚y:"; diff --git a/Upload/inc/languages/polish/mailhandler.lang.php b/Upload/inc/languages/polish/mailhandler.lang.php new file mode 100644 index 0000000..d796ce0 --- /dev/null +++ b/Upload/inc/languages/polish/mailhandler.lang.php @@ -0,0 +1,17 @@ +'; diff --git a/Upload/inc/languages/polish/managegroup.lang.php b/Upload/inc/languages/polish/managegroup.lang.php new file mode 100644 index 0000000..88d2cd8 --- /dev/null +++ b/Upload/inc/languages/polish/managegroup.lang.php @@ -0,0 +1,65 @@ +{1} nierozpatrzonych próśb o przyjÄ™cie."; +$l['group_management'] = "ZarzÄ…dzanie grupami"; +$l['members_of'] = "CzÅ‚onek \"{1}\""; +$l['user_name'] = "Użytkownik"; +$l['contact'] = "Kontakt"; +$l['reg_date'] = "Zarejestrowany"; +$l['post_count'] = "Postów"; +$l['remove_selected'] = "UsuÅ„ zaznaczonych użytkowników z grupy"; +$l['add_member'] = "Dodaj użytkownika do \"{1}\""; +$l['add_member_submit'] = "Dodaj użytkownika do grupy"; +$l['invite_member'] = "ZaproÅ› użytkownika do \"{1}\""; +$l['invite_member_submit'] = "ZaproÅ› użytkownika do grupy"; +$l['join_requests'] = "ProÅ›by o przyjÄ™cie"; +$l['join_requests_title'] = "ProÅ›by o przyjÄ™cie do \"{1}\""; +$l['leader'] = "(lider)"; +$l['reason'] = "Powód"; +$l['accept'] = "Akceptuj"; +$l['ignore'] = "Ignoruj"; +$l['decline'] = "Odrzuć"; +$l['action_requests'] = "Wykonaj"; +$l['join_requests_moderated'] = "ProÅ›by o przyjÄ™cie zostaÅ‚y rozpatrzone.
    Nastąpi przeniesienie do listy próśb."; +$l['no_requests'] = "Aktualnie brak próśb o przyjęcie."; +$l['no_users'] = "W tej grupie nie ma użytkowników."; +$l['user_added'] = "Użytkownik został dodany do grupy."; +$l['users_removed'] = "Zaznaczeni użytkownicy zostali usunięci z grupy."; +$l['group_no_members'] = "Aktualnie w tej grupie nie ma użytkowników.
    Aby powrócić do zarządzania grupami, kliknij tutaj."; +$l['group_public_moderated'] = "Ta grupa jest grupą publiczną, więc każdy może do niej dołączyć. Wszystkie prośby o dołączenie są rozpatrywane przez lidera."; +$l['group_public_not_moderated'] = "Ta grupa jest publiczna. Każdy może do niej dołączyć."; +$l['group_public_invite'] = "Ta grupa jest publiczna. Dołączenie do niej wymaga zaproszenia od lidera."; +$l['group_private'] = "To jest prywatna grupa. By do niej dołączyć, użytkownik musi zostać dodany przez lidera."; +$l['group_default'] = "To jest grupa główna."; +$l['group_leaders'] = "Liderzy grup"; +$l['search_user'] = "Szukaj użytkownika"; +$l['no_users_selected'] = "Nie zaznaczono użytkowników do usunięcia.
    Wróć i usuń użytkowników do usunięcia z grupy."; + +$l['error_alreadyingroup'] = "Wybrany użytkownik już należy do tej grupy."; +$l['error_alreadyinvited'] = "Wybrany użytkownik został już zaproszony do tej grupy."; + +$l['user_invited'] = "Użytkownik został zaproszony do dołączenia do grupy."; +$l['invite_pm_subject'] = "Nowe zaproszenie do grupy \"{1}\""; +$l['invite_pm_message'] = "Masz nowe zaproszenie do dołączenia do grupy \"{1}\". + +Aby do niej dołączyć, przejdź do sekcji [url={2}/usercp.php?action=usergroups]Grupy użytkowników[/url] w panelu użytkownika i kliknij \"Akceptuj\". + +To zaproszenie jest ważne bezterminowo."; +$l['invite_pm_message_expires'] = "Masz nowe zaproszenie do dołączenia do grupy \"{1}\". + +Aby do niej dołączyć, przejdź do sekcji [url={2}/usercp.php?action=usergroups]Grupy użytkowników[/url] w panelu użytkownika i kliknij \"Akceptuj\". + +To zaproszenie wygaśnie za {3} dni."; \ No newline at end of file diff --git a/Upload/inc/languages/polish/member.lang.php b/Upload/inc/languages/polish/member.lang.php new file mode 100644 index 0000000..9d54842 --- /dev/null +++ b/Upload/inc/languages/polish/member.lang.php @@ -0,0 +1,258 @@ +NIE WOLNO Ci pisać postów łamiących te zasady."; +$l['agreement_3'] = "Jeśli złamiesz któreś z tych postanowień, narazisz się na możliwość usunięcia konta lub zbanowania używanego przez Ciebie adresu IP."; +$l['agreement_4'] = "Żadne z Twoich danych podanych podczas rejestracji na forum nie będą wykorzystywane w celach niezwiązanych z działalnością forum ani przekazywane osobom trzecim."; +$l['agreement_5'] = "Kontynuując rejestrację oświadczasz, że zgadzasz się ze wszystkimi wymienionymi powyżej postanowieniami oraz innymi regułami ustalonymi przez administratorów tego forum. W celu poznania pełnych reguł obowiązujących na forum, skontaktuj się z administratorem."; +$l['registration'] = "Rejestracja"; +$l['required_fields'] = "Wymagane pola"; +$l['complex_password'] = "Złożone hasło:"; +$l['confirm_email'] = "Potwierdź e-mail:"; +$l['optional_fields'] = "Opcjonalne pola"; +$l['website_url'] = "Strona WWW:"; +$l['birthdate'] = "Urodziny:"; +$l['additional_info'] = "Dodatkowe informacje"; +$l['required_info'] = "Wymagane informacje"; +$l['i_agree'] = "Zgadzam się"; +$l['account_details'] = "Szczegóły konta"; +$l['account_prefs'] = "Ustawienia konta:"; +$l['invisible_mode'] = "Nie pokazuj mnie na liście osób online."; +$l['allow_notices'] = "Dostarczaj mi e-maile od administratorów."; +$l['hide_email'] = "Ukryj mój adres e-mail przed innymi użytkownikami."; +$l['email_notify'] = "Automatycznie subskrybuj wątek, w którym napiszę."; +$l['receive_pms'] = "Dostarczaj mi prywatne wiadomości od innych użytkowników."; +$l['pm_notice'] = "Powiadom mnie, gdy dostanę nową prywatną wiadomość."; +$l['email_notify_newpm'] = "Powiadamiaj mnie e-mailem o każdej nowej prywatnej wiadomości."; +$l['time_offset'] = "Strefa czasowa (czas letni):"; +$l['time_offset_desc'] = "Jeżeli mieszkasz w innej strefie czasowej niż domyślna, wybierz ją z listy poniżej."; +$l['dst_correction'] = "Ustawienia DST (czasu letniego):"; +$l['dst_correction_auto'] = "Automatycznie wykryj DST"; +$l['dst_correction_enabled'] = "Zawsze używaj DST"; +$l['dst_correction_disabled'] = "Nigdy nie używaj DST"; +$l['redirect_registered_coppa_activate'] = "Dziękujemy za rejestrację w {1}, {2}. Konto zostało utworzone, ale ponieważ nie spełniasz wymogu ukończenia 13 roku życia, musisz dostarczyć zgodę rodziców na używanie tego konta.

    Twój rodzic lub prawny opiekun musi pobrać, wypełnić i wysłać nam kopię formularza COPPA.

    Gdy dotrze do nas wypełniony formularz, Twoje konto zostanie aktywowane."; +$l['coppa_compliance'] = "COPPA"; +$l['coppa_desc'] = "Aby zarejestrować Cię na tym forum, musimy sprawdzić, czy spełniasz warunki COPPA. Podaj swoją datę urodzenia.

    Jeżeli masz mniej niż 13 lat, do rejestracji będzie wymagana zgoda rodziców. Twój rodzic lub prawny opiekun będzie musiał pobrać, wypełnić i wysłać nam kopię formularza COPPA."; +$l['hide_dob'] = "Edytując swój profil po zarejestrowaniu będziesz mieć możliwość ukrycia swojej daty urodzenia."; +$l['signature'] = "Sygnatura:"; +$l['continue_registration'] = "Kontynuuj rejestrację"; +$l['birthdayprivacy'] = "Wyświetlanie daty urodzenia:"; +$l['birthdayprivacyall'] = "Wyświetl wiek i datę urodzenia"; +$l['birthdayprivacynone'] = "Ukryj wiek i datę urodzenia"; +$l['birthdayprivacyage'] = "Wyświetl tylko wiek"; +$l['leave_this_field_empty'] = "Pozostaw to pole puste:"; +$l['error_need_to_be_thirteen'] = "Musisz mieć ukończone 13 lat by zarejestrować się na tym forum."; +$l['coppa_registration'] = "Formularz COPPA"; +$l['coppa_form_instructions'] = "Wydrukuj ten formularz, wypełnij go i wyślij faksem na podany poniżej numer lub pocztą pod poniższy adres."; +$l['fax_number'] = "Fax:"; +$l['mailing_address'] = "Adres korespondencyjny:"; +$l['account_information'] = "Informacje o koncie"; +$l['parent_details'] = "Dane rodzica / opiekuna"; +$l['full_name'] = "Pełne nazwisko:"; +$l['relation'] = "Pokrewieństwo:"; +$l['phone_no'] = "Nr telefonu:"; +$l['coppa_parent_agreement'] = "Potwierdzam prawdziwość podanych przeze mnie informacji. Rozumiem, że będą one mogły być zmienione po podaniu przeze mnie poprawnego hasła, a także że istnieje możliwość usunięcia mojego konta na żądanie."; + +$l['coppa_agreement_1'] = "Użytkownicy poniżej 13 roku życia muszą otrzymać zezwolenie rodzica lub prawnego opiekuna na rejestrację w {1}."; +$l['coppa_agreement_2'] = "Rodzic lub prawny opiekun będzie musiał pobrać, wypełnić i wysłać nam kopię formularza COPPA przed dokonaniem rejestracji."; +$l['coppa_agreement_3'] = "Jeżeli chcesz, możesz teraz rozpocząć proces rejestracji, ale konto będzie dostępne dopiero po spełnieniu wyżej wymienionych warunków."; + +$l['error_invalid_birthday'] = 'Podana data urodzin jest niepoprawna. Wybierz poprawną datę.'; +$l['error_awaitingcoppa'] = "Nie możesz zalogować się na to konto, bo nie otrzymaliśmy jeszcze wypełnionego formularza COPPA od Twojego rodzica lub prawnego opiekuna.

    Twój rodzic lub prawny opiekun musi pobrać, wypełnić i wysłać nam kopię formularza COPPA.

    Gdy dotrze do nas wypełniony formularz, Twoje konto zostanie aktywowane."; + +$l['lang_select'] = "Ustawienia językowe:"; +$l['lang_select_desc'] = "Wybierz jedną z paczek językowych."; +$l['lang_select_default'] = "Użyj domyślnego"; + +$l['submit_registration'] = "Zakończ rejestrację!"; +$l['confirm_password'] = "Potwierdź hasło:"; +$l['referrer'] = "Polecający:"; +$l['referrer_desc'] = "Jeśli ktoś polecił Ci forum, wpisz tutaj jego login. Jeśli nie - pozostaw to pole puste."; +$l['search_user'] = "Szukaj użytkownika"; +$l['resend_activation'] = "Prześlij kod aktywacyjny"; +$l['request_activation'] = "Poproś o kod aktywacyjny"; +$l['ppp'] = "Postów na stronę:"; +$l['ppp_desc'] = "Pozwala Ci na wybranie maksymalnej liczby postów wyświetlanych na jednej stronie."; +$l['tpp'] = "Wątków na stronę:"; +$l['tpp_desc'] = "Pozwala Ci na wybranie maksymalnej liczby wątków wyświetlanych na jednej stronie."; +$l['reset_password'] = "Resetuj hasło"; +$l['send_password'] = "Wyślij nowe hasło!"; +$l['image_verification'] = "Potwierdzenie kodem"; +$l['verification_note'] = "Przepisz do poniższego pola ciąg znaków z obrazka. Taki proces jest niezbędny, by zapobiec rejestracjom automatów."; +$l['verification_subnote'] = "(wielkość znaków nie ma znaczenia)"; +$l['registration_errors'] = "Przy rejestracji wystąpiły następujące błędy:"; +$l['timeonline'] = "Spędzony czas online:"; +$l['timeonline_hidden'] = "(ukryte)"; +$l['registrations_disabled'] = "Rejestracja kont jest aktualnie wyłączona. Zapraszamy później."; +$l['error_username_length'] = "Login jest nieprawidłowy - musi on zawierać od {1} do {2} znaków."; +$l['error_stop_forum_spam_spammer'] = 'Twój adres IP lub e-mail znajduje się w bazie znanych spamerów. Jeżeli uważasz, że jest to błąd, skontaktuj się z administratorem.'; +$l['error_stop_forum_spam_fetching'] = 'Nie mogliśmy upewnić sie, że nie jesteś spamerem. Prawdopodobnie jest to spowodowane problemami z połączeniem z bazą danych. Spróbuj ponownie później.'; + +$l['none_registered'] = "Niezarejestrowany"; +$l['not_specified'] = "Nie określono"; +$l['membdayage'] = "({1} lat)"; +$l['mod_options'] = "Opcje moderatora"; +$l['edit_in_mcp'] = "Edytuj tego użytkownika w panelu moderatora"; +$l['ban_in_mcp'] = "Zbanuj tego użytkownika w panelu moderatora"; +$l['purgespammer'] = "Usuń spamera"; +$l['edit_usernotes'] = "Edytuj notatki o użytkowniku w panelu moderatora"; +$l['no_usernotes'] = "Nie ma notatek o tym użytkowniku"; +$l['view_all_notes'] = "Przeglądaj wszystkie notatki"; +$l['view_notes_for'] = "Przeglądaj notatki o użytkowniku {1}"; +$l['reputation'] = "Reputacja:"; +$l['reputation_vote'] = "Oceń"; +$l['reputation_details'] = "Szczegóły"; +$l['already_logged_in'] = "Uwaga: jesteś już zalogowany jako {1}."; +$l['admin_edit_in_acp'] = "Edytuj tego użytkownika w panelu administratora"; +$l['admin_ban_in_acp'] = "Zbanuj tego użytkownika w panelu administratora"; +$l['admin_options'] = "Opcje administratora"; + +$l['redirect_registered_activation'] = "Dziękujemy za rejestrację na {1}, {2}.

    Aby zakończyć rejestrację, sprawdź swoją skrzynkę e-mail w celu aktywacji konta. Przed aktywacją konta nie możesz pisać na forum"; +$l['redirect_emailupdated'] = "Adres e-mail został zmieniony.
    Teraz nastąpi przeniesienie na stronę główną forum."; +$l['redirect_accountactivated'] = "Konto zostało aktywowane.
    Teraz nastąpi przeniesienie na stronę główną forum."; +$l['redirect_accountactivated_admin'] = "Adres email został zweryfikowany.
    Twoje konto musi zostać aktywowane przez administratora. Przed aktywacją konta nie możesz pisać na forum.
    Teraz nastąpi przeniesienie na stronę główną forum."; +$l['redirect_registered'] = "Dziękujemy za rejestrację na {1}, {2}.
    Teraz nastąpi przeniesienie na stronę główną forum."; +$l['redirect_registered_admin_activate'] = "Dziękujemy za rejestrację na {1}, {2}.
    Twoje konto musi zostać aktywowane przez administratora. Przed aktywacją konta nie możesz pisać na forum."; +$l['redirect_loggedout'] = "Wylogowano z forum.
    Teraz nastąpi przeniesienie na stronę główną forum."; +$l['redirect_alreadyloggedout'] = "Już wcześniej wylogowano z forum.
    Teraz nastąpi przeniesienie na stronę główną forum."; +$l['redirect_lostpwsent'] = "Na Twój adres został wysłany e-mail z instrukcją dotyczącą resetowania hasła.

    Teraz nastąpi przeniesienie na stronę główną forum."; +$l['redirect_activationresent'] = "E-mail aktywacyjny został wysłany."; +$l['redirect_passwordreset'] = "Hasło zostało zresetowane. Nowe hasło zostało wysłane na Twój adres e-mail."; +$l['redirect_memberrated'] = "Użytkownik został oceniony."; +$l['redirect_registered_passwordsent'] = "Wygenerowane hasło zostało wysłane na Twój adres e-mail. Zanim zaczniesz korzystać z forum, musisz sprawdzić skrzynkę e-mail w celu zdobycia hasła."; +$l['redirect_validated'] = "Twoje konto zostało aktywowane.
    Teraz nastąpi przeniesienie na forum."; + +$l['error_activated_by_admin'] = "Nie możesz przesłać ponownie kodu aktywacyjnego, gdyż administrator musi aktywować Twoje konto."; +$l['error_alreadyregistered'] = "Prawdopodobnie jesteś już zarejestrowanym użytkownikiem forum. Nie możesz zarejestrować kilku kont, gdyż administrator zablokował taką możliwość."; +$l['error_alreadyregisteredtime'] = "Nie możesz się zarejestrować, gdyż dokonano już {1} rejestracji z Twojego adresu IP w przeciągu {2} godzin. Spróbuj później."; +$l['error_badlostpwcode'] = "Wprowadzono nieprawidłowy kod resetowania hasła. Przeczytaj uważnie e-mail lub skontaktuj się z administratorem."; +$l['error_badactivationcode'] = "Wprowadzono nieprawidłowy kod aktywacyjny. Aby ponownie przesłać e-mail aktywacyjny, kliknij tutaj."; +$l['error_alreadyactivated'] = "Może to być spowodowane tym, że posiadasz już aktywowane konto lub forum nie wymaga aktywacji."; +$l['error_alreadyvalidated'] = "Twój adres e-mail został już zweryfikowany."; +$l['error_nothreadurl'] = "ID wątku nieznane. Użyj przycisku \"Powiadom znajomego\"."; +$l['error_bannedusername'] = "Wybrano zabroniony login. Użyj innego loginu."; +$l['error_notloggedout'] = "Wystąpił błąd przy wylogowaniu. Może to być spowodowane szkodliwym Javascriptem, który próbuje wylogowywać Cię automatycznie. Jeśli chcesz się wylogować, kliknij na \"Wyloguj\"."; +$l['error_regimageinvalid'] = "Wprowadzony kod z obrazka jest nieprawidłowy. Spróbuj ponownie."; +$l['error_regimagerequired'] = "Uzupełnij kod weryfikujący aby kontynuować proces logowania. Przepisz kod identyczny jak ten na obrazku."; +$l['error_spam_deny'] = "Możliwość rejestracji została zablokowana ze względu na podejrzenie, że jesteś spamerem. Jeżeli uważasz, że jest to błędem, skontaktuj się z administratorem."; +$l['error_spam_deny_time'] = "Możliwość rejestracji została zablokowana ze względu na podejrzenie, że jesteś spamerem. Aby zapobiec automatycznym rejestracjom ustalono minimalny czas potrzebny na wypełnienie formularza, który wynosi {1} sekund(y); ta rejestracja trwała {2} sekund(y). Jeżeli uważasz, że jest to błędem, skontaktuj się z administratorem.."; + +$l['js_validator_no_username'] = "Musisz podać login"; +$l['js_validator_invalid_email'] = "Musisz podać prawidłowy adres e-mail"; +$l['js_validator_email_match'] = "Podane adresy e-mail nie zgadzają się"; +$l['js_validator_no_image_text'] = "Musisz tutaj przepisać tekst z obrazka obok"; +$l['js_validator_no_security_question'] = "Musisz odpowiedzieć na powyższe pytanie"; +$l['js_validator_password_matches'] = "Podane hasła nie zgadzają się"; +$l['js_validator_password_complexity'] = "Sprawdzanie złożoności hasła"; +$l['js_validator_password_length'] = "Hasło musi zawierać przynajmniej {1} znaków"; +$l['js_validator_not_empty'] = "Nie możesz pozostawić tego pola pustego"; +$l['js_validator_checking_username'] = "Sprawdzam czy login jest dostępny..."; +$l['js_validator_username_length'] = "Login musi zawierać od {1} do {2} znaków"; +$l['js_validator_checking_referrer'] = "Sprawdzam czy istnieje taki użytkownik..."; +$l['js_validator_captcha_valid'] = "Sprawdzam czy poprawnie przepisano kod..."; + +$l['security_question'] = "Pytanie zabezpieczające"; +$l['question_note'] = "Udziel odpowiedzi na pytanie. Proces ten ma na celu zapobieżenie automatycznym rejestracjom."; +$l['error_question_wrong'] = "Podana odpowiedź na pytanie jest niepoprawna. Spróbuj ponownie."; + +$l['subscription_method'] = "Domyślny sposób subskrypcji wątków:"; +$l['no_auto_subscribe'] = "Nie subskrybuj"; +$l['no_subscribe'] = "Subskrybuj bez powiadamiania"; +$l['instant_email_subscribe'] = "Subskrybuj i powiadamiaj e-mailem"; +$l['instant_pm_subscribe'] = "Subskrybuj i powiadamiaj poprzez prywatną wiadomość"; + +$l['remove_from_buddy_list'] = "Usuń z listy znajomych"; +$l['add_to_buddy_list'] = "Dodaj do listy znajomych"; +$l['remove_from_ignore_list'] = "Usuń z listy ignorowanych"; +$l['add_to_ignore_list'] = "Dodaj do listy ignorowanych"; +$l['report_user'] = "Zgłoś użytkownika"; + +$l['newregistration_subject'] = "Nowa rejestracja na {1}"; +$l['newregistration_message'] = "{1}, + +Nowy użytkownik zarejestrował się na {2} i oczekuje na aktywację swojego konta przez administratora. + +Nazwa użytkownika: {3} + +Dziękujemy, +Ekipa {2}"; diff --git a/Upload/inc/languages/polish/memberlist.lang.php b/Upload/inc/languages/polish/memberlist.lang.php new file mode 100644 index 0000000..daccd8b --- /dev/null +++ b/Upload/inc/languages/polish/memberlist.lang.php @@ -0,0 +1,80 @@ +Nie znaleziono żadnych użytkowników spełniających kryteria wyszukiwania.

    Podaj inne kryteria i spróbuj jeszcze raz.

    "; + +$l['a'] = 'A'; +$l['b'] = 'B'; +$l['c'] = 'C'; +$l['d'] = 'D'; +$l['e'] = 'E'; +$l['f'] = 'F'; +$l['g'] = 'G'; +$l['h'] = 'H'; +$l['i'] = 'I'; +$l['j'] = 'J'; +$l['k'] = 'K'; +$l['l'] = 'L'; +$l['m'] = 'M'; +$l['n'] = 'N'; +$l['o'] = 'O'; +$l['p'] = 'P'; +$l['q'] = 'Q'; +$l['r'] = 'R'; +$l['s'] = 'S'; +$l['t'] = 'T'; +$l['u'] = 'U'; +$l['v'] = 'V'; +$l['w'] = 'W'; +$l['x'] = 'X'; +$l['y'] = 'Y'; +$l['z'] = 'Z'; diff --git a/Upload/inc/languages/polish/messages.lang.php b/Upload/inc/languages/polish/messages.lang.php new file mode 100644 index 0000000..2f3f984 --- /dev/null +++ b/Upload/inc/languages/polish/messages.lang.php @@ -0,0 +1,473 @@ +
    Możesz też wrócić do działu."; +$l['redirect_emailsent'] = "E-mail został wysłany."; +$l['redirect_loggedin'] = "Zalogowano na forum.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; + +$l['error_invalidpworusername'] = "Wprowadzono nieprawidłowy login i/lub hasło.

    Jeżeli nie pamiętasz swojego hasła, kliknij tutaj, by wygenerować nowe."; +$l['error_invalidpworusername1'] = "Wprowadzono nieprawidłowy adres e-mail i/lub hasło.

    Jeżeli nie pamiętasz swojego hasła, kliknij tutaj, aby wygenerować nowe."; +$l['error_invalidpworusername2'] = "Wprowadzono nieprawidłowy login lub adres e-mail i/lub hasło.

    Jeżeli nie pamiętasz swojego hasła, kliknij tutaj, aby wygenerować nowe."; +$l['error_incompletefields'] = "Nie wypełniono któregoś z wymaganych pól. Wróć i wypełnij wszystkie wymagane pola."; +$l['error_alreadyuploaded'] = "Plik o takiej nazwie został już raz wysłany. Zmień nazwę pliku i spróbuj ponownie. Alternatywnie możesz kliknąć na przycisk \"Aktualizuj załącznik\"."; +$l['error_alreadyuploaded_perm'] = "Ten post zawiera już plik o takiej samej nazwie. Usuń poprzedni plik lub zmień nazwę pliku, który próbujesz wysłać, i spróbuj ponownie."; +$l['error_nomessage'] = "Nie podano treści wiadomości. Wróć i wpisz wiadomość."; +$l['error_invalidemail'] = "Musisz wprowadzić prawidłowy adres e-mail."; +$l['error_nomember'] = "Podany login jest nieprawidłowy albo nie istnieje."; +$l['error_maxposts'] = "Przekroczono dzienny limit postów. Zapraszamy jutro.

    Maksymalna liczba postów dziennie to {1}"; +$l['error_nohostname'] = "Nie można znaleźć nazwy hosta dla wprowadzonego IP."; +$l['error_invalidthread'] = "Wątek nie istnieje."; +$l['error_invalidpost'] = "Post nie istnieje."; +$l['error_invalidannouncement'] = "Ogłoszenie nie istnieje."; +$l['error_invalidattachment'] = "Załącznik nie istnieje."; +$l['error_invalidforum'] = "Nieprawidłowy dział"; +$l['error_closedinvalidforum'] = "Nie możesz napisać wątku w zamkniętym dziale ani w zamkniętej kategorii."; +$l['error_attachtype'] = "Typ pliku, który załączono, nie jest obsługiwany. Usuń załącznik i spróbuj ponownie."; +$l['error_attachsize'] = "Plik załącznika jest za duży. Maksymalny rozmiar pliku to {1} kilobajtów."; +$l['error_uploadempty'] = "Wybrany plik jest pusty."; +$l['error_uploadsize'] = "Plik, który próbujesz załączyć jest za duży."; +$l['error_uploadfailed'] = "Plik nie został załadowany. Wybierz prawidłowy plik i spróbuj ponownie. "; +$l['error_uploadfailed_detail'] = "Szczegóły błędu: "; +$l['error_uploadfailed_php1'] = "Błąd PHP: Wysyłany plik przekracza rozmiar upload_max_filesize podany w php.ini. Skontaktuj się z administratorem forum."; +$l['error_uploadfailed_php2'] = "Plik przekracza maksymalny rozmiar."; +$l['error_uploadfailed_php3'] = "Plik częściowo wysłany."; +$l['error_uploadfailed_php4'] = "Nie wysłano pliku."; +$l['error_uploadfailed_php6'] = "Błąd PHP: Folder docelowy nie istnieje. Skontaktuj się z administratorem forum."; +$l['error_uploadfailed_php7'] = "Błąd PHP: Błąd zapisu. Skontaktuj się z administratorem forum."; +$l['error_uploadfailed_phpx'] = "PHP zwróciło numer błędu: {1}. Skontaktuj się z administratorem forum, podaj szczegóły i numer błędu."; +$l['error_uploadfailed_nothingtomove'] = "Nieprawidłowy plik. Wysyłany plik nie może zostać przeniesiony do katalogu docelowego."; +$l['error_uploadfailed_movefailed'] = "Wystąpił problem przy przenoszeniu pliku."; +$l['error_uploadfailed_lost'] = "Załącznik nie mógł zostać znaleziony na serwerze."; +$l['error_emailmismatch'] = "Wprowadzone adresy e-mail nie są identyczne. Wróć i spróbuj ponownie"; +$l['error_nopassword'] = "Musisz wprowadzić hasło."; +$l['error_usernametaken'] = "Użytkownik o takim loginie już istnieje. Jeśli posiadasz już konto na tym forum, zaloguj się."; +$l['error_nousername'] = "Musisz wprowadzić login."; +$l['error_invalidusername'] = "Użytkownik z takim loginem nie istnieje."; +$l['error_invalidpassword'] = "Wprowadzone hasło jest niepoprawne. Jeśli nie pamiętasz hasła, kliknij tutaj, albo wróć i spróbuj ponownie."; +$l['error_postflooding'] = "Nie możesz teraz napisać posta, ponieważ od publikacji przez Ciebie ostatniego posta musi minąć {1} sekund."; +$l['error_nopermission_guest_1'] = "Nie nastąpiło zalogowanie, lub nie masz dostępu do tej części forum. Możliwe powody takiej sytuacji:"; +$l['error_nopermission_guest_2'] = "Nie zalogowano lub nie zarejestrowano się na forum. Zaloguj się lub zarejestruj."; +$l['error_nopermission_guest_3'] = "Możesz nie mieć uprawnień do oglądania tej strony."; +$l['error_nopermission_guest_4'] = "Twoje konto może być nieaktywne albo zablokowane."; +$l['error_nopermission_guest_5'] = "Odwiedzono tę stronę wpisując jej adres bezpośrednio w pasek adresu przeglądarki zamiast użyć odpowiedniego formularza lub odnośnika."; +$l['login'] = "Zaloguj się"; +$l['need_reg'] = "Rejestracja"; +$l['forgot_password'] = "Nie pamiętam hasła"; +$l['error_nopermission_user_1'] = "Nie masz uprawnień, aby przeglądać tę stronę. Możliwe powody takiej sytuacji:"; +$l['error_nopermission_user_ajax'] = "Nie masz uprawnień do przeglądania tej strony."; +$l['error_nopermission_user_2'] = "Twoje konto może być zawieszone lub zablokowane."; +$l['error_nopermission_user_3'] = "Możesz nie mieć uprawnień do oglądania tej strony."; +$l['error_nopermission_user_4'] = "Twoje konto może być nieaktywne lub moderowane."; +$l['error_nopermission_user_5'] = "Odwiedzono tę stronę wpisując jej adres bezpośrednio w pasek adresu przeglądarki zamiast użyć odpowiedniego formularza lub odnośnika."; +$l['error_nopermission_user_resendactivation'] = "Prześlij ponownie kod aktywacyjny"; +$l['error_nopermission_user_username'] = "Zalogowano jako: '{1}'"; +$l['logged_in_user'] = "Zalogowano jako"; +$l['error_too_many_images'] = "Za dużo obrazków"; +$l['error_too_many_images2'] = "Twoja wiadomość zawiera za dużo obrazków. Usuń niektóre obrazki i spróbuj ponownie."; +$l['error_too_many_images3'] = "Uwaga: Maksymalna liczba obrazków w poście to"; +$l['error_attach_file'] = "Błąd podczas załączania pliku"; +$l['please_correct_errors'] = "Popraw następujące błędy:"; +$l['error_reachedattachquota'] = "Nie możesz załączyć plików - przekroczono limit {1}"; +$l['error_maxattachpost'] = "Nie można dodać kolejnego załącznika, ponieważ przekroczono liczbę dozwolonych załączników, która wynosi {1}"; +$l['error_invaliduser'] = "Określony użytkownik nie istnieje."; +$l['error_invalidaction'] = "Nieprawidłowe polecenie"; +$l['error_messagelength'] = "Twoja wiadomość jest zbyt długa. Skróć wiadomość i spróbuj ponownie."; +$l['error_message_too_short'] = "Twoja wiadomość jest za krótka."; +$l['failed_login_wait'] = "Przekroczono limit błędnych logowań. Musisz odczekać {1} godz. {2} min. {3} sek. przed kolejną próbą logowania."; +$l['failed_login_again'] = "
    Pozostało Ci jeszcze {1} prób logowania."; +$l['error_max_emails_day'] = "Nie możesz użyć opcji \"Wyślij wątek do znajomego\" i \"E-mail do użytkownika\" - przekroczono limit {1} wiadomości na dobę."; +$l['attachments_disabled'] = "Nie możesz dodać załącznika, ponieważ taka możliwość została wyłączona przez administratora."; + +$l['emailsubject_lostpw'] = "Zmiana hasła na forum {1}"; +$l['emailsubject_passwordreset'] = "Nowe hasło na forum {1}"; +$l['emailsubject_subscription'] = "Nowa odpowiedź na forum {1}"; +$l['emailsubject_randompassword'] = "Twoje hasło do {1}"; +$l['emailsubject_activateaccount'] = "Aktywacja konta na forum {1}"; +$l['emailsubject_forumsubscription'] = "Nowy wątek na forum {1}"; +$l['emailsubject_reportpost'] = "Zgłoszony post na forum {1}"; +$l['emailsubject_reachedpmquota'] = "Przekroczono limit ({1}) PW"; +$l['emailsubject_changeemail'] = "Zmiana e-maila na forum {1}"; +$l['emailsubject_newpm'] = "Nowa prywatna wiadomość na forum {1} - {2}"; +$l['emailsubject_newjoinrequest'] = "Nowa prośba o przyjęcie do grupy na forum {1}"; +$l['emailsubject_sendtofriend'] = "Interesujący wątek na forum {1}"; +$l['emailsubject_changepassword'] = "Zmiana hasła na forum {1}"; +$l['emailbit_viewthread'] = "... (odwiedź ten wątek, by przeczytać pełną treść...)"; + +$l['email_lostpw'] = "{1}, + +Aby zakończyć proces resetowania hasła w {2}, odwiedź ten adres: + +{3}/member.php?action=resetpassword&uid={4}&code={5} + +W razie problemów z powyższym linkiem, odwiedź + +{3}/member.php?action=resetpassword + +i podaj poniższe dane, potrzebne do zresetowania hasła: +Użytkownik: {1} +Kod aktywacji: {5} + +Dziękujemy, +Ekipa {2}"; +$l['email_lostpw1'] = "{1}, + +Aby zakończyć proces resetowania hasła w {2}. odwiedź ten adres: + +{3}/member.php?action=resetpassword&uid={4}&code={5} + +W razie problemów z powyższym linkiem, odwiedź + +{3}/member.php?action=resetpassword + +i podaj poniższe dane, potrzebne do zresetowania hasła: +Adres e-mail, na który została wysłana ta wiadomość +Kod aktywacji: {5} + +Dziękujemy, +Ekipa {2}"; +$l['email_lostpw2'] = "{1}, + +Aby zakończyć proces resetowania hasła w {2}, odwiedź ten adres: + +{3}/member.php?action=resetpassword&uid={4}&code={5} + +W razie problemów z powyższym linkiem, odwiedź + +{3}/member.php?action=resetpassword + +i podaj poniższe dane, potrzebne do zresetowania hasła: +Login: {1} (lub adres e-mail, na który wysłana została ta wiadomość) +Kod aktywacji: {5} + +Dziękujemy, +Ekipa {2}"; + + +$l['email_reportpost'] = "{1} z {2} zgłosił post: + +{3} +{4}/{5} + +Powód zgłoszenia: +{7} + +Ta wiadomość została wysłana do wszystkich moderatorów tego działu (jeśli dział nie ma moderatorów - poinformowani zostali globalni moderatorzy i administratorzy). + +Sprawdź ten post."; + +$l['email_passwordreset'] = "{1}, + +Hasło na forum {2} zostało zresetowane. + +Nowe hasło: {3} + +Podaj to hasło podczas logowania na forum. Po zalogowaniu niezwłocznie zmień hasło w panelu użytkownika. + +Pozdrawiamy, +Ekipa {2}"; + +$l['email_randompassword'] = "{1}, + +Dziękujemy za rejestrację na forum {2}. Poniżej podane są Twój login i losowo wygenerowane hasło, które są Ci potrzebne do logowania na forum {2}. + +Login: {3} +Hasło: {4} + +Zalecana jest zmiana hasła po zalogowaniu. Aby to zrobić przejdź do panelu użytkownika i kliknij Zmień hasło. + +Pozdrawiamy, +Ekipa {2}"; + +$l['email_randompassword1'] = "{1}, + +Dziękujemy za rejestrację na forum {2}. Poniżej podane są Twój login i losowo wygenerowane hasło, które są Ci potrzebne do logowania na forum {2}. + +Login: adres email, na który została wysłana ta wiadomość +Hasło: {4} + +Zalecana jest zmiana hasła po zalogowaniu. Aby to zrobić przejdź do panelu użytkownika i kliknij Zmień hasło. + +Pozdrawiamy, +Ekipa {2}"; + +$l['email_randompassword2'] = "{1}, + +Dziękujemy za rejestrację na forum {2}. Poniżej podane są Twój login i losowo wygenerowane hasło, które są Ci potrzebne do logowania na forum {2}. + +Login: {3} (lub adres e-mail, na który wysłana została ta wiadomość) +Hasło: {4} + +Zalecana jest zmiana hasła po zalogowaniu. Aby to zrobić przejdź do panelu użytkownika i kliknij Zmień hasło. + +Pozdrawiamy, +Ekipa {2}"; + +$l['email_sendtofriend'] = "Witaj, + +{1} z {2} uważa, że zainteresuje Cię strona WWW: + +{3} + +{1} dołączył wiadomość: +------------------------------------------ +{4} +------------------------------------------ + +Pozdrawiamy, +Ekipa {2} +"; + +$l['email_forumsubscription'] = "{1}, + +{2} napisał nowy wątek w dziale {3}. Jest to subskrybowany przez Ciebie dział w {4}. + +Temat wątku: {5} + +Streszczenie wątku: +-- +{6} +-- + +Aby przeczytać ten wątek, przejdź pod adres: +{7}/{8} + +Kolejne powiadomienia otrzymasz dopiero po odwiedzeniu forum. + +Pozdrawiamy, +Ekipa {4} + +------------------------------------------ +Rezygnacja ze subskrypcji: + +Jeśli nie chcesz otrzymywać informacji o nowych wątkach, przejdź pod adres: +{7}/usercp2.php?action=removesubscription&type=forum&fid={9}&my_post_key={10} + +------------------------------------------"; + +$l['email_activateaccount'] = "{1}, + +Aby zakończyć proces rejestracji na forum {2}, musisz odwiedzić poniższy adres: + +{3}/member.php?action=activate&uid={4}&code={5} + +Jeśli powyższy link nie działa, przejdź pod podany poniżej adres: + +{3}/member.php?action=activate + +i podaj poniższe dane potrzebne do aktywacji: +Użytkownik: {1} +Kod aktywacji: {5} + +Pozdrawiamy, +Ekipa {2}"; + +$l['email_activateaccount1'] = "{1}, + +Aby zakończyć proces rejestracji na forum {2}, musisz odwiedzić poniższy adres: + +{3}/member.php?action=activate&uid={4}&code={5} + +Jeśli powyższy link nie działa, przejdź pod podany poniżej adres: + +{3}/member.php?action=activate + +i podaj poniższe dane potrzebne do aktywacji: +Adres e-mail, na który wysłana została ta wiadomość +Kod aktywacji: {5} + +Pozdrawiamy, +Ekipa {2}"; + +$l['email_activateaccount2'] = "{1}, + +Aby zakończyć proces rejestracji na forum {2}, musisz odwiedzić poniższy adres: + +{3}/member.php?action=activate&uid={4}&code={5} + +Jeśli powyższy link nie działa, przejdź pod podany poniżej adres: + +{3}/member.php?action=activate + +i podaj poniższe dane potrzebne do aktywacji: +Nazwa użytkownika: {1} (lub adres e-mail, na który wysłana została ta wiadomość) +Kod aktywacji: {5} + +Pozdrawiamy, +Ekipa {2}"; + +$l['email_subscription'] = "{1}, + +{2} odpowiedział w wątku, który subskrybujesz ({3}). Temat wątku: \"{4}\". + +Streszczenie odpowiedzi: +------------------------------------------ +{5} +------------------------------------------ + +Aby przeczytać ten wątek, przejdź pod adres: +{6}/{7} + +Kolejne powiadomienia otrzymasz dopiero po odwiedzeniu forum. + +Dziękujemy, +Ekipa {3} + +------------------------------------------ +Rezygnacja ze subskrypcji: + +Jeśli nie chcesz otrzymywać informacji o nowych odpowiedziach w tym wątku, przejdź pod adres: +{6}/usercp2.php?action=removesubscription&tid={8}&key={9}&my_post_key={10} + +------------------------------------------"; +$l['email_reachedpmquota'] = "{1}, + +To jest automatycznie wysłana wiadomość z forum {2}. Informujemy Cię, że Twoja skrzynka prywatnych wiadomości jest pełna. + +Ktoś próbował wysłać do Ciebie prywatną wiadomość. Niestety, z powodu przekroczenia przez Ciebie limitu miejsca, nie było to możliwe. + +Odwiedź forum i usuń starsze prywatne wiadomości, pamiętając również o opróżnieniu \"Usuniętych\". + +Pozdrawiamy, +Ekipa {2} +{3}"; +$l['email_changeemail'] = "{1}, + +Poproszono o zmianę adresu e-mail na stronie {2} (szczegóły poniżej). + +Stary e-mail: {3} +Nowy e-mail: {4} + +Jeśli te zmiany są prawidłowe, dokończ proces aktywacji przechodząc na {2} pod adres: + +{5}/member.php?action=activate&uid={8}&code={6} + +Jeśli powyższy link nie działa, przejdź pod podany poniżej adres: + +{5}/member.php?action=activate + +i podaj poniższe dane aktywacji: +Użytkownik: {7} +Kod aktywacji: {6} + +Jeśli nie aktywujesz nowego adresu e-mail, w Twoim profilu nadal będzie widoczny stary adres e-mail. + +Pozdrawiamy, +Ekipa {2} +{5}"; + +$l['email_changeemail_noactivation'] = "{1}, + +Otrzymujesz tę wiadomość ponieważ na twoim profilu na forum {2} zmieniono adres email (szczegóły poniżej). + +Poprzedni adres email: {3} +Nowy adres email: {4} + +Zmiana została wprowadzona natychmiast. Jeśli nie została ona dokonana przez ciebie, jak najszybciej skontaktuj się z administratorem. + +Pozdrawiamy, +Ekipa {2} +{5}"; + +$l['email_changepassword'] = "{1}, + +Otrzymujesz tę wiadomość ponieważ ty lub ktoś inny zmienił hasło na twoim koncie. + +Login: {1} +Adres e-mail: {2} + +Jeśli zmiana hasła nie została dokonana przez ciebie, jak najszybciej skontaktuj się z administratorem. + +Pozdrawiamy, +Ekipa {3} +{4}"; + +$l['email_newpm'] = "{1}, + +Otrzymano prywatną wiadomość na forum {3} od {2}. Aby przeczytać tę wiadomość, przejdź pod adres: + +------------------------------------------ +{5} +------------------------------------------ + +Aby wyświetlić lub odpowiedzieć na tę wiadomość przechodząc pod adres: + +{4}/private.php + +Kolejne powiadomienia otrzymasz dopiero po odwiedzeniu {3}. + +Możesz wyłączyć powiadomienia o prywatnych wiadomościach pod adresem: + +{4}/usercp.php?action=options + +Pozdrawiamy, +Ekipa {3} +{4}"; + +$l['email_emailuser'] = "{1}, + +{2} z {3} wysłał do Ciebie następującą wiadomość: +------------------------------------------ +{5} +------------------------------------------ + +Pozdrawiamy, +{3} +{4} + +------------------------------------------ +Nie chcesz otrzymywać e-maili od innych użytkowników? + +Jeżeli nie chcesz otrzymywać e-maili od innych użytkowników, odwiedź swój panel użytkownika i włącz opcję \"Ukryj mój adres e-mail.\": +{4}/usercp.php?action=options + +------------------------------------------"; + +$l['email_groupleader_joinrequest'] = "{1}, + +{2} poprosił o przyjęcie do grupy {3} na forum {4} (szczegóły poniżej). + +Powód: {5} + +Aby zaakceptować lub odrzucić prośbę przejdź pod adres: + +{6}/managegroup.php?gid={7} + +Pozdrawiamy, +Ekipa {4}"; + +$l['email_contact_subject'] = "Formularz kontaktowy: {1}"; +$l['email_contact'] = "E-mail: {1} +Profil na forum: {2} +Adres IP: {3} +Treść wiadomości: +{4}"; + +$l['pmsubject_subscription'] = "Nowa odpowiedź w wątku {1}"; +$l['pm_subscription'] = "{1}, + +{2} odpowiedział w wątku, który subskrybujesz. Temat wątku: \"{3}\". + +Streszczenie odpowiedzi: +------------------------------------------ +{4} +------------------------------------------ + +Aby przeczytać ten wątek, przejdź pod adres: +[url]{5}/{6}[/url] + +Kolejne powiadomienia otrzymasz dopiero po odwiedzeniu forum. + + +------------------------------------------ +Rezygnacja ze subskrypcji: + +Jeśli nie chcesz otrzymywać informacji o nowych odpowiedziach w tym wątku, przejdź pod adres: +[url]{5}/usercp2.php?action=removesubscription&tid={7}&key={8}&my_post_key={9}[/url] + +------------------------------------------"; diff --git a/Upload/inc/languages/polish/misc.lang.php b/Upload/inc/languages/polish/misc.lang.php new file mode 100644 index 0000000..fc4e5f0 --- /dev/null +++ b/Upload/inc/languages/polish/misc.lang.php @@ -0,0 +1,96 @@ +Nie ma znajomych w trybie online"; +$l['offline'] = "Offline"; +$l['offline_none'] = "Nie ma znajomych w trybie offline"; +$l['delete_buddy'] = "X"; +$l['pm_buddy'] = "Wyślij prywatną wiadomość"; +$l['last_active'] = "Ostatnio aktywny: {1}"; +$l['close'] = "Zamknij"; +$l['no_buddies'] = "Lista znajomych jest pusta. Możesz ją edytować w panelu użytkownika. Dodawanie znajomych jest możliwe także w profilach użytkowników."; + +$l['help_docs'] = "Dokumentacja"; + +$l['search_help_documents'] = "Szukaj"; +$l['search_by_name'] = "Szukaj w nazwie"; +$l['search_by_document'] = "Szukaj w treści"; +$l['enter_keywords'] = "Słowa kluczowe"; +$l['search'] = "Przeszukaj dokumentację"; +$l['redirect_searchresults'] = "Teraz nastąpi przeniesienie do wyników wyszukiwania."; +$l['search_results'] = "Wyniki wyszukiwania"; +$l['help_doc_results'] = "Wyniki wyszukiwania w dokumentacji"; +$l['document'] = "Dokument"; +$l['error_nosearchresults'] = "Nic nie znaleziono. Zmień kryteria wyszukiwania i spróbuj ponownie."; +$l['no_help_results'] = "Nic nie znaleziono."; +$l['error_helpsearchdisabled'] = "Możliwość wyszukiwania w dokumentacji została zablokowana przez administratora."; + +$l['smilies_listing'] = "Emotikony"; +$l['name'] = "Imię"; +$l['abbreviation'] = "Skrót"; +$l['click_to_add'] = "Kliknij w emotikona, by umieścić go w wiadomości."; +$l['close_window'] = "zamknij okno"; + +$l['who_posted'] = "Kto napisał?"; +$l['total_posts'] = "Razem postów:"; +$l['user'] = "Użytkownik"; +$l['num_posts'] = "Liczba postów"; + +$l['forum_rules'] = "{1} - Regulamin"; + +$l['error_invalid_limit'] ="Podany limit jest nieprawidłowy. Wpisz poprawny limit."; + +$l['syndication'] = "RSS"; +$l['syndication_generated_url'] = "Twój wygenerowany URL:"; +$l['syndication_note'] = "Poniżej możesz wybrać działy, dla których chcesz wygenerować swój link RSS. Do odczytania nagłówków RSS będzie Ci potrzebny specjalny program, np. SharpReader. Dowiedz się więcej o RSS"; +$l['syndication_forum'] = "Działy do subskrybowania (RSS):"; +$l['syndication_forum_desc'] = "Wybierz działy, które chcesz subskrybować przez RSS. By zaznaczyć kilka działów naraz, przytrzymaj klawisz CTRL i kliknij je."; +$l['syndication_version'] = "Wersja RSS:"; +$l['syndication_version_desc'] = "Wybierz preferowaną wersję RSS."; +$l['syndication_version_atom1'] = "Atom 1.0"; +$l['syndication_version_rss2'] = "RSS 2.00 (domyślnie)"; +$l['syndication_generate'] = "Generuj link do RSS"; +$l['syndication_limit'] = "Limit:"; +$l['syndication_limit_desc'] = "Liczba wątków do jednoczesnej subskrypcji (zalecana: poniżej 50)."; +$l['syndication_threads_time'] = "wątków naraz"; +$l['syndicate_all_forums'] = "Wszystkie działy"; + +$l['redirect_markforumread'] = "Wybrany dział został oznaczony jako przeczytany."; +$l['redirect_markforumsread'] = "Wybrane działy zostały oznaczone jako przeczytane."; +$l['redirect_forumpasscleared'] = "Przechowywane hasła zostały wyczyszczone."; +$l['redirect_cookiescleared'] = "Wszystkie ciasteczka zostały wyczyszczone."; + +$l['error_invalidimtype'] = "Ten użytkownik nie określił w profilu swoich danych dla tego komunikatora."; +$l['error_invalidhelpdoc'] = "Wybrany dokument pomocy nie istnieje."; + +$l['dst_settings_updated'] = "Ustawienia dotyczące czasu zimowego zostały automatycznie zaktualizowane.

    Teraz nastąpi przeniesienie na stronę główną forum."; diff --git a/Upload/inc/languages/polish/modcp.lang.php b/Upload/inc/languages/polish/modcp.lang.php new file mode 100644 index 0000000..787d46b --- /dev/null +++ b/Upload/inc/languages/polish/modcp.lang.php @@ -0,0 +1,330 @@ +Post napisany przez {2}"; +$l['report_info_post_thread'] = "
    W dziale {2}"; +$l['report_info_profile'] = "Profil użytkownika {1}"; +$l['report_info_reputation'] = "Punkt reputacji od {2}"; +$l['report_info_rep_profile'] = "
    Dla użytkownika {1}"; +$l['report_info_lastreporter'] = "{1}
    zgłoszony przez {2}"; + +$l['moderator_notes'] = "Notatki moderatorów"; +$l['notes_public_all'] = "Te notatki widzą wszyscy moderatorzy."; +$l['save_notes'] = "Zapisz"; +$l['bans_ending_soon'] = "Bany, które zostaną wkrótce zniesione"; +$l['latest_5_modactions'] = "5 ostatnich akcji moderatorów"; +$l['awaiting_moderation'] = "Oczekujące na moderację"; +$l['type'] = "Typ"; +$l['number_awaiting'] = "Liczba oczekujących"; +$l['latest'] = "Ostatni"; +$l['ipsearch'] = "Wyszukiwanie IP"; +$l['ipsearch_results'] = "Wyniki wyszukiwania IP '{1}'"; +$l['ipaddress_search'] = "Szukaj adresu IP"; +$l['ipaddress_misc_info'] = "Inne informacje dla adresu '{1}'"; +$l['ipaddress_host_name'] = "Nazwa hosta:"; +$l['ipaddress_location'] = "Lokalizacja GeoIP:"; +$l['search_users'] = "Znajdź użytkowników"; +$l['search_posts'] = "Znajdź posty"; +$l['ip_address'] = "Adres IP:"; +$l['result'] = "Wyniki"; +$l['ipresult_regip'] = "IP rejestracji:"; +$l['ipresult_lastip'] = "Ostatnio używał tego IP:"; +$l['ipresult_post'] = "Post:"; +$l['subject'] = "Temat"; +$l['username'] = "Użytkownik"; +$l['ipaddress'] = "IP"; +$l['options'] = "Opcje:"; +$l['find'] = "Znajdź"; +$l['modlogs'] = "Logi moderatorów"; +$l['action'] = "Akcja"; +$l['all_moderators'] = "Wszyscy moderatorzy"; +$l['ip'] = "Adres IP"; +$l['info_on_ip'] = "Informacje dla tego adresu IP"; +$l['information'] = "Informacja"; +$l['filter_modlogs'] = "Filtruj logi moderatorów"; +$l['forum'] = "Dział"; +$l['post'] = "Post"; +$l['from_moderator'] = "Moderator:"; +$l['na_deleted'] = "Usunięto"; +$l['sort_by'] = "Sortuj wg:"; +$l['forum_name'] = "Nazwa działu"; +$l['thread_subject'] = "Temat wątku"; +$l['in'] = "w"; +$l['order'] = "kolejności"; +$l['asc'] = "rosnącej"; +$l['desc'] = "malejącej"; +$l['per_page'] = "Wyników na stronie:"; +$l['filter_logs'] = "Pokaż logi"; +$l['error_no_log_results'] = "Nie ma rezultatów dla podanych kryteriów wyszukiwania."; +$l['find_users'] = "Szukaj użytkowników"; +$l['users'] = "Użytkownicy"; +$l['regdate'] = "Data rejestracji"; +$l['lastvisit'] = "Ostatnia wizyta"; +$l['postnum'] = "Liczba postów"; +$l['username_contains'] = "Których login zawiera"; +$l['no_user_results'] = "Nie ma rezultatów dla podanych kryteriów wyszukiwania."; +$l['edit_profile'] = "Edycja profilu {1}"; +$l['birthday'] = "Data urodzenia:"; +$l['title'] = "Tytuł użytkownika:"; +$l['profile_required'] = "Wymagane pola"; +$l['remove_avatar'] = "Usunąć awatar?"; +$l['profile_optional'] = "Dodatkowe pola"; +$l['website_url'] = "Strona domowa:"; +$l['birthdate'] = "Urodziny:"; +$l['icq_number'] = "Numer ICQ:"; +$l['aim_screenname'] = "Nazwa użytkownika AIM:"; +$l['yahoo_id'] = "Identyfikator Yahoo:"; +$l['skype_id'] = "Identyfikator Skype:"; +$l['google_id'] = "Identyfikator Google Talk:"; +$l['away_notice'] = "Ta opcja pozwala na ustawienie statusu \"Nieobecny\"."; +$l['additional_information'] = "Dodatkowe informacje"; +$l['update_profile'] = "Aktualizuj profil"; +$l['custom_usertitle'] = "Tytuł użytkownika"; +$l['new_custom_usertitle'] = "Nowy tytuł użytkownika (zostaw puste, aby użyć już istniejącego):"; +$l['custom_usertitle_note'] = "Możesz przypisać sobie dowolny tytuł użytkownika. Zastąpi on tytuł właściwy dla grupy."; +$l['default_usertitle'] = "Domyślny tytuł użytkownika:"; +$l['current_custom_usertitle'] = "Aktualny tytuł użytkownika:"; +$l['revert_usertitle'] = "Przywróć tytuł domyślny dla grupy"; +$l['additional_contact_details'] = "Dodatkowe informacje kontaktowe"; +$l['current_username'] = "Login:"; +$l['away_information'] = "Dostępność"; +$l['away_status'] = "Status:"; +$l['away_status_desc'] = "Pozwala pozostawić wiadomość jeśli nie będzie cię na forum przez jakiś czas."; +$l['im_away'] = "Jestem niedostępny"; +$l['im_here'] = "Jestem dostępny"; +$l['away_reason'] = "Powód nieobecności:"; +$l['away_reason_desc'] = "Pozwala na wpisanie krótkiego powodu nieobecności (maksymalnie 200 znaków)."; +$l['return_date'] = "Data powrotu:"; +$l['return_date_desc'] = "Jeśli wiesz kiedy wrócisz, możesz wpisać datę powrotu."; +$l['error_modcp_return_date_past'] = "Data powrotu nie może być datą w przeszłości."; +$l['usergroup'] = "Główna grupa użytkowników"; +$l['redirect_user_updated'] = "Profil użytkownika został zaktualizowany."; +$l['posts_awaiting_moderation'] = "Posty oczekujące na moderację"; +$l['threads_awaiting_moderation'] = "Wątki oczekujące na moderację"; +$l['attachments_awaiting_moderation'] = "Załączniki oczekujące na moderację"; +$l['mod_queue'] = "Oczekujące na moderację"; +$l['approve'] = "Zatwierdź"; +$l['ignore'] = "Ignoruj"; +$l['perform_actions'] = "Wykonaj czynności"; +$l['author'] = "Autor"; +$l['threads'] = "Wątki"; +$l['posts'] = "Posty"; +$l['filename'] = "Nazwa pliku"; +$l['thread_post'] = "Wątek / Post"; +$l['permanent'] = "Na zawsze"; +$l['ban_error'] = "Błąd"; +$l['ban_banned'] = "Zbanowani użytkownicy"; +$l['ban_user'] = "Zbanuj użytkownika"; +$l['reason'] = "Powód"; +$l['ban_username'] = "Login:"; +$l['ban_reason'] = "Powód:"; +$l['ban_length'] = "Długość"; +$l['ban_remaining'] = "pozostało"; +$l['ban_ending_imminently'] = "Ban wkrótce zostanie zniesiony"; +$l['ban_bannedby'] = "Zbanowany przez"; +$l['ban_movegroup'] = "Przenieś do grupy:"; +$l['ban_liftafter'] = "Znieś bana po:"; +$l['no_banned'] = "Nie ma zbanowanych użytkowników."; +$l['no_banned_group'] = "Nie ma zbanowanych grup użytkowników."; +$l['redirect_banuser'] = "Użytkownik został zbanowany."; +$l['redirect_banuser_updated'] = "Ustawienia dotyczące bana zostały zaktualizowane."; +$l['invalid_username'] = "Nie istnieje użytkownik o podanym loginie. Upewnij się, że podajesz prawidłowy login."; +$l['error_useralreadybanned'] = "Ten użytkownik jest już zbanowany. Nie możesz zbanować go dwukrotnie."; +$l['error_cannotbanuser'] = "Nie możesz zbanować tego użytkownika, bo ma on wyższy poziom uprawnień od Ciebie. Skontaktuj się z administratorem by zbanować tego użytkownika."; +$l['error_cannotbanself'] = "Nie możesz zbanować sam siebie. Podaj inny login."; +$l['error_no_perm_to_ban'] = "Nie masz uprawnień by zbanować tego użytkownika."; +$l['error_nobanreason'] = "Nie podano powodu bana. Wpisz poprawny powód poniżej."; +$l['error_nobangroup'] = "Nie wybrano grupy, do której użytkownik ma zostać przeniesiony."; +$l['edit_ban'] = "Edytuj bana"; +$l['lift_ban'] = "Znieś bana"; +$l['ban'] = "Banuj"; +$l['error_invalidban'] = "Wybrany ban nie istnieje."; +$l['redirect_banlifted'] = "Ban został zdjęty."; +$l['mark_all_ignored'] = "Oznacz wszystkie jako ignorowane"; +$l['mark_all_deletion'] = "Oznacz wszystkie do usunięcia"; +$l['mark_all_approved'] = "Oznacz wszystkie do zatwierdzenia"; +$l['meta_forum'] = "Dział:"; +$l['meta_thread'] = "Wątek:"; +$l['mod_queue_empty'] = "Nie ma wątków, postów ani załączników oczekujących na moderację."; +$l['mod_queue_threads_empty'] = "Nie ma wątków oczekujących na moderację."; +$l['mod_queue_posts_empty'] = "Nie ma postów oczekujących na moderację"; +$l['mod_queue_attachments_empty'] = "Nie ma załączników oczekujących na moderację"; +$l['redirect_threadsmoderated'] = "Wybrane wątki zostały poddane moderacji."; +$l['redirect_postsmoderated'] = "Wybrane posty zostały poddane moderacji."; +$l['redirect_attachmentsmoderated'] = "Wybrane załączniki zostały poddane moderacji."; +$l['multi_approve_posts'] = "Wybrane posty zostały zatwierdzone."; +$l['multi_delete_posts'] = "Wybrane posty zostały trwale usunięte."; +$l['multi_soft_delete_posts'] = "Wybrane posty zostały nietrwale usunięte."; +$l['multi_approve_threads'] = "Wybrane wątki zostały zatwierdzone."; +$l['multi_delete_threads'] = "Wybrane wątki zostały trwale usunięte."; +$l['multi_soft_delete_threads'] = "Wybrane wątki zostały nietrwale usunięte."; +$l['edited_user'] = "Wyedytowano profil użytkownika"; +$l['edited_user_info'] = "Użytkownik: {1}"; +$l['edited_user_ban'] = "Wyedytowano bana użykownika"; +$l['banned_user'] = "Zbanowano użytkownika"; +$l['lifted_ban'] = "Zdjęto bana"; +$l['no_bans_ending'] = "W najbliższym czasie nie zostaną zdjęte żadne bany."; + +$l['warning_logs'] = "Logi ostrzeżeń"; +$l['warned_user'] = "Ostrzeżony użytkownik"; +$l['warning'] = "Ostrzeżenie"; +$l['date_issued'] = "Data wystawienia"; +$l['expires'] = "Przedawni się"; +$l['expiry_date'] = "Data przedawnienia"; +$l['issued_date'] = "Data wystawienia"; +$l['issued_by'] = "Wystawione przez"; +$l['details'] = "Szczegóły"; +$l['filter_warning_logs'] = "Filtruj logi ostrzeżeń"; +$l['filter_warned_user'] = "Ostrzeżony użytkownik:"; +$l['filter_issued_by'] = "Ostrzeżenie dodane przez:"; +$l['filter_reason'] = "Powód zawiera:"; +$l['view'] = "Podgląd"; +$l['no_warning_logs'] = "Brak logów ostrzeżeń."; +$l['revoked'] = "Zdjęto "; +$l['signature'] = "Sygnatura"; +$l['suspend_signature'] = "Wyłącz sygnaturę użytkownika"; +$l['suspend_length'] = "Czas blokady:"; +$l['mod_notes'] = "Notatki moderatora"; +$l['moderation'] = "Opcje moderatora"; +$l['moderate_posts'] = "Posty tego użytkownika będą moderowane"; +$l['suspend_posts'] = "Odbierz użytkownikowi możliwość pisania"; +$l['modpost_length'] = "Posty będą moderowane przez:"; +$l['suspost_length'] = "Odbierz użytkownikowi możliwość pisania na okres:"; + +$l['moderateposts_for'] = "Posty moderowane do {1}.
    Odznacz tę opcję, aby anulować ograniczenie lub przedłuż je poniżej."; +$l['suspendposting_for'] = "Odebrana możliwość pisania do {1}.
    Odznacz tę opcję, aby anulować ograniczenie lub przedłuż je poniżej."; +$l['suspendsignature_for'] = "Sygnatura zawieszona do {1}.
    Odznacz tę opcję, aby anulować ograniczenie lub przedłuż je poniżej."; +$l['suspendposting_perm'] = "Zawieszone na zawsze.
    Odznacz tę opcję, aby anulować ograniczenie lub przedłuż je poniżej."; +$l['moderateposts_perm'] = "Moderowane na zawsze.
    Odznacz tę opcję, aby anulować ograniczenie lub przedłuż je poniżej."; +$l['suspendsignature_perm'] = "Zawieszona na zawsze.
    Odznacz tÄ™ opcjÄ™, aby anulować ograniczenie lub przedÅ‚uż je poniżej."; +$l['suspendsignature_error'] = "Wybrano, aby zawiesić użytkownikowi możliwość pokazywania sygnatury, ale nie podano prawidÅ‚owego okresu czasu. Podaj prawidÅ‚owy okres czasu lub odznacz tÄ™ opcjÄ™, aby anulować."; +$l['moderateposting_error'] = "Wybrano, aby posty użytkownika byÅ‚y moderowane, ale nie podano prawidÅ‚owego okresu czasu. Podaj prawidÅ‚owy okres czasu lub odznacz tÄ™ opcjÄ™, aby anulować."; +$l['suspendposting_error'] = "Wybrano, aby odebrać użytkownikowi możliwość pisania, ale nie podano prawidÅ‚owego okresu czasu. Podaj prawidÅ‚owy okres czasu lub odznacz tÄ™ opcjÄ™, aby anulować."; +$l['suspendmoderate_error'] = "Wybrano zarówno opcjÄ™ moderowania postów użytkownika, jak i jej anulowania. Wybierz tylko jednÄ… z opcji."; + +$l['expire_hours'] = "godzin(y)"; +$l['expire_days'] = "dzieÅ„ (dni)"; +$l['expire_weeks'] = "tydzieÅ„ (tygodni)"; +$l['expire_months'] = "miesiÄ…c (miesiÄ™cy)"; +$l['expire_permanent'] = "nigdy"; + +$l['manage_announcement'] = "ZarzÄ…dzanie ogÅ‚oszeniami"; +$l['forum_announcements'] = "OgÅ‚oszenia w dziaÅ‚ach"; +$l['announcement'] = "OgÅ‚oszenie"; +$l['controls'] = "CzynnoÅ›ci"; +$l['expired_announcement'] = "Przedawnione ogÅ‚oszenie"; +$l['active_announcement'] = "Aktywne ogÅ‚oszenie"; +$l['active'] = "Aktywne"; +$l['expired'] = "Przedawnione"; +$l['edit'] = "Edytuj"; +$l['add_announcement'] = "Nowe ogÅ‚oszenie"; +$l['edit_announcement'] = "Edytuj ogÅ‚oszenie"; +$l['no_forum_announcements'] = "Brak ogÅ‚oszeÅ„ w dziaÅ‚ach na forum."; +$l['no_global_announcements'] = "Brak globalnych ogÅ‚oszeÅ„ na forum."; +$l['add_global_announcement'] = "Nowe globalne ogÅ‚oszenie"; +$l['global_announcements'] = "Globalne ogÅ‚oszenia"; +$l['title'] = "TytuÅ‚"; +$l['start_date'] = "Data rozpoczÄ™cia"; +$l['time'] = "Godzina:"; +$l['end_date'] = "Data zakoÅ„czenia"; +$l['never'] = "Nigdy"; +$l['allow_html'] = "WÅ‚Ä…cz HTML"; +$l['allow_mycode'] = "WÅ‚Ä…cz MyCode"; +$l['allow_smilies'] = "WÅ‚Ä…cz emotikony"; +$l['reset'] = "Wyczyść"; +$l['january'] = "styczeÅ„"; +$l['february'] = "luty"; +$l['march'] = "marzec"; +$l['april'] = "kwiecieÅ„"; +$l['may'] = "maj"; +$l['june'] = "czerwiec"; +$l['july'] = "lipiec"; +$l['august'] = "sierpieÅ„"; +$l['september'] = "wrzesieÅ„"; +$l['october'] = "październik"; +$l['november'] = "listopad"; +$l['december'] = "grudzieÅ„"; +$l['delete_announcement'] = "UsuÅ„ ogÅ‚oszenie"; +$l['confirm_delete_announcement'] = "Czy na pewno chcesz usunąć to ogÅ‚oszenie?"; +$l['redirect_add_announcement'] = "OgÅ‚oszenie zostaÅ‚o dodane."; +$l['redirect_edit_announcement'] = "OgÅ‚oszenie zostaÅ‚o wyedytowane."; +$l['redirect_delete_announcement'] = "OgÅ‚oszenie zostaÅ‚o usuniÄ™te."; +$l['error_missing_title'] = "Nie podano tytuÅ‚u."; +$l['error_missing_message'] = "Nie podano treÅ›ci."; +$l['error_missing_forum'] = "Nie wybrano dziaÅ‚u."; +$l['error_invalid_start_date'] = "Data rozpoczÄ™cia wyÅ›wietlania ogÅ‚oszenia jest nieprawidÅ‚owa."; +$l['error_invalid_end_date'] = "Data zakoÅ„czenia wyÅ›wietlania ogÅ‚oszenia jest nieprawidÅ‚owa."; +$l['error_end_before_start'] = "Data zakoÅ„czenia wyÅ›wietlania ogÅ‚oszenia musi być późniejsza niż data rozpoczÄ™cia."; +$l['error_invalid_announcement'] = "Wybrane ogÅ‚oszenie jest nieprawidÅ‚owe."; + +$l['announcement_added'] = "Dodano ogÅ‚oszenie"; +$l['announcement_edited'] = "Wyedytowano ogÅ‚oszenie"; +$l['announcement_deleted'] = "UsuniÄ™to ogÅ‚oszenie Deleted"; + +$l['preview'] = 'PodglÄ…d'; + +$l['you_cannot_view_mod_logs'] = "Nie masz uprawnieÅ„ do przeglÄ…dania logów moderatorów."; +$l['you_cannot_view_reported_posts'] = "Nie masz uprawnieÅ„ do przeglÄ…dania zgÅ‚oszonych postów."; +$l['you_cannot_manage_announcements'] = "Nie masz uprawnieÅ„ do zarzÄ…dzania ogÅ‚oszeniami."; +$l['you_cannot_moderate_threads'] = "Nie masz uprawnieÅ„ do moderacji wÄ…tków."; +$l['you_cannot_moderate_posts'] = "Nie masz uprawnieÅ„ do moderacji postów."; +$l['you_cannot_moderate_attachments'] = "Nie masz uprawnieÅ„ do moderacji zaÅ‚Ä…czników."; +$l['you_cannot_use_mod_queue'] = "Nie masz uprawnieÅ„ do korzystania z kolejki moderacji."; + +$l['post'] = 'Post'; +$l['search_user'] = "Szukaj użytkownika"; diff --git a/Upload/inc/languages/polish/moderation.lang.php b/Upload/inc/languages/polish/moderation.lang.php new file mode 100644 index 0000000..2836ce1 --- /dev/null +++ b/Upload/inc/languages/polish/moderation.lang.php @@ -0,0 +1,221 @@ +Wszystkie posty z wÄ…tku zostanÄ… doÅ‚Ä…czone do nowego, a doÅ‚Ä…czany wÄ…tek zostanie usuniÄ™ty."; +$l['merge_posts'] = "ÅÄ…cz posty"; +$l['merge_posts_note'] = "Wszystkie zaznaczone posty zostanÄ… doÅ‚Ä…czone do pierwszego zaznaczonego posta."; +$l['move_copy_thread'] = "PrzenieÅ› / Kopiuj wÄ…tek"; +$l['new_forum'] = "Nowy dziaÅ‚:"; +$l['method'] = "Metoda"; +$l['method_move'] = "PrzenieÅ› wÄ…tek"; +$l['method_move_redirect'] = "PrzenieÅ› wÄ…tek i zostaw przekierowanie w aktualnym dziale na"; +$l['redirect_expire_note'] = "dni (zostaw to pole puste by pozostawić przekierowanie na zawsze)"; +$l['method_copy'] = "Skopiuj do nowego dziaÅ‚u"; +$l['split_thread_subject'] = "[oddzielony]"; +$l['split_thread'] = "Podziel wÄ…tek"; +$l['move_posts'] = "PrzenieÅ› posty"; +$l['thread_to_move_to'] = "WÄ…tek do którego majÄ… być przeniesione posty:"; +$l['move_post_note'] = "Skopiuj link do wÄ…tku, do którego majÄ… zostać przeniesione wybrane posty, do pola tekstowego."; +$l['new_thread_info'] = "Informacja o nowym wÄ…tku"; +$l['posts_to_split'] = "Posty do wydzielenia"; +$l['thread_notes_editor'] = "Edytor notatek wÄ…tku"; +$l['below_notes'] = "Poniżej możesz edytować notatki tego wÄ…tku."; +$l['update_notes'] = "Aktualizuj notatki wÄ…tków"; +$l['mod_logs'] = "Logi moderatorów (20 ostatnich akcji)"; +$l['mod_username'] = "Użytkownik"; +$l['mod_date'] = "Data"; +$l['mod_actions'] = "Akcja"; +$l['mod_information'] = "Informacja"; +$l['read'] = "Czytaj:"; +$l['thread'] = "WÄ…tek:"; +$l['post'] = "Post:"; +$l['forum'] = "DziaÅ‚:"; +$l['confirm_execute_tool'] = "Wykonywanie czynnoÅ›ci"; +$l['confirm_execute_tool_desc'] = "Czy na pewno chcesz wykonać czynność {1}? Po wykonaniu jej nie bÄ™dzie można cofnać wprowadzonych zmian."; +$l['delete_threads'] = "UsuÅ„ wÄ…tki"; +$l['confirm_delete_threads'] = "Czy na pewno chcesz usunąć zaznaczone wÄ…tki?"; +$l['move_threads'] = "PrzenieÅ› wÄ…tki"; +$l['confirm_delete_posts'] = "Czy na pewno chcesz usunąć zaznaczone posty? JeÅ›li w wÄ…tku nie bÄ™dzie żadnych postów, zostanie on usuniÄ™ty."; +$l['post_separator'] = "Separator postów"; +$l['new_line'] = "Wolna linijka"; +$l['horizontal_rule'] = "Pozioma linia"; +$l['resolve_fail'] = "(host nieznany)"; + +$l['opened'] = "Otwarty"; +$l['closed'] = "ZamkniÄ™ty"; +$l['stuck'] = "PrzypiÄ™ty"; +$l['unstuck'] = "OdpiÄ™ty"; +$l['mod_process'] = "WÄ…tek {1}"; +$l['redirects_removed'] = "UsuniÄ™to przekierowanie"; +$l['thread_deleted'] = "UsuniÄ™to wÄ…tek: {1}"; +$l['poll_deleted'] = "UsuniÄ™to ankietÄ™: {1}"; +$l['thread_approved'] = "Zatwierdzono wÄ…tek: {1}"; +$l['thread_unapproved'] = "Ukryto wÄ…tek: {1}"; +$l['thread_restored'] = "Przywrócono wÄ…tek: {1}"; +$l['thread_soft_deleted'] = "Nietrwale usuniÄ™to wÄ…tek: {1}"; +$l['deleted_selective_posts'] = "UsuniÄ™to zaznaczone posty ({1})"; +$l['merged_selective_posts'] = "PoÅ‚Ä…czono zaznaczone posty"; +$l['split_selective_posts'] = "Wydzielono posty (ID postów: {1}) do wÄ…tku (ID wÄ…tku: {2})"; +$l['move_selective_posts'] = "Przeniesiono posty (ID postów: {1}) do wÄ…tku (ID wÄ…tku: {2}"; +$l['removed_subscriptions'] = "UsuniÄ™to wszystkie subskrypcje"; +$l['thread_moved'] = "Przeniesiono wÄ…tek"; +$l['thread_copied'] = "Skopiowano wÄ…tek"; +$l['thread_merged'] = "PoÅ‚Ä…czono wÄ…tki"; +$l['thread_split'] = "Oddzielono wÄ…tki"; +$l['thread_notes_edited'] = "Wyedytowano notatki wÄ…tków"; +$l['multi_deleted_threads'] = "UsuniÄ™to wÄ…tki"; +$l['multi_opened_threads'] = "Otwarto wÄ…tki"; +$l['multi_closed_threads'] = "ZamkniÄ™to wÄ…tki"; +$l['multi_approved_threads'] = "Zatwierdzono wÄ…tki"; +$l['multi_unapproved_threads'] = "Ukryto wÄ…tki"; +$l['multi_restored_threads'] = "Przywrócono wÄ…tki"; +$l['multi_soft_deleted_threads'] = "Nietrwale usuniÄ™to wÄ…tki"; +$l['multi_approve_posts'] = "Zatwierdzono zaznaczone posty"; +$l['multi_unapprove_posts'] = "Ukryto zaznaczone posty"; +$l['multi_restore_posts'] = "Przywrócono zaznaczone posty"; +$l['multi_soft_delete_posts'] = "Nietrwale usuniÄ™to zaznaczone posty"; +$l['multi_stuck_threads'] = "PrzypiÄ™to wÄ…tki"; +$l['multi_unstuck_threads'] = "OdpiÄ™to wÄ…tki"; +$l['multi_moved_threads'] = "Przeniesiono wÄ…tki"; +$l['multi_copied_threads'] = "Skopiowano wÄ…tki"; +$l['custom_tool'] = "Niestandardowe narzÄ™dzie moderatorskie: {1}"; + +$l['delayed_moderation'] = "Opóźniona moderacja"; +$l['delayed_moderation_desc'] = "Opóźniaj akcje moderatorskie o okreÅ›lonÄ… liczbÄ™ dni."; +$l['threads'] = "WÄ…tki:"; +$l['threads_selected'] = "Zaznaczono {1} wÄ…tków"; +$l['run_moderation_time'] = "Przeprowadź akcje moderatorskie w dniu:"; +$l['days'] = "dni"; +$l['moderation_action'] = "Opóźniona moderacja:"; +$l['open_close_thread'] = "Zamknij/Otwórz wÄ…tek"; +$l['remove_redirects'] = "UsuÅ„ przekierowania"; +$l['remove_subscriptions'] = "UsuÅ„ subskrypcje"; +$l['approve_unapprove_thread'] = "Zatwierdź/Ukryj wÄ…tek"; +$l['softdelete_restore_thread'] = "Nietrwale usuÅ„/Przywróć wÄ…tek"; +$l['stick_unstick_thread'] = "Przypnij/Odepnij wÄ…tek"; +$l['save_delayed_moderation'] = "Zapisz opóźnionÄ… moderacjÄ™"; +$l['custom'] = "inne"; +$l['delayed_mod_queue'] = "Kolejka opóźnionej moderacji"; +$l['days_to_perform_action'] = "Czas do wykonania akcji"; +$l['leave_redirect'] = "ProwadzÄ…ce przekierowanie:"; +$l['multiple_threads'] = "Wiele wÄ…tków"; +$l['actions'] = "Akcje"; +$l['cancel'] = "Anuluj"; +$l['leave_redirect_for'] = "Zostaw przekierowanie w aktualnym dziale na:"; +$l['redirect_forever'] = "zawsze"; +$l['view_notes_for'] = "PrzeglÄ…da notatki użytkownika {1}"; + +$l['purgespammer'] = "UsuÅ„ spamera"; +$l['purgespammer_purge'] = "UsuÅ„ spamera {1}"; +$l['purgespammer_purge_desc'] = "Wybranie opcji spowoduje usuniÄ™cie caÅ‚ej aktywnoÅ›ci (postów, prywatnych wiadomoÅ›ci, wydarzeÅ„, itp.) spamera oraz samego użytkownika {1}."; +$l['purgespammer_ban'] = "zbanuj"; +$l['purgespammer_delete'] = "usuÅ„"; +$l['purgespammer_submit'] = "UsuÅ„ spamera"; +$l['purgespammer_success'] = "Użytkownik zostaÅ‚ usuniÄ™ty."; +$l['purgespammer_invalid_user'] = "Wybrano nieprawidÅ‚owego użytkownika."; +$l['purgespammer_modlog'] = "UsuniÄ™to spamera"; + +$l['error_invalidpm'] = "NieprawidÅ‚owa wiadomość"; +$l['error_nomergeposts'] = "Musisz wybrać 1 lub wiÄ™cej postów do poÅ‚Ä…czenia."; +$l['error_cantsplitonepost'] = "Nie możesz wydzielić jedynego posta z wÄ…tku."; +$l['error_badmergeurl'] = "Link do wÄ…tku jest nieprawidÅ‚owy. Wprowadź poprawny link.
    Wróć i spróbuj ponownie."; +$l['error_badmovepostsurl'] = "Link do wątku jest nieprawidłowy. Wprowadź poprawny link.
    Wróć i spróbuj ponownie."; +$l['error_inline_nothreadsselected'] = "Nie zaznaczono żadnego wÄ…tku lub twoja poprzednia sesja wygasÅ‚a (automatycznie po 1 godzinie nieaktywnoÅ›ci). Wybierz inne wÄ…tki i spróbuj ponownie."; +$l['error_inline_nopostsselected'] = "Nie zaznaczono żadnego posta lub twoja poprzednia sesja minęła (automatycznie po 1 godzinie nieaktywnoÅ›ci). Wybierz inne posty i spróbuj ponownie."; +$l['error_movetocategory'] = "To narzÄ™dzie sÅ‚uży do przenoszenia wÄ…tków do kategorii. ZmieÅ„ ustawienia wg swoich potrzeb i wskaż wÅ‚aÅ›ciwy dziaÅ‚."; +$l['error_cantsplitall'] = "Nie możesz wydzielić wszystkich postów - wÄ…tek nie może pozostać pusty!"; +$l['error_cantmoveall'] = "Nie możesz przenieść wszystkich postów - wÄ…tek nie może pozostać pusty!"; +$l['error_nosplitposts'] = "Nie możesz wydzielić postów, bo nic nie zaznaczono."; +$l['error_movetosameforum'] = "Wskazany wÄ…tek istnieje już w tym dziale. Wybierz inny dziaÅ‚."; +$l['error_mergewithself'] = "ÅÄ…czenie wÄ…tków nie powiodÅ‚o siÄ™.
    Wróć i wprowadź prawidłowy URL."; +$l['error_movetoself'] = "Nie można przenieść postów do tego samego wątku.
    Wróć i wprowadź prawidłowy URL."; +$l['error_delayedmoderation_unsupported_type'] = "Nie wybrano prawidłowego typu akcji dla opóźnionej moderacji."; +$l['error_delayedmoderation_unsupported_method'] = "Nie wybrano prawidłowej metody przeniesienia dla tej akcji opóźnionej moderacji."; +$l['error_delayedmoderation_invalid_date_day'] = "Nie wprowadzono prawidłowego dnia dla akcji opóźnionej moderacji."; +$l['error_delayedmoderation_invalid_date_month'] = "Nie wprowadzono prawidłowego miesiąca dla akcji opóźnionej moderacji."; +$l['error_delayedmoderation_invalid_date_year'] = "Nie wprowadzono prawidłowego roku dla akcji opóźnionej moderacji."; + +$l['redirect_pollnotdeleted'] = "Ankieta nie została usunięta, gdyż nie zaznaczono pola \"Usuń\".
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_polldeleted'] = "Ankieta została usunięta.
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_mergeposts'] = "Zaznaczone posty zostały połączone. Teraz nastąpi przeniesienie do wątku."; +$l['redirect_openthread'] = "Wątek został otwarty.
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_closethread'] = "Wątek został zamknięty.
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_stickthread'] = "Wątek został przypięty.
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_unstickthread'] = "Wątek został odpięty.
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_threaddeleted'] = "Wątek został trwale usunięty.
    Teraz nastąpi przeniesienie na forum."; +$l['redirect_threadmoved'] = "Wątek został przeniesiony lub skopiowany do wybranego działu.
    Teraz nastąpi przeniesienie do tego wątku."; +$l['redirect_redirectsremoved'] = "Wszystkie przekierowania prowadzące do tego wątku zostały usunięte.
    Teraz nastąpi przeniesienie do tego wątku."; +$l['redirect_threadapproved'] = "Wątek został zatwierdzony."; +$l['redirect_threadunapproved'] = "Wątek został ukryty."; +$l['redirect_threadrestored'] = "Wątek został przywrócony."; +$l['redirect_threadsoftdeleted'] = "Wątek został nietrwale usunięty."; +$l['redirect_threadsplit'] = "Wątek został podzielony.
    Teraz nastąpi przeniesienie do wątku oddzielonego jako nowy."; +$l['redirect_moveposts'] = "Posty zostały przeniesione do wybranego wątku.
    Teraz nastąpi przeniesienie do tego wątku."; +$l['redirect_threadnotesupdated'] = "Notatki do tego wątku zostały zaktualizowane.
    Teraz nastąpi przeniesienie do tego wątku."; +$l['redirect_threadsmerged'] = "Wybrane wątki zostały połączone.
    Teraz nastąpi przeniesienie do wątku, który powstał z połączenia."; +$l['redirect_inline_threadsdeleted'] = "Wskazane wątki zostały trwale usunięte.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_inline_threadsopened'] = "Wskazane wątki zostały otwarte.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_inline_threadsclosed'] = "Wskazane wątki zostały zamknięte.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_inline_threadsstuck'] = "Wskazane wątki zostały przypięte.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_inline_threadsunstuck'] = "Wskazane wątki zostały odpięte.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_inline_threadsmoved'] = "Wskazane wątki zostały przeniesione.
    Teraz nastąpi przeniesienie do działu, w którym je umieszczono."; +$l['redirect_inline_threadsapproved'] = "Wskazane wątki zostały zatwierdzone.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_inline_threadsunapproved'] = "Wskazane wątki zostały ukryte.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_inline_threadsrestored'] = "Wskazane wątki zostały przywrócone.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_inline_threadssoftdeleted'] = "Wskazane wątki zostały nietrwale usunięte.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_inline_postsmerged'] = "Wskazane posty zostały połączone.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_inline_postsapproved'] = "Wskazane posty zostały zatwierdzone.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_inline_postsunapproved'] = "Wskazane posty zostały ukryte.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_inline_postsrestored'] = "Wskazane posty zostały przywrócone.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_inline_postssoftdeleted'] = "Wskazane posty zostały nietrwale usunięte.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_postsdeleted'] = "Wskazane posty zostały trwale usunięte.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_removed_subscriptions'] = "Wszystkie subskrypcje tego wątku zostały usunięte.
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_customtool_thread'] = "Czynność \"{1}\" została wykonana.
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_customtool_forum'] = "Czynność \"{1}\" została wykonana.
    Teraz nastąpi przeniesienie do działu."; +$l['redirect_customtool_search'] = "Czynność \"{1}\" została wykonana.
    Teraz nastąpi przeniesienie do narzędzi wyszukiwania."; +$l['redirect_delayed_moderation_thread'] = "Narzędzie moderowania zostało zapisane i opóźnione o {1} dzień (dni).
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_delayed_moderation_forum'] = "Narzędzie moderowania zostało zapisane i opóźnione o {1} dzień (dni).
    Teraz nastąpi przeniesienie do działu."; +$l['redirect_delayed_moderation_search'] = "Narzędzie moderowania zostało zapisane i opóźnione o {1} dzień (dni).
    Teraz nastąpi przeniesienie do wyników wyszukiwania."; +$l['redirect_delayed_moderation_cancelled'] = "Wybrane narzędzie moderacji zostało anulowane.
    Teraz nastąpi przekierowanie do strony opóźnionej moderacji."; diff --git a/Upload/inc/languages/polish/newreply.lang.php b/Upload/inc/languages/polish/newreply.lang.php new file mode 100644 index 0000000..34e3260 --- /dev/null +++ b/Upload/inc/languages/polish/newreply.lang.php @@ -0,0 +1,55 @@ +Sygnatura: pod postem pojawi się twoja sygnatura (o ile jesteś zarejestrowanym użytkownikiem)."; +$l['options_emailnotify'] = "Powiadomienie: kiedy ktoś odpowie, otrzymasz powiadomienie w postaci wiadomości e-mail (o ile jesteś zarejestrowanym użytkownikiem)."; +$l['options_disablesmilies'] = "Wyłącz emotikony: emotikony w tym poście nie będą widoczne."; +$l['post_reply'] = "Odpowiedz"; +$l['preview_post'] = "Podgląd"; +$l['mod_options'] = "Opcje moderatora:"; +$l['close_thread'] = "Zamknij wątek: nikt nie będzie mógł odpowiadać w tym wątku."; +$l['stick_thread'] = "Przypnij wątek: wątek będzie widoczny na górze działu."; +$l['forum_rules'] = "{1} - zasady działu"; +$l['thread_review'] = "Podgląd wątku (od najnowszej odpowiedzi)"; +$l['thread_review_more'] = "Ten wątek ma jeszcze {1} odpowiedzi. Przeczytaj całość."; +$l['posted_by'] = "Napisane przez"; +$l['draft_saved'] = "Nowy szkic posta został zapisany.
    Teraz nastąpi przeniesienie do listy Twoich szkiców."; +$l['image_verification'] = "Potwierdzenie kodem"; +$l['verification_note'] = "Przepisz tekst z obrazka po lewej do poniższego pola tekstowego. Taki proces jest niezbędny, by zapobiec wysyłaniu wiadomości przez automaty."; +$l['verification_subnote'] = "(wielkość liter ma znaczenie)"; +$l['invalid_captcha'] = "Wprowadzony kod weryfikacji jest nieprawidłowy. Przepisz kod z obrazka dokładnie."; +$l['error_post_already_submitted'] = "Napisano już wcześniej identyczną odpowiedź."; +$l['multiquote_external_one'] = "Zaznaczono 1 post do zacytowania."; +$l['multiquote_external'] = "Zaznaczono {1} postów do zacytowania."; +$l['multiquote_external_one_deselect'] = "odznacz ten post"; +$l['multiquote_external_deselect'] = "odznacz te posty"; +$l['multiquote_external_one_quote'] = "Zacytuj ten post teraz"; +$l['multiquote_external_quote'] = "Zacytuj te posty teraz"; + +$l['redirect_newreply'] = "Post został umieszczony na forum."; +$l['redirect_newreply_moderation'] = "
    Twój post przed opublikowaniem zostanie sprawdzony przez moderatora. Teraz nastąpi przeniesienie do wątku."; +$l['redirect_newreply_post'] = "
    Teraz nastąpi przeniesienie do nowego posta."; +$l['redirect_newreplyerror'] = "Twoja wiadomość nie zostanie opublikowana, gdyż posiada nieprawidłową zawartość.
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_threadclosed'] = "Nie możesz odpowiedzieć w tym wątku, gdyż został zamknięty przez moderatora."; +$l['error_post_noperms'] = "Nie masz uprawnień do edytowania tego szkicu."; + +$l['error_stop_forum_spam_spammer'] = 'Twój adres IP lub e-mail znajduje się w bazie znanych spamerów. Jeżeli uważasz, że jest to błąd, powiadom o tym administratora.'; +$l['error_stop_forum_spam_fetching'] = 'Nie mogliśmy upewnić sie, że nie jesteś spamerem. Prawdopodobnie jest to spowodowane problemami z połączeniem z bazą danych. Spróbuj ponownie później.'; +$l['error_suspendedposting'] = "Odebrano Ci możliwość pisania postów. Blokada {1}.

    + +Data nałożenia ograniczenia: {2}"; +$l['error_suspendedposting_temporal'] = "zostanie zniesiona {1}"; +$l['error_suspendedposting_permanent'] = "jest permanentna"; diff --git a/Upload/inc/languages/polish/newthread.lang.php b/Upload/inc/languages/polish/newthread.lang.php new file mode 100644 index 0000000..ba4a17b --- /dev/null +++ b/Upload/inc/languages/polish/newthread.lang.php @@ -0,0 +1,57 @@ +Sygnatura: pod postem pojawi się twoja sygnatura (o ile jesteś zarejestrowanym użytkownikiem)."; +$l['options_emailnotify'] = "Powiadomienie: kiedy ktoś odpowie, otrzymasz powiadomienie e-mailem (o ile jesteś zarejestrowanym użytkownikiem)."; +$l['options_disablesmilies'] = "Wyłącz emotikony: emotikony w tym poście nie będą widoczne."; +$l['post_thread'] = "Napisz wątek"; +$l['preview_post'] = "Podgląd"; +$l['poll'] = "Ankieta:"; +$l['poll_desc'] = "Możesz dodać ankietę do wątku."; +$l['poll_check'] = "Chcę dodać ankietę"; +$l['num_options'] = "Liczba odpowiedzi:"; +$l['max_options'] = "(maksymalnie {1})"; +$l['mod_options'] = "Opcje moderatora:"; +$l['close_thread'] = "Zamknij wątek: nie będzie możliwości odpowiadania."; +$l['stick_thread'] = "Przypnij wątek: będzie widoczny na górze działu."; +$l['draft_saved'] = "Nowy szkic wątku został zapisany.
    Teraz nastąpi przeniesienie do listy Twoich szkiców."; +$l['image_verification'] = "Potwierdzenie kodem"; +$l['verification_note'] = "Przepisz tekst z obrazka po lewej do poniższego pola tekstowego. Taki proces jest niezbędny, by zapobiec wysyłaniu wiadomości przez automaty."; +$l['verification_subnote'] = "(wielkość liter ma znaczenie)"; +$l['invalid_captcha'] = "Wprowadzony kod weryfikacji jest nieprawidłowy. Przepisz kod z obrazka dokładnie."; +$l['error_post_already_submitted'] = "Już napisano identyczny wątek w tym dziale."; +$l['no_prefix'] = "Bez prefiksu"; +$l['forum_rules'] = "{1} - zasady działu"; + +$l['multiquote_external_one'] = "Wybrano 1 post z innego wątku."; +$l['multiquote_external'] = "Wybrano {1} postów z innych wątków."; +$l['multiquote_external_one_deselect'] = "odznacz ten post"; +$l['multiquote_external_deselect'] = "odznacz te posty"; +$l['multiquote_external_one_quote'] = "Zacytuj również ten post"; +$l['multiquote_external_quote'] = "Zacytuj również te posty"; + +$l['redirect_newthread'] = "Wątek został umieszczony na forum."; +$l['redirect_newthread_poll'] = "
    Teraz nastąpi przeniesienie do ustawień ankiety."; +$l['redirect_newthread_moderation'] = "
    Twój wątek przed opublikowaniem zostanie zweryfikowany przez moderatora. Teraz nastąpi przeniesienie do wątku."; +$l['redirect_newthread_thread'] = "
    Teraz nastąpi przeniesienie do nowego wątku."; +$l['invalidthread'] = "Nie masz uprawnień do edytowania wybranego szkicu."; + +$l['error_stop_forum_spam_spammer'] = 'Twój adres IP lub e-mail znajduje się w bazie znanych spamerów. Jeżeli uważasz, że jest to błąd, powiadom o tym administratora.'; +$l['error_stop_forum_spam_fetching'] = 'Nie mogliśmy upewnić sie, że nie jesteś spamerem. Prawdopodobnie jest to spowodowane problemami z połączeniem z bazą danych. Spróbuj ponownie później.'; +$l['error_suspendedposting'] = "Odebrano Ci możliwość pisania postów. Blokada {1}.

    + +Data nałożenia ograniczenia: {2}"; +$l['error_suspendedposting_temporal'] = "zostanie zniesiona {1}"; +$l['error_suspendedposting_permanent'] = "jest permanentna"; +?> \ No newline at end of file diff --git a/Upload/inc/languages/polish/online.lang.php b/Upload/inc/languages/polish/online.lang.php new file mode 100644 index 0000000..f2bcc48 --- /dev/null +++ b/Upload/inc/languages/polish/online.lang.php @@ -0,0 +1,136 @@ +{2}"; +$l['viewing_announcements2'] = "Przegląda ogłoszenie"; +$l['viewing_attachment'] = "Przegląda załącznik"; +$l['viewing_attachment2'] = "Przegląda załącznik w wątku {2}"; +$l['viewing_calendar'] = "Przegląda Kalendarz"; +$l['viewing_event'] = "Przegląda wydarzenie"; +$l['viewing_event2'] = "Przegląda wydarzenie {2}"; +$l['adding_event'] = "Dodaje wydarzenie"; +$l['editing_event'] = "Edytuje wydarzenie"; +$l['viewing_contact_us'] = "Przegląda stronę kontaktową"; +$l['editing_post'] = "Edytuje post"; +$l['viewing_forum'] = "Przegląda dział"; +$l['viewing_forum2'] = "Przegląda dział {2}"; +$l['forum_redirect_to'] = "Jest przekierowywany do: {2}"; +$l['viewing_index'] = "Przegląda stronę główną forum"; +$l['activating_account'] = "Aktywuje konto"; +$l['viewing_profile'] = "Przegląda profil"; +$l['viewing_profile2'] = "Przegląda profil {2}"; +$l['registering'] = "Rejestruje się"; +$l['logging_in'] = "Loguje się"; +$l['logging_in_plain'] = "Loguje się"; +$l['logging_out'] = "Wylogowuje się"; +$l['emailing_user'] = "Pisze e-mail"; +$l['rating_user'] = "Ocenia użytkownika"; +$l['viewing_memberlist'] = "Przegląda listę użytkowników"; +$l['viewing_whoposted'] = "Przegląda \"Kto napisał\""; +$l['viewing_whoposted2'] = "Przegląda \"Kto napisał\" w wątku {2}"; +$l['marking_read'] = "Oznacza działy jako przeczytane"; +$l['viewing_helpdocs'] = "Przegląda pomoc"; +$l['viewing_buddylist'] = "Przegląda listę znajomych"; +$l['viewing_smilies'] = "Przegląda listę emotikonów"; +$l['viewing_syndication'] = "Przegląda stronę RSS"; +$l['replying_thread'] = "Odpowiada w wątku"; +$l['replying_thread2'] = "Odpowiada w wątku {2}"; +$l['posting_thread'] = "Pisze nowy wątek"; +$l['posting_thread2'] = "Pisze nowy wątek w {2}"; +$l['viewing_wol'] = "Przegląda \"Kto jest online\""; +$l['viewing_woltoday'] = "Przegląda \"Kto był dzisiaj online\""; +$l['creating_poll'] = "Tworzy nową ankietę"; +$l['editing_poll'] = "Edytuje ankietę"; +$l['viewing_pollresults'] = "Przegląda wyniki ankiety"; +$l['voting_poll'] = "Głosuje w ankiecie"; +$l['using_modtools'] = "Używa narzędzi moderatorskich"; +$l['sending_pm'] = "Wysyła prywatną wiadomość"; +$l['reading_pm'] = "Czyta prywatną wiadomość"; +$l['editing_pmfolders'] = "Edytuje foldery PW"; +$l['using_pmsystem'] = "Używa systemu PW"; +$l['reporting_post'] = "Zgłasza post"; +$l['searching_forum'] = "Przeszukuje {1}"; +$l['reading_thread'] = "Czyta wątek"; +$l['reading_thread2'] = "Czyta wątek {2} {3}"; +$l['viewing_team'] = "Przegląda ekipę forum"; +$l['viewing_stats'] = "Przegląda statystyki forum"; +$l['updating_profile'] = "Aktualizuje profil"; +$l['updating_options'] = "Aktualizuje opcje"; +$l['editing_signature'] = "Edytuje sygnaturę"; +$l['changing_avatar'] = "Zmienia awatar"; +$l['viewing_subscriptions'] = "Przegląda subskrypcje wątków"; +$l['viewing_favorites'] = "Przegląda ulubione wątki"; +$l['editing_pad'] = "Edytuje osobisty notatnik"; +$l['editing_password'] = "Zmienia hasło"; +$l['user_cp'] = "Przegląda panel użytkownika"; +$l['viewing_portal'] = "Przegląda Portal"; +$l['viewing_noperms'] = "Przegląda informacje o braku dostępu"; +$l['unknown_location'] = "Nieznana lokalizacja"; +$l['giving_reputation'] = "Przyznaje punkt reputacji użytkownikowi {2}"; +$l['viewing_reputation_report'] = "Przegląda informacje o reputacji użytkownika {2}"; +$l['viewing_reputation_report2'] = "Przegląda informacje o reputacji"; +$l['member_resendactivation'] = "Przesyła sobie e-mail aktywujący"; +$l['member_lostpw'] = "Przywraca zapomniane hasło"; +$l['sending_thread'] = "Wysyła wątek znajomemu"; +$l['guest'] = "Gość"; +$l['page'] = "Strona"; +$l['users_online'] = "Kto jest online"; +$l['on_username'] = "Użytkownik"; +$l['time'] = "Czas"; +$l['location'] = "Lokalizacja"; +$l['online_today'] = "Kto był online przez ostatnie 24 godziny"; +$l['refresh_page'] = "Odśwież"; +$l['online_online_plural'] = "użytkowników aktywnych"; +$l['online_online_singular'] = "użytkownik aktywny"; +$l['online_member_plural'] = "zarejestrowanych"; +$l['online_member_singular'] = "zarejestrowany"; +$l['online_anon_plural'] = "niewidocznych"; +$l['online_anon_singular'] = "niewidoczny"; +$l['online_guest_plural'] = "gości"; +$l['online_guest_singular'] = "gość"; +$l['online_count'] = "{1} {2} w ciągu ostatnich {3} minut ({4} {5}, {6} {7} i {8} {9})."; +$l['ip'] = "IP:"; +$l['resolves_to'] = "Nazwa hosta:"; +$l['if_resolvable'] = "(jeśli możliwe)"; +$l['admin_options'] = "Opcje administratora:"; +$l['search_regip_users'] = "Szukaj użytkowników, którzy rejestrowali się z tego IP"; +$l['search_postip_users'] = "Szukaj użytkowników, którzy pisali z tego IP"; +$l['lookup'] = "[więcej]"; +$l['member_online_today'] = "1 użytkownik był dzisiaj online"; +$l['members_were_online_today'] = "W ciągu ostatnich 24 godzin było {1} użytkowników online"; +$l['member_online_hidden'] = " ({1} z nich był ukryty)"; +$l['members_online_hidden'] = " ({1} z nich było ukrytych)"; +$l['rating_thread'] = "Ocenia wątek"; +$l['viewing_imcenter'] = "Przegląda centrum IM"; +$l['managing_favorites'] = "Zarządza ulubionymi"; +$l['managing_subscriptions'] = "Zarządza subskrybowanymi wątkami"; +$l['managing_group'] = "Zarządza grupą użytkowników"; +$l['viewing_modcp'] = "Przegląda panel moderatora"; +$l['viewing_modlogs'] = "Przegląda logi moderatorów"; +$l['managing_announcements'] = "Zarządza ogłoszeniami"; +$l['search_for_user'] = "Wyszukuje użytkowników"; +$l['managing_warninglogs'] = "Zarządza logami ostrzeżeń"; +$l['searching_ips'] = "Wyszukuje IP"; +$l['viewing_reports'] = "Przegląda zgłoszone posty"; +$l['adding_announcement'] = "Dodaje ogłoszenie"; +$l['deleting_announcement'] = "Usuwa ogłoszenie"; +$l['editing_announcement'] = "Edytuje ogłoszenie"; +$l['managing_modqueue'] = "Moderuje oczekujące posty, wątki i załączniki"; +$l['editing_user_profiles'] = "Edytuje profile użytkowników"; +$l['managing_bans'] = "Zarządza banami"; +$l['revoking_warning'] = "Cofa ostrzeżenie"; +$l['warning_user'] = "Ostrzega użytkownika"; +$l['viewing_warning'] = "Przegląda ostrzeżenie"; +$l['managing_warnings'] = "Zarządza ostrzeżeniami"; +$l['changing_dst'] = "Zmienia ustawienia czasu letniego"; +$l['printing_thread'] = "Drukuje wątek"; +$l['printing_thread2'] = "Drukuje wątek {2}"; +$l['managing_buddyignorelist'] = "Zarządza listą znajomych/ignorowanych"; diff --git a/Upload/inc/languages/polish/polls.lang.php b/Upload/inc/languages/polish/polls.lang.php new file mode 100644 index 0000000..03dde4b --- /dev/null +++ b/Upload/inc/languages/polish/polls.lang.php @@ -0,0 +1,60 @@ +Uwaga: Po usunięciu ankiety nie będzie już możliwości jej przywrócenia."; +$l['question'] = "Pytanie:"; +$l['num_options'] = "Liczba odpowiedzi:"; +$l['max_options'] = "Maksymalnie"; +$l['poll_options'] = "Odpowiedzi ankiety:"; +$l['update_options'] = "Aktualizuj liczbę odpowiedzi"; +$l['poll_options_note'] = "Odpowiedzi ankiety powinny być krótkie i zwięzłe."; +$l['options'] = "Opcje:"; +$l['option_multiple'] = "Ankieta wielokrotnego wyboru: użytkownik będzie mógł wybrać wiele odpowiedzi."; +$l['option_multiple_maxoptions'] = "Maksymalna licza możliwych do wyboru odpowiedzi dla użytkownika (jeśli wpiszesz 0, liczba odpowiedzi pozostanie nielimitowana):"; +$l['option_public'] = "Ankieta publiczna: użytkownicy będą mogli wzajemnie poznać swoje odpowiedzi."; +$l['option_closed'] = "Ankieta zamknięta: użytkownicy nie będą mogli odpowiadać."; +$l['poll_timeout'] = "Data wygaśnięcia:"; +$l['timeout_note'] = "Liczba dni do zakończenia głosowania.
    Jeśli wpiszesz 0, ankieta nigdy nie wygaśnie."; +$l['days_after'] = "dni od"; +$l['update_poll'] = "Aktualizuj ankietę"; +$l['option'] = "Odpowiedź"; +$l['votes'] = "Głosów:"; +$l['post_new_poll'] = "Zapisz ankietę"; +$l['days'] = "dni"; +$l['poll_results'] = "Wyniki ankiety"; +$l['poll_total'] = "Razem:"; +$l['poll_votes'] = "głosów"; + +$l['redirect_pollposted'] = "Twoja ankieta została utworzona.
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_pollpostedmoderated'] = "Twoja ankieta została utworzona, jednak przed opublikowaniem musi być zweryfikowana przez moderatora.
    Teraz nastąpi przeniesienie na forum."; +$l['redirect_pollupdated'] = "Ankieta została zaktualizowana.
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_votethanks'] = "Dziękujemy za wypełnienie ankiety.
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_unvoted'] = "Twój głos w ankiecie został usunięty.
    Teraz nastąpi przeniesienie do wątku."; +$l['redirect_polldeleted'] = "Ankieta została usunięta z wątku.
    Teraz nastąpi przeniesienie do wątku."; + +$l['error_polloptiontoolong'] = "Jedna lub więcej odpowiedzi jest za długa. Wróć i skróć je."; +$l['error_noquestionoptions'] = "Musisz wprowadzić pytanie do ankiety lub więcej odpowiedzi. Minimalna liczba odpowiedzi to 2.
    Wróć i popraw ten błąd."; +$l['error_pollalready'] = "Ten wątek ma już ankietę!"; +$l['error_nopolloptions'] = "Wybrana odpowiedź ankiety jest nieprawidłowa lub nie istnieje."; +$l['error_maxpolloptions'] = "Wybrano zbyt dużo odpowiedzi w ankiecie. Maksymalna liczba odpowiedzi do wyboru to {1}.
    Wróć i spróbu ponownie."; +$l['error_alreadyvoted'] = "Wzięto już wcześniej udział w tej ankiecie."; +$l['error_notvoted'] = "W tej ankiecie nie brano udziału."; +$l['error_invalidpoll'] = "Wybrana ankieta nie istnieje lub jest nieprawidłowa."; +$l['error_pollclosed'] = "Ta ankieta jest już zakończona."; +$l['poll_time_limit'] = "Nie możesz dodać ankiety do swojego wątku. Administrator nałożył limit czasowy na dodawanie ankiet i można je dodawać tylko w ciągu pierwszych {1} godzin od zamieszczenia wątku."; + +$l['poll_deleted'] = "Usunięto ankietę"; +$l['poll_edited'] = "Wyedytowano ankietę"; diff --git a/Upload/inc/languages/polish/portal.lang.php b/Upload/inc/languages/polish/portal.lang.php new file mode 100644 index 0000000..5f39802 --- /dev/null +++ b/Upload/inc/languages/polish/portal.lang.php @@ -0,0 +1,53 @@ +{2} nieprzeczytanych wiadomości."; +$l['pms_unread'] = "Nieprzeczytane wiadomości"; +$l['pms_total'] = "Razem wiadomości"; +$l['search_forums'] = "Szukaj na forum"; +$l['advanced_search'] = "Zaawansowane szukanie"; +$l['forum_stats'] = "Statystyki"; +$l['num_members'] = "Użytkownicy:"; +$l['latest_member'] = "Najnowszy użytkownik:"; +$l['num_threads'] = "Wątków na forum:"; +$l['num_posts'] = "Postów na forum:"; +$l['full_stats'] = "Pełne statystyki"; +$l['welcome'] = "Witaj, {1}"; +$l['guest'] = "Gość"; +$l['guest_welcome_registration'] = "Musisz się zarejestrować przed napisaniem posta."; +$l['username'] = "Użytkownik"; +$l['password'] = "Hasło"; +$l['login'] = "Zaloguj!"; +$l['member_welcome_lastvisit'] = "Ostatnia wizyta:"; +$l['since_then'] = "Od Twojej ostatniej wizyty napisano:"; +$l['new_announcements'] = "{1} nowych ogłoszeń"; +$l['new_announcement'] = "1 nowe ogłoszenie"; +$l['new_threads'] = "{1} nowych wątków"; +$l['new_thread'] = "1 nowy wątek"; +$l['new_posts'] = "{1} nowych postów"; +$l['new_post'] = "1 nowy post"; +$l['view_new'] = "Pokaż nowe posty"; +$l['view_todays'] = "Pokaż dzisiejsze posty"; +$l['online'] = "Użytkownicy online"; +$l['online_user'] = "Aktualnie jest 1 użytkownik online."; +$l['online_users'] = "Aktualnie jest {1} użytkowników online."; +$l['online_counts'] = "{1} Użytkownik(ów) | {2} Gość(i)"; +$l['print_this_item'] = "Wydrukuj tę wiadomość"; +$l['send_to_friend'] = "Wyślij tę wiadomość znajomemu"; +$l['latest_announcements'] = "Ostatnie ogłoszenia"; +$l['portal_disabled'] = "Portal został wyłączony przez administratora."; \ No newline at end of file diff --git a/Upload/inc/languages/polish/printthread.lang.php b/Upload/inc/languages/polish/printthread.lang.php new file mode 100644 index 0000000..b2ee427 --- /dev/null +++ b/Upload/inc/languages/polish/printthread.lang.php @@ -0,0 +1,12 @@ +Uwaga: usuniętych wiadomości nie będzie można przywrócić."; +$l['num_messages'] = "Liczba wiadomości:"; +$l['empty_q'] = "Opróżnić?"; +$l['keep_unread'] = "Nie usuwaj nieprzeczytanych wiadomości"; +$l['pm_folders'] = "Foldery prywatnych wiadomości"; +$l['existing_folders'] = "Istniejące foldery"; +$l['edit_folder_note'] = "Tutaj możesz zmienić nazwy istniejących folderów. Aby usunąć folder, po prostu usuń jego nazwę. Podstawowych folderów nie można usunąć.
    Uwaga: Usuwając folder, usuwasz również wszystkie wiadomości znajdujące się w nim."; +$l['new_folders'] = "Nowe foldery"; +$l['add_folders_note'] = "Tutaj możesz utworzyć dodatkowe foldery. Nie musisz wypełniać wszystkich pól."; +$l['update_folders'] = "Aktualizuj foldery"; +$l['cannot_be_removed'] = "Nie można usunąć"; +$l['reached_warning'] = "Uwaga: przekroczono limit wiadomości."; +$l['reached_warning2'] = "Usuń stare prywatne wiadomości."; +$l['deny_receipt'] = "[nie powiadamiaj]"; +$l['viewing_pm'] = "Przegląda PW:"; +$l['reply'] = "Odpowiedz"; +$l['reply_to_all'] = "Odpowiedz na wszystkie"; +$l['forward'] = "Przekaż"; +$l['compose_pm'] = "Pisanie prywatnej wiadomości"; +$l['compose_to'] = "Odbiorcy:"; +$l['compose_bcc'] = "UDW:"; +$l['compose_bcc_show'] = "UDW"; +$l['compose_bcc_show_title'] = "Pokaż pole UDW pozwalające na dodanie odbiorców ukrytej kopii wiadomości."; +$l['separate_names'] = "Oddzielaj loginy przecinkami."; +$l['max_recipients'] = "
    Możesz wysłać jednorazowo wiadomość do maksymalnie {1} osób."; +$l['compose_subject'] = "Temat:"; +$l['compose_message'] = "Wiadomość:"; +$l['compose_options'] = "Opcje:"; +$l['message_icon'] = "Ikona wiadomości:"; +$l['options_sig'] = "Sygnatura: dołączona zostanie Twoja sygnatura."; +$l['options_disable_smilies'] = "Wyłącz emotikony: emotikony nie będą widoczne w tej wiadomości."; +$l['options_save_copy'] = "Zapisz kopię: wiadomość po wysłaniu zostanie zapisana w folderze Wysłane."; +$l['options_read_receipt'] = "Dostarcz potwierdzenie: otrzymasz je, gdy wiadomość zostanie przeczytana przez adresata."; +$l['send_message'] = "Wyślij wiadomość"; +$l['save_draft'] = "Zapisz jako szkic"; +$l['preview'] = "Podgląd"; +$l['select_buddy'] = "Lub wybierz znajomego:"; +$l['pm_tracking'] = "Śledzenie prywatnych wiadomości"; +$l['read_messages'] = "Przeczytane wiadomości"; +$l['unread_messages'] = "Nieprzeczytane wiadomości"; +$l['q'] = "?"; +$l['dateread'] = "Data przeczytania"; +$l['stop_tracking'] = "Zatrzymaj śledzenie"; +$l['datesent'] = "Data wysłania"; +$l['cancel'] = "Anuluj"; +$l['export_date_sent'] = "Data"; +$l['export_folder'] = "Folder"; +$l['export_subject'] = "Temat"; +$l['export_to'] = "Do"; +$l['export_from'] = "Od"; +$l['export_message'] = "Wiadomość"; +$l['not_sent'] = "(nie wysłano)"; +$l['at'] = "o"; +$l['nomessages'] = "W tym folderze nie ma wiadomości."; +$l['details'] = "Szczegóły"; +$l['message'] = "Wiadomość"; +$l['buddy_list'] = "Lista znajomych"; +$l['multiple_recipients'] = "Wielu odbiorców"; +$l['bcc'] = "UDW:"; +$l['reply_title'] = "Odpowiedz na tę prywatną wiadomość"; +$l['forward_title'] = "Prześlij tę prywatną wiadomość dalej"; +$l['delete_title'] = "Usuń tę prywatną wiadomość"; +$l['you_replied_on'] = "Odpowiedziano na tę wiadomość {1}"; +$l['you_forwarded_on'] = "Przesłano tę wiadomość dalej {1}"; +$l['you_replied'] = "Odpowiedziano na tę wiadomość {1}"; +$l['you_forwarded'] = "Przesłano tę wiadomość dalej {1}"; +$l['select_from_buddies'] = "Wybierz z listy znajomych"; +$l['no_readmessages'] = "Aktualnie nie ma żadnej przeczytanej śledzonej przez Ciebie wiadomości."; +$l['no_unreadmessages'] = "Aktualnie nie ma żadnej nieprzeczytanej śledzonej przez Ciebie wiadomości."; +$l['stop_tracking_all'] = "Przestań śledzić wszystkie wiadomości"; + +$l['enter_keywords'] = "Wpisz słowa kluczowe"; +$l['advanced_search'] = "Zaawansowane wyszukiwanie"; +$l['search_pms'] = "Szukaj"; +$l['advanced_private_message_search'] = "Zaawansowane wyszukiwanie prywatnych wiadomości"; +$l['search_criteria'] = "Kryteria wyszukiwania"; +$l['keywords'] = "Słowa kluczowe"; +$l['search_in_subject'] = "Wyszukaj w temacie"; +$l['search_in_message'] = "Wyszukaj w treści wiadomości"; +$l['message_status'] = "Status wiadomości"; +$l['message_status_new'] = "Nowa"; +$l['message_status_replied_to'] = "Odpowiedziano na wiadomość"; +$l['message_status_forwarded'] = "Przesłano dalej"; +$l['message_status_read'] = "Przeczytano"; +$l['folder'] = "Folder"; +$l['search_options'] = "Opcje wyszukiwania"; +$l['sort_by'] = "Sortuj według"; +$l['sort_by_subject'] = "tematu"; +$l['sort_by_sender'] = "nadawcy"; +$l['sort_by_date'] = "daty"; +$l['ascending_order'] = "w kolejności rosnącej"; +$l['descending_order'] = "w kolejności malejącej"; +$l['search_private_messages'] = "Szukaj w prywatnych wiadomościach"; +$l['check_all'] = "Zaznacz wszystkie"; +$l['search_user'] = "Szukaj użytkownika"; + +$l['error_nopmsarchive'] = "Nie znaleziono prywatnych wiadomości spełniających podane kryteria."; +$l['error_invalidpmfoldername'] = "Wprowadzona nazwa folderu zawiera niedozwolone znaki."; +$l['error_emptypmfoldername'] = "Wprowadzona nazwa folderu nie zawiera żadnego tekstu. Wpisz nazwę folderu, albo pozostaw ją zupełnie pustą by usunąć folder."; +$l['error_invalidpmrecipient'] = "Wprowadzony odbiorca nie jest prawidłowy. Wróć i popraw ten błąd."; +$l['error_invalidpm'] = "Nieprawidłowa PW"; +$l['error_pmrecipientreachedquota'] = "Nie możesz wysłać prywatnej wiadomości do {1}, gdyż ten użytkownik przekroczył limit miejsca na PW. Nie będzie mógł wysłać/odbierać żadnych wiadomości dopóki nie zostanie opróżniona jego skrzynka. Ten użytkownik został powiadomiony e-mailem o zaistniałej sytuacji. Spróbuj wysłać wiadomość później."; +$l['error_recipientpmturnedoff'] = "{1} wyłączył prywatne wiadomości lub nie ma uprawnień do używania ich. Nie możesz wysłać PW do tego użytkownika."; +$l['error_pmsturnedoff'] = "Prywatne wiadomości w ustawieniach profilu są wyłączone.
    Jeśli chcesz korzystać z systemu PW - musisz włączyć go z powrotem."; +$l['error_recipientignoring'] = "Nie możesz zobaczyć prywatnych wiadomości {1}. Nie masz uprawnień, aby przeprowadzić taką akcję."; +$l['error_pm_already_submitted'] = "Wysłano już identyczną PW do tego odbiorcy w ciągu ostatnich 5 minut"; +$l['error_nopms'] = "Aby skorzystać z tej funkcji musisz posiadać przynajmniej jedną prywatną wiadomość."; + +$l['error_minsearchlength'] = "Jedno lub więcej ze słów kluczowych było krótsze niż jego minimalna długość. Minimalna długość słowa kluczowego to {1} znaków.

    Jeżeli próbujesz wyszukać dokładną frazę, umieść ją w cudzysłowach. Na przykład \"Zażółć gęślą jaźń\"."; +$l['error_nosearchresults'] = "Wyszukiwanie z podanymi słowami kluczowymi nie zwróciło żadnych wyników. Zmień kryteria wyszukiwania i spróbuj ponownie."; +$l['error_no_search_support'] = "Ten silnik bazy danych nie obsługuje wyszukiwania."; +$l['error_nosearchterms'] = "Nie podano żadnych kryteriów wyszukiwania. Jako minimum należy wprowadzić kilka kryteriów wyszukiwania bądź nazwę użytkownika, który wysłał wiadomość."; +$l['error_searchflooding_1'] = "Nie możesz przeprowadzić kolejnego wyszukiwania, gdyż można przeprowadzać je co {1} sekund. Odczekaj 1 sekundę i spróbuj ponownie."; +$l['error_searchflooding'] = "Nie możesz przeprowadzić kolejnego wyszukiwania, gdyż można przeprowadzać je co {1} sekund. Odczekaj {2} sekund i spróbuj ponownie."; +$l['error_invalidsearch'] = "Wpisano nieprawidłowe kryterium. Wróć i spróbuj ponownie."; + +$l['redirect_pmsaved'] = "Prywatna wiadomość została zapisana w folderze Szkice."; +$l['redirect_pmstrackingstopped'] = "Śledzenie zaznaczonych PW zostało zatrzymane."; +$l['redirect_allpmstrackingstopped'] = "Śledzenie wszystkich PW zostało zatrzymane."; +$l['redirect_pmstrackingcanceled'] = "Zaznaczone nieprzeczytane PW zostały usunięte ze skrzynki odbiorczej."; +$l['redirect_pmsmoved'] = "Zaznaczone prywatne wiadomości zostały przeniesione."; +$l['redirect_pmsdeleted'] = "Zaznaczone prywatne wiadomości zostały usunięte."; +$l['redirect_pmsent'] = "Prywatna wiadomość została wysłana.
    Teraz nastąpi przeniesienie do skrzynki odbiorczej."; +$l['redirect_pmfoldersupdated'] = "Twoje foldery prywatnych wiadomości zostały zapisane.
    Teraz nastąpi przeniesienie do skrzynki odbiorczej."; +$l['redirect_pmfoldersemptied'] = "Zaznaczone foldery prywatnych wiadomości zostały opróżnione.
    Teraz nastąpi przeniesienie do skrzynki odbiorczej."; +$l['redirect_searchresults'] = "Wyszukiwanie zakończone. Teraz nastąpi przeniesienie do wyników wyszukiwania."; + +$l['quick_reply'] = "Szybka odpowiedź"; +$l['message_note'] = "Wprowadź tu swoją odpowiedź na tę wiadomość."; +$l['send_reply'] = "Odpowiedz"; +$l['quickreply_signature'] = "Sygnatura"; +$l['quickreply_disable_smilies'] = "Wyłącz uśmieszki"; +$l['quickreply_save_copy'] = "Zapisz kopię"; +$l['quickreply_read_receipt'] = "Zażądaj potwierdzenia przeczytania"; diff --git a/Upload/inc/languages/polish/ratethread.lang.php b/Upload/inc/languages/polish/ratethread.lang.php new file mode 100644 index 0000000..ed6e094 --- /dev/null +++ b/Upload/inc/languages/polish/ratethread.lang.php @@ -0,0 +1,21 @@ +Zostanie wkrótce sprawdzone przez któregoś z członków ekipy forum."; + +$l['error_report_length'] = "Wybierz powód zgłoszenia."; +$l['error_invalid_report'] = "Zawartość nie istnieje lub nie można jej zgłosić."; +$l['error_report_duplicate'] = "Ta zawartość została już zgłoszona przez innego użytkownika.
    Możesz wysłać kolejne zgłoszenie, korzystając z poniższego formularza."; +$l['report_reason_other_description'] = "Jeżeli wybrano opcję 'Inny powód', podaj powód zgłoszenia."; diff --git a/Upload/inc/languages/polish/reputation.lang.php b/Upload/inc/languages/polish/reputation.lang.php new file mode 100644 index 0000000..ae1dcdf --- /dev/null +++ b/Upload/inc/languages/polish/reputation.lang.php @@ -0,0 +1,82 @@ +"; +$l['neg_rep_disabled'] = "* - Przyznawanie ujemnych punktów reputacji zostało wyłączone"; +$l['pos_rep_disabled'] = "* - Przyznawanie dodatnich punktów reputacji zostało wyłączone"; +$l['neu_rep_disabled'] = "* - Przyznawanie neutralnych punktów reputacji zostało wyłączone"; +$l['no_comment_needed'] = "Wynagradzasz użytkownika punktem reputacji za konkretny post - link do tego posta będzie widoczny w jego profilu. Jeżeli chcesz oprócz tego dodać jakiś komentarz, wpisz go w polu poniżej.
    "; +$l['no_comment'] = "[brak komentarza]"; +$l['vote_added'] = "Punkt dodany"; +$l['vote_updated'] = "Punkt zaktualizowany"; +$l['vote_deleted'] = "Punkt usunięty"; +$l['vote_added_message'] = "Punkt reputacji został dodany."; +$l['vote_updated_message'] = "Punkt reputacji został zaktualizowany."; +$l['vote_deleted_message'] = "Punkt reputacji został usunięty."; +$l['update_reputation_vote'] = "Zaktualizuj swoją ocenę dla: {1}"; +$l['positive'] = "Pozytywny"; +$l['negative'] = "Negatywny"; +$l['neutral'] = "Neutralny"; +$l['user_comments'] = "Twoje komentarze dla {1}:"; +$l['add_vote'] = "Dodaj punkt"; +$l['update_vote'] = "Aktualizuj punkt"; +$l['delete_vote'] = "Usuń punkt"; +$l['report_vote'] = "Zgłoś punkt"; +$l['power_positive'] = "Pozytywny ({1})"; +$l['power_neutral'] = "Neutralny"; +$l['power_negative'] = "Negatywny ({1})"; +$l['show_all'] = "Pokaż wszystkie oceny"; +$l['show_positive'] = "Pokaż pozytywne oceny"; +$l['show_neutral'] = "Pokaż neutralne oceny"; +$l['show_negative'] = "Pokaż negatywne oceny"; +$l['sort_updated'] = "posortowane wg daty aktualizacji"; +$l['sort_username'] = "posortowane wg loginu"; +$l['last_updated'] = "Ostatnio zaktualizowano {1}"; +$l['postrep_given'] = "Punkt przyznany za post {3}
    "; +$l['postrep_given_thread'] = "w wątku {2}"; +$l['no_reputation_votes'] = "Ten użytkownik w tej chwili nie posiada ocen spełniających podane kryteria."; +$l['delete_reputation_confirm'] = "Czy na pewno chcesz usunąć ten punkt reputacji?"; +$l['delete_reputation_log'] = "Punkty reputacji usunięte przez {1} (UID {2})."; +$l['reputations_disabled_group'] = "System reputacji jest wyłączony dla użytkowników tej grupy."; +$l['rate_user'] = "Oceń użytkownika"; diff --git a/Upload/inc/languages/polish/search.lang.php b/Upload/inc/languages/polish/search.lang.php new file mode 100644 index 0000000..08af5c3 --- /dev/null +++ b/Upload/inc/languages/polish/search.lang.php @@ -0,0 +1,111 @@ +{1} wyników wyszukiwania zostało zaznaczonych na tej stronie."; +$l['all_selected'] = "Wszystkie {1} wyników wyszukiwania zostało zaznaczonych."; +$l['select_all'] = "Zaznacz wszystkie {1} wyniki wyszukiwania."; +$l['clear_selection'] = "Usuń zaznaczenie"; +$l['search_user'] = "Szukaj użytkownika"; + +$l['results'] = "wyniki"; +$l['mod_options'] = "Opcje moderatora"; +$l['display_all'] = "Pokaż wszystkie"; +$l['display_only_approved'] = "Pokaż tylko zaakceptowane"; +$l['display_only_unapproved'] = "Pokaż tylko ukryte"; +$l['display_only_softdeleted'] = "Pokaż tylko nietrwale usunięte"; + +$l['redirect_searchresults'] = "Teraz nastąpi przeniesienie do wyników wyszukiwania."; + +$l['error_minsearchlength'] = "Jedno lub więcej spośród słów kluczowych jest za krótkie. Minimalna długość słowa to {1} znaków.

    Jeśli próbujesz znaleźć jakąś frazę, obejmij ją cudzysłowami, np. \"ala ma kota\"."; +$l['error_nosearchresults'] = "Nic nie znaleziono."; +$l['error_no_search_support'] = "Obecnie używany silnik bazy danych nie wspiera wyszukiwania."; +$l['error_nosearchterms'] = "Nie wprowadzono żadnych zasad wyszukiwania. Musisz wprowadzić przynajmniej jedno kryterium wyszukiwania."; +$l['error_searchflooding_1'] = "Możesz wykonać tylko jedno wyszukiwanie w ciągu {1} sekund. Poczekaj jeszcze 1 sekundę przed następną próbą."; +$l['error_searchflooding'] = "Możesz wykonać tylko jedno wyszukiwanie w ciągu {1} sekund. Poczekaj {2} sekund przed następną próbą."; +$l['error_invalidsearch'] = "Błędne wyszukiwanie. Wróć i spróbuj ponownie."; diff --git a/Upload/inc/languages/polish/sendthread.lang.php b/Upload/inc/languages/polish/sendthread.lang.php new file mode 100644 index 0000000..2d60dbd --- /dev/null +++ b/Upload/inc/languages/polish/sendthread.lang.php @@ -0,0 +1,20 @@ +Uwaga: To jest publiczna ankieta, więc każdy może zobaczyć na co zagłosowano."; +$l['total'] = "Razem"; +$l['vote'] = "Zagłosuj"; +$l['total_votes'] = "{1} głosów"; +$l['you_voted'] = "*) odpowiedź wybrana przez Ciebie"; +$l['poll_closed'] = "Ankieta jest zamknięta."; +$l['poll_closes'] = "Ankieta zostanie zamknięta {1}"; +$l['already_voted'] = "Już głosowano w tej ankiecie."; +$l['undo_vote'] = "Cofnij głos"; +$l['quick_reply'] = "Szybka odpowiedź"; +$l['message_note'] = "Wpisz tutaj swoją odpowiedź."; +$l['signature'] = "Sygnatura"; +$l['email_notify'] = "Powiadomienie"; +$l['disable_smilies'] = "Wyłącz emotikony"; +$l['post_reply'] = "Odpowiedz"; +$l['post_reply_img'] = "Odpowiedz"; +$l['new_reply'] = "Nowa odpowiedź"; +$l['search_button'] = 'Szukaj'; +$l['post_thread'] = "Rozpocznij wątek"; +$l['preview_post'] = "Podgląd"; +$l['rating_average'] = "{1} głosów - średnia: {2}"; +$l['rate_thread'] = "Oceń ten wątek:"; +$l['thread_rating'] = "Ocena wątku:"; +$l['similar_threads'] = "Podobne wątki"; +$l['thread'] = "Wątek:"; +$l['replies'] = "Odpowiedzi:"; +$l['views'] = "Wyświetleń:"; +$l['lastpost'] = "Ostatni post"; +$l['messages_in_thread'] = "Wiadomości w tym wątku"; +$l['users_browsing_thread'] = "Użytkownicy przeglądający ten wątek:"; +$l['users_browsing_thread_guests'] = "{1} gości"; +$l['users_browsing_thread_invis'] = "{1} niewidocznych użytkowników"; +$l['users_browsing_thread_reading'] = "Czyta..."; +$l['inline_soft_delete_posts'] = "Nietrwale usuń posty"; +$l['inline_restore_posts'] = "Przywróć posty"; +$l['inline_delete_posts'] = "Trwale usuń posty"; +$l['inline_merge_posts'] = "Połącz posty"; +$l['inline_split_posts'] = "Oddziel posty"; +$l['inline_move_posts'] = "Przenieś posty"; +$l['inline_approve_posts'] = "Zatwierdź posty"; +$l['inline_unapprove_posts'] = "Ukryj posty"; +$l['inline_post_moderation'] = "Moderacja zbiorowa:"; +$l['inline_go'] = "OK"; +$l['clear'] = "Wyczyść"; +$l['thread_closed'] = "Wątek zamknięty"; +$l['no_subject'] = "Bez nazwy"; +$l['error_nonextnewest'] = "Nie ma wątków nowszych niż oglądany przed chwilą."; +$l['error_nonextoldest'] = "Nie ma wątków starszych niż oglądany przed chwilą."; +$l['quickreply_multiquote_selected'] = "Zaznaczono 1 lub więcej postów do zacytowania."; +$l['quickreply_multiquote_now'] = "Zacytuj te posty teraz"; +$l['or'] = "lub"; +$l['quickreply_multiquote_deselect'] = "odznacz je"; +$l['search_thread'] = "Przeszukaj wątek"; +$l['enter_keywords'] = "Wpisz słowa kluczowe"; +$l['image_verification'] = "Potwierdzenie kodem"; +$l['verification_note'] = "Przepisz tekst z obrazka po lewej do poniższego pola tekstowego. Taki proces jest niezbędny, by zapobiec wysyłaniu wiadomości przez automaty."; +$l['verification_subnote'] = "(wielkość znaków nie ma znaczenia)"; +$l['view_thread_notes'] = "Notatki do wątku"; +$l['view_all_notes'] = "Zobacz wszystkie notatki"; + +$l['save_changes'] = 'Zapisz zmiany'; +$l['cancel_edit'] = 'Anuluj edycję'; +$l['quick_edit_update_error'] = 'Podczas edytowania odpowiedzi wystąpił błąd:'; +$l['quick_reply_post_error'] = 'Podczas dodawania odpowiedzi wystąpił błąd:'; +$l['quick_delete_error'] = 'Podczas usuwania odpowiedzi wystąpił błąd:'; +$l['quick_delete_success'] = 'Post został usunięty.'; +$l['quick_delete_thread_success'] = 'Wątek został usunięty.'; +$l['quick_restore_error'] = 'Podczas przywracania odpowiedzi wystąpił błąd:'; +$l['quick_restore_success'] = 'Post został przywrócony.'; diff --git a/Upload/inc/languages/polish/stats.lang.php b/Upload/inc/languages/polish/stats.lang.php new file mode 100644 index 0000000..0d5649b --- /dev/null +++ b/Upload/inc/languages/polish/stats.lang.php @@ -0,0 +1,37 @@ +{1} ({2} postów)"; +$l['popular_forum'] = "Najpopularniejszy dział: {1} ({2} postów, {3} wątków)"; +$l['most_popular'] = "Najpopularniejsze wątki"; +$l['most_replied_threads'] = "Najwięcej odpowiedzi"; +$l['most_viewed_threads'] = "Najwięcej wyświetleń"; +$l['not_enough_info_stats'] = "Aby można było wygenerować statystyki, potrzebny jest przynajmniej jeden użytkownik i jeden wątek."; +$l['replies'] = "odpowiedzi"; +$l['views'] = "wyświetleń"; +$l['top_referrer'] = "Najwięcej poleconych użytkowników: {1} ({2})"; diff --git a/Upload/inc/languages/polish/syndication.lang.php b/Upload/inc/languages/polish/syndication.lang.php new file mode 100644 index 0000000..a2f4039 --- /dev/null +++ b/Upload/inc/languages/polish/syndication.lang.php @@ -0,0 +1,13 @@ +Strona główna zawiera informacje o Tobie."; +$l['account_summary'] = "Podsumowanie konta"; +$l['username'] = "Użytkownik:"; +$l['user_id'] = "ID użytkownika:"; +$l['title'] = "Tytuł:"; +$l['postnum'] = "Postów:"; +$l['posts_day'] = "({1} dziennie | {2} procent wszystkich postów)"; +$l['additional_contact_details'] = "Dodatkowe informacje kontaktowe"; +$l['email'] = "E-mail:"; +$l['reputation'] = "Reputacja:"; +$l['website'] = "Strona WWW:"; +$l['usergroup'] = "Grupa"; +$l['birthday'] = "Data urodzenia:"; +$l['birthdayprivacy'] = "Poufność daty urodzenia:"; +$l['birthdayprivacyall'] = "Wyświetl wiek i datę urodzenia"; +$l['birthdayprivacynone'] = "Ukryj wiek i datę urodzenia"; +$l['birthdayprivacyage'] = "Wyświetl tylko wiek"; +$l['avatar'] = "Awatar:"; +$l['avatar_mine'] = "To jest Twój aktualny awatar"; +$l['change_avatar'] = "Zmień awatar"; +$l['avatar_url'] = "Link do awatara:"; +$l['avatar_url_note'] = "Wprowadź URL awatara."; +$l['avatar_url_gravatar'] = "Aby skorzystać z Gravatara, wprowadź tu adres e-mail, jakiego używasz w tym serwisie."; +$l['avatar_upload'] = "Awatar z dysku:"; +$l['avatar_upload_note'] = "Wybierz awatar ze swojego komputera."; +$l['no_avatar'] = "Brak awatara"; +$l['no_avatar_note'] = "Zaznacz tę opcję, jeśli nie chcesz używać awatara."; +$l['change_username'] = "Zmień login"; +$l['new_username'] = "Nowy login:"; +$l['update_username'] = "Aktualizuj login"; +$l['edit_lists'] = "Edytuj listę znajomych i ignorowanych"; +$l['edit_buddy_list'] = "Edytuj listę znajomych"; +$l['edit_ignore_list'] = "Edytuj listę ignorowanych"; +$l['users_added_to_ignore_list'] = "Wybrani użytkownicy zostali dodani do listy ignorowanych"; +$l['users_added_to_buddy_list'] = "Wybrani użytkownicy zostali dodani do listy znajomych"; +$l['removed_from_ignore_list'] = "Usunięto użytkownika {1} z listy ignorowanych"; +$l['removed_from_buddy_list'] = "Usunięto użytkownika {1} z listy znajomych"; +$l['cant_add_self_to_ignore_list'] = "Nie możesz dodać siebie do swojej listy ignorowanych."; +$l['cant_add_self_to_buddy_list'] = "Nie możesz dodać siebie do swojej listy znajomych."; +$l['users_already_on_ignore_list'] = "Nie można dodawać wielokrotnie tego samego użytkownika na listę ignorowanych."; +$l['users_already_on_ignore_list_alt'] = "Nie można dodawać do listy ignorowanych użytkowników, którzy znajdują się na liście znajomych."; +$l['users_already_on_buddy_list'] = "Nie można dodawać wielokrotnie tego samego użytkownika na listę znajomych."; +$l['users_already_on_buddy_list_alt'] = "Nie można dodawać do listy znajomych użytkowników, którzy znajdują się na liście ignorowanych."; +$l['invalid_user_selected'] = "Jeden lub więcej wybranych użytkowników nie zostało znalezionych."; +$l['ignore_list_empty'] = "Lista ignorowanych jest pusta. By dodać do niej kogoś, użyj pola powyżej."; +$l['buddy_list_empty'] = "Lista znajomych jest pusta. By dodać do niej kogoś, użyj pola powyżej."; +$l['confirm_remove_buddy'] = "Usunąć tego użytkownika z listy znajomych?"; +$l['confirm_remove_ignored'] = "Usunąć tego użytkownika z listy ignorowanych?"; +$l['adding_buddy'] = "Dodawanie znajomego..."; +$l['adding_ignored'] = "Dodawanie do ignorowanych..."; +$l['add_buddies'] = "Dodaj użytkowników do swojej listy znajomych"; +$l['add_buddies_desc'] = "By dodać użytkowników do swojej listy znajomych, wpisz ich loginy w polu poniżej. Możesz wpisać kilka loginów, oddzielając je przecinkami."; +$l['username_or_usernames'] = "Użytkownicy:"; +$l['add_to_buddies'] = "Dodaj znajomych"; +$l['current_buddies'] = "Masz w tej chwili {1} użytkowników na liście znajomych"; +$l['add_ignored_users'] = "Dodaj użytkowników do swojej listy ignorowanych"; +$l['add_ignored_users_desc'] = "By zacząć ignorować posty i prywatne wiadomości od wybranych użytkowników, wpisz ich loginy w polu poniżej. Możesz wpisać kilka loginów naraz, oddzielając je przecinkami."; +$l['ignore_users'] = "Ignoruj"; +$l['current_ignored_users'] = "Masz w tej chwili {1} użytkowników na liście ignorowanych"; +$l['online'] = "Online"; +$l['offline'] = "Offline"; +$l['remove_from_list'] = "Usuń z listy"; +$l['edit_sig'] = "Edytuj sygnaturę"; +$l['edit_sig_note'] = "Możesz tutaj wprowadzić krótką wiadomość, która będzie widoczna pod Twoimi postami."; +$l['edit_sig_note2'] = "Emotikony są {1}.
    MyCode jest {2}.
    [img] sÄ… {3}.
    HTML jest {4}.
    Limit znaków wynosi {5}."; +$l['edit_sig_error_title'] = "Wystąpił błąd:"; +$l['edit_sig_no_permission'] = "Nie masz uprawnień do edytowania swojej sygnatury."; +$l['characters_remaining'] = "znaków pozostało"; +$l['enable_sig_posts'] = "Włącz moją sygnaturę we wszystkich moich istniejących postach."; +$l['disable_sig_posts'] = "Wyłącz moją sygnaturę we wszystkich moich istniejących postach."; +$l['leave_sig_settings'] = "Bez zmian."; +$l['update_sig'] = "Aktualizuj sygnaturę"; +$l['preview'] = "Podgląd"; +$l['current_sig'] = "Aktualna sygnatura"; +$l['sig_preview'] = "Podgląd"; + +$l['sig_suspended'] = "Możliwość posiadania przez Ciebie sygnatury została wyłączona."; +$l['sig_suspended_posts'] = "Musisz napisać co najmniej {1} postów, zanim będzie można dodać sygnaturę."; + +$l['change_email'] = "Zmień e-mail"; +$l['please_enter_confirm_new_email'] = "Wprowadź i potwierdź swój nowy e-mail"; +$l['new_email'] = "Nowy adres e-mail:"; +$l['confirm_email'] = "Potwierdź adres e-mail:"; +$l['update_email'] = "Aktualizuj e-mail"; +$l['thread'] = "Wątek"; +$l['author'] = "Autor"; +$l['replies'] = "Odpowiedzi"; +$l['views'] = "Wyświetleń"; +$l['lastpost'] = "Ostatni post"; +$l['post_reply'] = "Odpowiedz"; +$l['forum_subscriptions'] = "Subskrypcje działów"; +$l['posts'] = "Postów"; +$l['forum'] = "Dział"; +$l['threads'] = "Wątków"; +$l['unsubscribe'] = "Anuluj subskrybcję"; +$l['new_thread'] = "Nowy wątek"; +$l['personal_notepad'] = "Osobisty notatnik"; +$l['update_notepad'] = "Aktualizuj"; +$l['edit_options'] = "Edytuj opcje"; +$l['login_cookies_privacy'] = "Prywatność"; +$l['invisible_mode'] = "Nie pokazuj mnie na liście osób online."; +$l['invisible_mode_desc'] = "Zaznaczając \"tak\" Twój login nie będzie widoczny na liście osób online."; +$l['messaging_notification'] = "Wiadomości i powiadomienia"; +$l['allow_notices'] = "Dostarczaj wiadomości od administratorów."; +$l['allow_notices_desc'] = "Jeśli zaznaczysz \"tak\", na Twój e-mail będą wysyłane informacje i wiadomości od administratora."; +$l['allow_emails'] = "Ukryj swój adres e-mail."; +$l['allow_emails_desc'] = "Jeśli zaznaczysz \"tak\", użytkownicy będą mogli wysłać do Ciebie e-maila tylko przez formularz."; +$l['email_notify'] = "Automatycznie subskrybuj wątki w których się wypowiadam."; +$l['email_notify_desc'] = "Jeśli zaznaczysz \"tak\", wątki w których odpowiesz będą automatycznie dodawane do listy subskrybowanych."; +$l['receive_pms'] = "Dostarczaj prywatne wiadomości od innych użytkowników."; +$l['receive_pms_desc'] = "Włącza możliwość odbierania i wysyłania prywatnych wiadomości."; +$l['receive_from_buddy'] = "Dostarczaj prywatne wiadomości tylko od użytkowników z mojej listy znajomych."; +$l['pm_notice'] = "Powiadom mnie, gdy otrzymam nową prywatną wiadomość."; +$l['pm_notify'] = "Powiadom mnie e-mailem kiedy dostanę nową prywatną wiadomość."; +$l['show_codebuttons'] = "Pokaż opcje formatowania MyCode w czasie pisania postów."; +$l['source_editor'] = "Zmień domyślny tryb edytora na pokazywanie kodu"; +$l['show_redirect'] = "Pokaż strony przekierowujące."; +$l['thread_view_options'] = "Opcje wyświetlania wątków"; +$l['thread_mode'] = "Tryb wyświetlania wątków:"; +$l['thread_mode_desc'] = "Styl wyświetlania wątków. Wybierz \"Użyj domyślnego\" jeśli chcesz przeglądać w trybie domyślnym."; +$l['use_default'] = "Użyj domyślnego"; +$l['threaded'] = "Drzewo"; +$l['linear'] = "Standardowy"; +$l['show_classic_postbit'] = "Wyświetlaj posty w trybie klasycznym."; +$l['show_images'] = "Wyświetlaj obrazki w postach."; +$l['show_videos'] = "Wyświetaj pliki wideo w postach."; +$l['show_sigs'] = "Pokazuj sygnatury użytkowników pod ich postami."; +$l['show_sigs_desc'] = "Czy chcesz widzieć sygnatury innych użytkowników?"; +$l['show_avatars'] = "Pokazuj awatary użytkowników przy ich postach."; +$l['show_avatars_desc'] = "Czy chcesz widzieć awatary innych użytkowników?"; +$l['show_quick_reply'] = "Pokazuj okienko szybkiej odpowiedzi."; +$l['show_quick_reply_desc'] = "Okienko szybkiej odpowiedzi pozwala na szybką odpowiedź w wątku. Będzie wyświetlane u dołu strony z wątkiem."; +$l['forum_display_options'] = "Opcje wyświetlania działów"; +$l['thread_view'] = "Ilość wyświetlanych wątków:"; +$l['thread_view_lastday'] = "Pokaż wątki z ostatniego dnia"; +$l['thread_view_5days'] = "Pokaż wątki z ostatnich 5 dni"; +$l['thread_view_10days'] = "Pokaż wątki z ostatnich 10 dni"; +$l['thread_view_20days'] = "Pokaż wątki z ostatnich 20 dni"; +$l['thread_view_50days'] = "Pokaż wątki z ostatnich 50 dni"; +$l['thread_view_75days'] = "Pokaż wątki z ostatnich 75 dni"; +$l['thread_view_100days'] = "Pokaż wątki z ostatnich 100 dni"; +$l['thread_view_year'] = "Pokaż wątki z ostatniego roku"; +$l['thread_view_all'] = "Pokaż wszystkie wątki"; +$l['date_time_options'] = "Opcje daty i czasu"; +$l['date_format'] = "Format daty:"; +$l['date_format_desc'] = "Format, w którym będą pokazywane daty."; +$l['time_format'] = "Format czasu:"; +$l['time_format_desc'] = "Format, w którym będzie pokazywany czas."; +$l['time_offset'] = "Strefa czasowa (czas zimowy):"; +$l['time_offset_desc'] = "Jeżeli mieszkasz w innej strefie czasowej niż domyślna dla tego forum, możesz ją wybrać z listy poniżej."; +$l['gmt'] = "UTC"; +$l['dst_correction'] = "Ustawienia czasu letniego:"; +$l['dst_correction_auto'] = "Automatycznie wykryj czas letni"; +$l['dst_correction_enabled'] = "Zawsze używaj czasu letniego"; +$l['dst_correction_disabled'] = "Nigdy nie używaj czasu letniego"; +$l['board_language'] = "Język forum"; +$l['other_options'] = "Inne opcje"; +$l['style'] = "Styl forum:"; +$l['style_desc'] = "Jeśli nie podoba Ci się domyślny styl forum - tutaj możesz wybrać inny."; +$l['update_options'] = "Aktualizuj opcje"; +$l['tpp_option'] = "Pokaż {1} wątków na stronę"; +$l['ppp_option'] = "Pokaż {1} postów na stronę"; +$l['ppp'] = "Ilość postów na stronę:"; +$l['ppp_desc'] = "Pozwala na wybranie liczby postów wyświetlanych na jedną stronę wątku."; +$l['tpp'] = "Ilość wątków na stronę:"; +$l['tpp_desc'] = "Pozwala na wybranie liczby wątków wyświetlanych na jedną stronę działu."; +$l['change_password'] = "Zmień hasło"; +$l['current_password'] = "Obecne hasło"; +$l['password_confirmation'] = "Potwierdź hasło"; +$l['please_enter_confirm_new_password'] = "Wprowadź i potwierdź nowe hasło"; +$l['new_password'] = "Nowe hasło:"; +$l['confirm_password'] = "Potwierdź hasło:"; +$l['update_password'] = "Aktualizuj hasło"; +$l['edit_profile'] = "Edytuj profil"; +$l['profile_required'] = "Wymagane pola"; +$l['change_email_notice'] = "Aby zmienić adres e-mail, kliknij tutaj."; +$l['profile_optional'] = "Niewymagane pola"; +$l['website_url'] = "Strona domowa:"; +$l['birthdate'] = "Urodziny:"; +$l['contact_field_icq'] = "Numer ICQ:"; +$l['contact_field_aim'] = "Nazwa użytkownika AIM:"; +$l['contact_field_yahoo'] = "Identyfikator Yahoo:"; +$l['contact_field_skype'] = "Identyfikator Skype:"; +$l['contact_field_google'] = "Identyfikator Google Talk:"; +$l['additional_information'] = "Dodatkowe informacje"; +$l['update_profile'] = "Aktualizuj profil"; +$l['away_information'] = "Dostępność"; +$l['away_status'] = "Status:"; +$l['away_status_desc'] = "Pozwala na wpisanie wiadomości informującej o nieobecności."; +$l['im_away'] = "Niedostępny"; +$l['im_here'] = "Dostępny"; +$l['away_reason'] = "Powód nieobecności:"; +$l['away_reason_desc'] = "Pozwala Ci na wpisanie krótkiego powodu nieobecności (maksymalnie 200 znaków)."; +$l['return_date'] = "Data powrotu:"; +$l['return_date_desc'] = "Wpisz tu datę powrotu, o ile ją znasz."; +$l['subscriptions'] = "Subskrypcje wątków"; +$l['remove_all_subscriptions'] = "Usuń wszystkie subskrypcje"; +$l['no_thread_subscriptions'] = "Aktualnie nie subskrybujesz żadnych wątków.

    Aby zacząć subskrybować wątek:

    1. Otwórz wątek który chcesz subskrybować.
    2. Kliknij na link \"Subskrybuj ten wątek\" znajdujący się na końcu strony.
    "; +$l['no_forum_subscriptions'] = "Aktualnie nie subskrybujesz żadnych działów.

    Aby zacząć subskrybować dział:

    1. Otwórz dział który chcesz subskrybować.
    2. Kliknij na link \"Subskrybuj ten dział\" znajdujący się na końcu strony.
    "; +$l['no_drafts'] = "Aktualnie nie masz żadnych szkiców.

    Aby zapisać szkic posta lub wątku:

    1. Przejdź do strony pisania posta (napisz nowy wątek lub odpowiedz na istniejący).
    2. Napisz swoją wypowiedź.
    3. Kliknij na przycisk \"Zapisz jako szkic\".
    "; +$l['drafts'] = "Zapisane szkice"; +$l['drafts_count'] = "Zapisane szkice ({1})"; +$l['draft_saved'] = "Zapisane"; +$l['edit_draft'] = "Edytuj szkic"; +$l['draft_title'] = "Tytuł szkicu"; +$l['delete_drafts'] = "Usuń zaznaczone szkice"; +$l['draft_options'] = "Opcje szkicu"; +$l['selected_drafts_deleted'] = "Zaznaczone szkice zostały usunięte.
    Teraz nastąpi przeniesienie do listy szkiców."; +$l['no_drafts_selected'] = "Nie zaznaczono żadnych szkiców do usunięcia"; +$l['too_many_sig_images'] = "Nie możemy przyjąć nowej sygnatury, gdyż zawiera zbyt dużo obrazków. Usuń zbędne obrazki i spróbuj ponownie."; +$l['too_many_sig_images2'] = "Uwaga: Maksymalna liczba obrazków na sygnaturę to {1}."; +$l['sig_too_long'] = "Nie możesz zaktualizować sygnatury, gdyż jest za długa. Maksymalny rozmiar sygnatury to {1} znaków. "; +$l['sig_remove_chars_plural'] = "Skróć ją o {1} znaków i spróbuj ponownie."; +$l['sig_remove_chars_singular'] = "Skróć ją o 1 znak i spróbuj ponownie."; +$l['group_memberships'] = "Członkostwo"; +$l['not_member_of_group'] = "Nie możesz wykonać tej akcji, gdyż nie jesteś użytkownikiem tej grupy."; +$l['cannot_set_displaygroup'] = "Ta grupa nie może zostać ustawiona jako domyślna."; +$l['display_group_changed'] = "Wyświetlana grupa została zaktualizowana.
    Teraz nastąpi przeniesienie do strony zarządzania grupami."; +$l['usergroups_memberof'] = "Aktualnie jesteś członkiem grup:"; +$l['usertitle'] = "Tytuł"; +$l['usergroup_leave'] = "Opuść grupę"; +$l['usergroup_leave_primary'] = "(nie możesz opuścić głównej grupy)"; +$l['usergroup_leave_leader'] = "(jesteś liderem tej grupy)"; +$l['usergroup_joins_moderated'] = "Lider grupy rozpatruje prośby o przyjęcie."; +$l['usergroup_joins_invite'] = "Aby móc dołączyć do tej grupy, musisz najpierw otrzymać zaproszenie od jej lidera."; +$l['usergroup_cannot_leave'] = "(nie możesz opuścić tej grupy)"; +$l['usergroup_joins_anyone'] = "Każdy może dołączyć do tej grupy."; +$l['usergroup_leaders'] = "Liderzy grupy:"; +$l['usergroups_joinable'] = "Grupy, do których możesz dołączyć"; +$l['join_conditions'] = "Warunki dołączenia"; +$l['join_group'] = "Dołącz do grupy"; +$l['join_group_applied'] = "Poproszono o członkostwo w grupie: {1}"; +$l['pending_invitation'] = "Otrzymano zaproszenie do grupy: Zaakceptuj zaproszenie"; +$l['usergroups_leader'] = "Grupy, którym przewodniczysz"; +$l['usergroup_members'] = "Użytkownicy grupy"; +$l['join_requests'] = "Nierozpatrzone prośby o przyjęcie"; +$l['request_join_usergroup'] = "Poproś o członkostwo w tej grupie"; +$l['join_group_moderate_note'] = "Wszystkie prośby o członkostwo w tej grupie muszą zostać zatwierdzone przez lidera grupy."; +$l['user_group'] = "Grupa:"; +$l['usergroups_usergroup'] = "Grupa użytkownika"; +$l['join_reason'] = "Powód:"; +$l['send_join_request'] = "Wyślij prośbę"; +$l['cannot_join_group'] = "Nie możesz dołączyć do tej grupy, gdyż nie jest ona publiczną grupą."; +$l['cannot_join_invite_group'] = "Do dołączenia do tej grupy wymagane jest otrzymanie zaproszenia od jej lidera."; +$l['no_pending_invitation'] = "Nie masz żadnych oczekujących zaproszeń do tej grupy."; +$l['already_accepted_invite'] = "Zaproszenie do tej grupy zostało już zaakceptowane."; +$l['already_member_of_group'] = "Nie możesz dołączyć do grupy, w której już jesteś."; +$l['already_sent_join_request'] = "Już wcześniej wysłano prośbę o przyjęcie."; +$l['group_join_requestsent'] = "Prośba o przyjęcie została wysłana. Gdy zostanie zatwierdzona, automatycznie zostaniesz członkiem tej grupy.
    Nastąpi teraz przeniesienie do zarządzania grupami."; +$l['joined_group'] = "Dołączono Cię do tej grupy.
    Nastąpi teraz przeniesienie do zarządzania grupami."; +$l['cannot_leave_primary_group'] = "Nie możesz opuścić głównej grupy."; +$l['left_group'] = "Usunięto Cię z grupy.
    Nastąpi teraz przeniesienie do zarządzania grupami."; +$l['avatar_note'] = "Awatar to mały obrazek widoczny przy każdej wypowiedzi użytkownika."; +$l['avatar_note_dimensions'] = "Maksymalne wymiary awatara to {1}x{2} pikseli."; +$l['avatar_note_size'] = "Maksymalny rozmiar awatara to {1}."; +$l['custom_avatar'] = "Własny awatar"; +$l['remove_avatar'] = "Usuń awatar"; +$l['attachments_manager'] = "Menadżer załączników"; +$l['attachments_attachment'] = "Załącznik"; +$l['attachments_post'] = "Dodaj"; +$l['delete_attachments'] = "Usuń zaznaczone załączniki"; +$l['attachment_size_downloads'] = "({1}, {2} pobrań)"; +$l['attachment_thread'] = "wątek:"; +$l['no_attachments'] = "Aktualnie nie posiadasz żadnych załączników."; +$l['date_uploaded'] = "Dodano"; +$l['no_attachments_selected'] = "Nie zaznaczono żadnych załączników do usunięcia."; +$l['attachments_deleted'] = "Zaznaczone załączniki zostały usunięte.
    Teraz nastąpi przeniesienie do menadżera załączników."; +$l['attachments_usage_quota'] = "- Używasz {1} z {2} ({3}) z {4} załączników"; +$l['attachments_usage'] = "- {1} z {2} załączników"; +$l['attachments_stats'] = "Statystyki załączników"; +$l['attachstats_attachs'] = "Liczba załączników"; +$l['attachstats_spaceused'] = "Użyta przestrzeń"; +$l['attachstats_quota'] = "Miejsce do wykorzystania"; +$l['attachstats_totaldl'] = "Razem pobrań"; +$l['attachstats_bandwidth'] = "Użycie transferu"; +$l['error_avatartoobig'] = "Awatar jest zbyt duży. Maksymalne wymiary to {1}x{2}."; +$l['error_invalidavatarurl'] = "Link do awatara nie jest prawidłowy. Wprowadź prawidłowy link."; +$l['custom_usertitle'] = "Tytuł użytkownika"; +$l['new_custom_usertitle'] = "Nowy tytuł użytkownika (zostaw puste, aby użyć już istniejącego):"; +$l['custom_usertitle_note'] = "Tutaj możesz przypisać dowolny tytuł użytkownika. Zastąpi on nazwę grupy."; +$l['default_usertitle'] = "Domyślny tytuł użytkownika:"; +$l['current_custom_usertitle'] = "Aktualny tytuł użytkownika:"; +$l['revert_usertitle'] = "Przywróć domyślny tytuł użytkownika"; +$l['primary_usergroup'] = "Główna grupa użytkownika:"; +$l['display_group'] = "Grupa wyświetlana"; +$l['set_as_display_group'] = "Ustaw jako wyświetlaną grupę"; +$l['registration_date'] = "Data rejestracji:"; +$l['view_members'] = "Pokaż użytkowników"; +$l['view_requests'] = "Prośby o przyjęcie"; +$l['cannot_leave_group'] = "Nie możesz opuścić tej grupy, gdyż to nie jest publiczna grupa."; +$l['details'] = "Szczegóły"; +$l['members_referred'] = "Poleconych użytkowników:"; +$l['referral_link'] = "
    Aby polecić to forum swoim znajomym, wyślij do nich odnośnik: {1}/member.php?action=register&referrer={2}"; +$l['redirect_subscriptionsremoved'] = "Lista subskrybowanych wątków została wyczyszczona. Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_forumsubscriptionsremoved'] = "Lista subskrybowanych działów została wyczyszczona. Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_subscriptionadded'] = "Wskazany wątek został dodany do listy subskrybowanych. Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_optionsupdated'] = "Twój profil został zaktualizowany."; +$l['redirect_subscriptionremoved'] = "Wskazany wątek został usunięty z listy subskrybowanych."; +$l['redirect_sigupdated'] = "Sygnatura została zaktualizowana.
    Teraz nastąpi przeniesienie do strony edycji sygnatury."; +$l['redirect_notepadupdated'] = "Twój osobisty notatnik został zaktualizowany.
    Teraz nastąpi przeniesienie do panelu użytkownika."; +$l['redirect_profileupdated'] = "Twój profil został zaktualizowany.
    Teraz nastąpi przeniesienie do panelu użytkownika."; +$l['redirect_forumsubscriptionadded'] = "Wskazany dział został dodany do listy subskrybowanych.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_forumsubscriptionremoved'] = "Wskazany dział został usunięty z listy subskrybowanych.
    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['redirect_namechanged'] = "Twój login został zaktualizowany.
    Teraz nastąpi przeniesienie do panelu użytkownika."; +$l['redirect_emailupdated'] = "Twój adres e-mail został zaktualizowany.
    Teraz nastąpi przeniesienie do panelu użytkownika."; +$l['redirect_passwordupdated'] = "Hasło zostało zaktualizowane.
    Teraz nastąpi przeniesienie do panelu użytkownika."; +$l['redirect_changeemail_activation'] = "Twój adres e-mail został zaktualizowany. Musisz jeszcze potwierdzić zmianę.

    E-mail z dalszymi informacjami został wysłany na podany przez Ciebie adres.

    "; +$l['redirect_avatarupdated'] = "Twój awatar został zaktualizowany.
    Teraz nastąpi przeniesienie do panelu użytkownika."; +$l['error_noavatar'] = "Musisz wybrać awatar. Wróć i wybierz go. Jeśli nie chcesz mieć awatara, wybierz opcję \"Brak awatara\"."; +$l['error_avatartype'] = "Nieprawidłowy typ pliku. Awatar musi być w formacie GIF, JPEG lub PNG."; +$l['error_alreadyingroup'] = "Wskazany użytkownik jest już w jakiejś grupie."; +$l['error_usercp_return_date_past'] = "Nie możesz wrócić w przeszłości!"; +$l['error_avatarresizefailed'] = "Nie udało się zmienić rozmiarów awatara tak, by spełniał wymagania ustalone przez administratora."; +$l['error_avataruserresize'] = "Możesz spróbować zaznaczyć pole \"spróbuj zmienić rozmiar mojego awatara\" i wysłać ten sam obrazek jeszcze raz."; +$l['avatar_auto_resize_note'] = "Jeżeli Twój awatar jest zbyt duży, zostanie automatycznie przeskalowany do wymaganych rozmiarów."; +$l['avatar_auto_resize_option'] = "Zmniejsz rozmiary awatara, jeżeli będą za duże."; +$l['subscribe_to_thread'] = "Subskrybuj wątek: {1}"; +$l['notification_method'] = "Metoda powiadamiania:"; +$l['no_notification'] = "Bez powiadamiania"; +$l['no_notification_desc'] = "Nie otrzymasz powiadomienia, gdy ktoś odpowie w wątku."; +$l['email_notification'] = "Powiadamianie e-mail"; +$l['email_notification_desc'] = "Będą wysyłane do Ciebie wiadomości e-mail, gdy ktoś odpowie w wątku."; +$l['pm_notification'] = "Powiadamianie przez PW"; +$l['pm_notification_desc'] = "Będą wysyłane do Ciebie prywatne wiadomości, gdy ktoś odpowie w wątku."; +$l['do_subscribe'] = "Subskrybuj wątek"; +$l['subscription_method'] = "Domyślny sposób subskrypcji wątku:"; +$l['no_auto_subscribe'] = "Nie subskrybuj"; +$l['no_subscribe'] = "Bez powiadamiania"; +$l['instant_email_subscribe'] = "Powiadomienie e-mail"; +$l['instant_pm_subscribe'] = "Powiadamianie przez PW"; +$l['with_selected'] = "Zaznaczone:"; +$l['delete_subscriptions'] = "Anuluj subskrypcję"; +$l['update_no_notification'] = "przestań powiadamiać e-mailem"; +$l['update_email_notification'] = "zacznij powiadamiać e-mailem"; +$l['update_pm_notification'] = "zacznij powiadamiać przez PW"; +$l['no_subscriptions_selected'] = "Nie wybrano subskrypcji na jakich ma być przeprowadzona ta czynność."; +$l['redirect_subscriptions_updated'] = "Wybrane subskrypcje zostały zmodyfikowane."; +$l['latest_threads'] = "Twoje najnowsze wątki"; +$l['find_all_threads'] = "Znajdź wszystkie moje wątki"; +$l['new_thread_subscriptions'] = "Subskrypcje wątków z nowymi odpowiedziami"; +$l['view_all_subscriptions'] = "Pokaż wszystkie subskrypcje"; +$l['latest_warnings'] = "Ostatnio otrzymane ostrzeżenia"; +$l['current_warning_level'] = "Aktualny poziom ostrzeżeń: {1}% ({2}/{3})"; +$l['warning'] = "Ostrzeżenie"; +$l['date_issued'] = "Data wystawienia"; +$l['expiry_date'] = "Data przedawnienia"; +$l['issued_by'] = "Wystawione przez"; +$l['warning_for_post'] = "za post: "; +$l['warning_revoked'] = "Zniesione"; +$l['already_expired'] = "Przedawnione"; +$l['warning_points'] = "({1} punktów)"; +$l['new_posts_thread'] = "Nowe posty"; +$l['new_hot_thread'] = "Popularny wątek (nowe)"; +$l['posts_by_you'] = "Zawiera Twoje posty"; +$l['no_new_thread'] = "Brak nowych postów"; +$l['hot_thread'] = "Popularny wątek (brak nowych)"; +$l['locked_thread'] = "Zamknięty wątek"; +$l['icon_dot'] = "Zawiera posty napisane przez Ciebie. "; // The spaces for the icon labels are strategically placed so that there should be no extra space at the beginning or end of the resulting label and that spaces separate each 'status' ;) +$l['icon_no_new'] = "Brak nowych postów."; +$l['icon_new'] = "Zawiera nowe posty."; +$l['icon_hot'] = " Gorący wątek."; +$l['icon_lock'] = " Zamknięty wątek."; +$l['search_user'] = "Szukaj użytkownika"; + +$l['buddylist_error'] = 'Podczas pobierania listy znajomych wystąpił błąd.'; + +$l['buddyrequests_sent'] = 'Wysłane zaproszenia do znajomych'; +$l['buddyrequests_received'] = 'Otrzymane zaproszenia do znajomych'; +$l['from'] = 'Od'; +$l['to'] = 'Do'; +$l['date'] = 'Data'; +$l['options'] = 'Opcje'; +$l['accept'] = 'Akceptuj'; +$l['decline'] = 'Odrzuć'; +$l['cancel'] = 'Anuluj'; +$l['no_requests'] = 'Brak zaproszeń.'; +$l['buddyrequests_pm'] = 'Otrzymuj powiadomienia na PW po otrzymaniu nowego zaproszenia.'; +$l['buddyrequests_auto'] = 'Automatyczne akceptowanie zaproszeń do znajomych (jeżeli poprzednie pole zostanie również zaznaczone, będziesz otrzymywać PW, informujące o nowym znajomym)'; +$l['buddyrequest_received'] = 'Otrzymano zaproszenie do znajomych'; +$l['buddyrequest_new_buddy'] = 'Masz nowego znajomego'; +$l['buddyrequest_new_buddy_message'] = "Cześć,\n\nWysłane przeze mnie zaproszenie zostało automatycznie zaakceptowane."; +$l['buddyrequest_accepted_request'] = 'Zaakceptowane zaproszenie do znajomych'; +$l['buddyrequest_accepted_request_message'] = "Cześć,\n\nTwoje zaproszenie do znajomych zostało przeze mnie zaakceptowane."; +$l['buddyrequest_received_message'] = "Chcę Cię dodać do mojej listy znajomych.\nMożesz zobaczyć wszystkie zaproszenia, przechodząc do Panelu użytkownika -> Znajomi i ignorowani."; +$l['users_already_sent_request'] = "Przynajmniej jeden z dodanych użytkowników otrzymał już od ciebie zaproszenie."; +$l['users_already_rec_request'] = "Przynajmniej jeden z dodanych użytkowników już ci wysłał zaproszenie."; +$l['users_already_sent_request_alt'] = "Przynajmniej jeden z dodanych użytkowników otrzymał już od ciebie zaproszenie. Musisz anulować to zaproszenie przed dodaniem go do listy ignorowanych."; +$l['users_already_rec_request_alt'] = "Przynajmniej jeden z dodanych użytkowników już ci wysłał zaproszenie. Musisz odrzucić to zaproszenie przed dodaniem go do listy ignorowanych."; +$l['invalid_request'] = 'Wybrano nieprawidłowe zaproszenie do znajomych.'; +$l['buddyrequest_cancelled'] = 'Wybrane zaproszenie do znajomych zostało anulowane.'; +$l['buddyrequest_accepted'] = 'Wybrane zaproszenie do znajomych zostało zaakceptowane.'; +$l['buddyrequest_declined'] = 'Wybrane zaproszenie do znajomych zostało odrzucone.'; +$l['user_doesnt_exist'] = 'Ten użytkownik już nie istnieje.'; +$l['buddyrequests_sent_success'] = 'Zaproszenia do znajomych zostały wysłane.'; diff --git a/Upload/inc/languages/polish/usercpnav.lang.php b/Upload/inc/languages/polish/usercpnav.lang.php new file mode 100644 index 0000000..4be0d99 --- /dev/null +++ b/Upload/inc/languages/polish/usercpnav.lang.php @@ -0,0 +1,34 @@ +Zapisane szkice ({1})"; +$l['ucp_nav_notepad'] = "Osobisty notatnik"; +$l['ucp_nav_view_profile'] = "Pokaż profil"; +$l['ucp_nav_home'] = "Podsumowanie"; +$l['ucp_nav_usergroups'] = "Grupy użytkowników"; +$l['ucp_nav_attachments'] = "Załączniki"; diff --git a/Upload/inc/languages/polish/warnings.lang.php b/Upload/inc/languages/polish/warnings.lang.php new file mode 100644 index 0000000..24dab66 --- /dev/null +++ b/Upload/inc/languages/polish/warnings.lang.php @@ -0,0 +1,98 @@ +Anonimowe PW: wyślij tę wiadomość jako użytkownik anonimowy."; +$l['expiration_never'] = "zawsze"; +$l['expiration_hours'] = "godzin"; +$l['expiration_days'] = "dni"; +$l['expiration_weeks'] = "tygodni"; +$l['expiration_months'] = "miesięcy"; +$l['redirect_warned_banned'] = "

    Użytkownik został też przeniesiony do grupy {1} na {2}."; +$l['redirect_warned_suspended'] = "

    Prawa tego użytkownika do pisania postów zostały zawieszone na {1}."; +$l['redirect_warned_moderate'] = "

    Wszystkie posty tego użytkownika będą musiały być zatwierdzane przez moderatorów przez {1}."; +$l['redirect_warned_pmerror'] = "

    Wiadomość nie została wysłana."; +$l['redirect_warned'] = "Poziom ostrzeżeń użytkownika {1} został podniesiony do {2}%.{3}

    Teraz nastąpi przeniesienie do poprzedniej lokalizacji."; +$l['error_warning_system_disabled'] = "Nie możesz używać systemu ostrzeżeń, bo został on wyłączony przez administratora."; +//$l['reached_max_warnings_day'] = "Nie możesz ostrzec żadnego użytkownika, bo przekroczono już dzienny limit dodanych ostrzeżeń.

    Możesz dodać maksymalnie {1} ostrzeżeń dziennie."; +//$l['user_reached_max_warning'] = "Nie możesz ostrzec tego użytkownika, bo osiągnął on już maksymalny poziom ostrzeżeń."; +$l['error_cant_warn_group'] = "Nie masz uprawnień do udzielania ostrzeżeń członkom tej grupy."; +//$l['error_no_note'] = "Nie wpisano notatki administracyjnej dla tego ostrzeżenia."; +//$l['error_invalid_type'] = "Wybrany typ ostrzeżenia jest nieprawidłowy."; +$l['error_invalid_user'] = "Wybrany użytkownik nie istnieje."; +//$l['error_invalid_post'] = "Wybrany post nie istnieje."; +//$l['error_cant_custom_warn'] = "Twoje uprawnienia pozwalają na dodawanie ostrzeżeń tylko typu ustalonego przez administratora. Wybierz typ ostrzeżenia z listy."; +//$l['error_no_custom_reason'] = "Nie podano powodu ostrzeżenia."; +//$l['error_invalid_custom_points'] = "Wpisana liczba punktów ostrzeżenia jest niepoprawna. Powinna ona być większa niż 0, ale nie większa niż {1}."; +$l['details'] = "Szczegóły"; +$l['view'] = "Zobacz"; +$l['current_warning_level'] = "Aktualny poziom ostrzeżeń: {1}% ({2}/{3})"; +$l['warning_details'] = "Szczegóły ostrzeżeń"; +$l['revoke_warning'] = "Cofnij to ostrzeżenie"; +$l['revoke_warning_desc'] = "By cofnąć to ostrzeżenie, wpisz powód w polu poniżej. Cofnięcie ostrzeżenia nie spowoduje zniesienia banów ani kar spowodowanych jego wystawieniem."; +$l['warning_is_revoked'] = "Ostrzeżenie zostało cofnięte."; +$l['revoked_by'] = "Cofnięte przez:"; +$l['date_revoked'] = "Data zniesienia:"; +$l['warning_already_revoked'] = "Ostrzeżenie zostało już cofnięte."; +$l['no_revoke_reason'] = "Nie podano powodu zniesienia ostrzeżenia."; +$l['redirect_warning_revoked'] = "Ostrzeżenie zostało cofnięte, a poziom ostrzeżeń użytkownika został zaktualizowany.

    Teraz nastÄ…pi przeniesienie do strony podglÄ…du ostrzeżenia."; +$l['result'] = "Wynik:"; +$l['result_banned'] = "Użytkownik zostanie przeniesiony do grupy {1} na {2}"; +$l['result_suspended'] = "Prawo tego użytkownika do pisania na forum zostanie zawieszone na {1}"; +$l['result_moderated'] = "Posty tego użytkownika bÄ™dÄ… musiaÅ‚y być zatwierdzane przez {1}"; +$l['result_period'] = "{1} {2}"; +$l['result_period_perm'] = "caÅ‚y czas"; +$l['hour_or_hours'] = "godzin"; +$l['day_or_days'] = "dni"; +$l['week_or_weeks'] = "tygodni"; +$l['month_or_months'] = "miesiÄ™cy"; +$l['expires'] = "Przedawni siÄ™:"; +$l['new_warning_level'] = "Nowy poziom ostrzeżeÅ„:"; +//$l['cannot_warn_self'] = "Nie możesz zwiÄ™kszyć wÅ‚asnego poziomu ostrzeżeÅ„."; +$l['error_cant_warn_user'] = "Nie masz uprawnieÅ„ do dodawania ostrzeżeÅ„ temu użytkownikowi."; +$l['existing_post_warnings'] = "Ostrzeżenia za ten post"; diff --git a/Upload/inc/languages/polish/xmlhttp.lang.php b/Upload/inc/languages/polish/xmlhttp.lang.php new file mode 100644 index 0000000..760feb3 --- /dev/null +++ b/Upload/inc/languages/polish/xmlhttp.lang.php @@ -0,0 +1,46 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/mailhandlers/php.php b/Upload/inc/mailhandlers/php.php new file mode 100644 index 0000000..57f51b9 --- /dev/null +++ b/Upload/inc/mailhandlers/php.php @@ -0,0 +1,73 @@ +
    Please make sure IN_MYBB is defined."); +} + +/** + * PHP mail handler class. + */ +class PhpMail extends MailHandler +{ + /** + * Additional parameters to pass to PHPs mail() function. + * + * @var string + */ + public $additional_parameters = ''; + + /** + * Sends the email. + * + * @return true/false whether or not the email got sent or not. + */ + function send() + { + global $lang, $mybb; + + // For some reason sendmail/qmail doesn't like \r\n + $this->sendmail = @ini_get('sendmail_path'); + if($this->sendmail) + { + $this->headers = str_replace("\r\n", "\n", $this->headers); + $this->message = str_replace("\r\n", "\n", $this->message); + $this->delimiter = "\n"; + } + + // Some mail providers ignore email's with incorrect return-to path's so try and fix that here + $this->sendmail_from = @ini_get('sendmail_from'); + if($this->sendmail_from != $mybb->settings['adminemail']) + { + @ini_set("sendmail_from", $mybb->settings['adminemail']); + } + + // If safe mode is on, don't send the additional parameters as we're not allowed to + if($mybb->safemode) + { + $sent = @mail($this->to, $this->subject, $this->message, trim($this->headers)); + } + else + { + $sent = @mail($this->to, $this->subject, $this->message, trim($this->headers), $this->additional_parameters); + } + $function_used = 'mail()'; + + if(!$sent) + { + $this->fatal_error("MyBB was unable to send the email using the PHP {$function_used} function."); + return false; + } + + return true; + } +} diff --git a/Upload/inc/mailhandlers/smtp.php b/Upload/inc/mailhandlers/smtp.php new file mode 100644 index 0000000..8c85cfa --- /dev/null +++ b/Upload/inc/mailhandlers/smtp.php @@ -0,0 +1,552 @@ +
    Please make sure IN_MYBB is defined."); +} + +/** + * SMTP mail handler class. + */ + +if(!defined('MYBB_SSL')) +{ + define('MYBB_SSL', 1); +} + +if(!defined('MYBB_TLS')) +{ + define('MYBB_TLS', 2); +} + +class SmtpMail extends MailHandler +{ + /** + * The SMTP connection. + * + * @var resource + */ + public $connection; + + /** + * SMTP username. + * + * @var string + */ + public $username = ''; + + /** + * SMTP password. + * + * @var string + */ + public $password = ''; + + /** + * Hello string sent to the smtp server with either HELO or EHLO. + * + * @var string + */ + public $helo = 'localhost'; + + /** + * User authenticated or not. + * + * @var boolean + */ + public $authenticated = false; + + /** + * How long before timeout. + * + * @var integer + */ + public $timeout = 5; + + /** + * SMTP status. + * + * @var integer + */ + public $status = 0; + + /** + * SMTP default port. + * + * @var integer + */ + public $port = 25; + + /** + * SMTP default secure port. + * + * @var integer + */ + public $secure_port = 465; + + /** + * SMTP host. + * + * @var string + */ + public $host = ''; + + /** + * The last received response from the SMTP server. + * + * @var string + */ + public $data = ''; + + /** + * The last received response code from the SMTP server. + * + * @var string + */ + public $code = 0; + + /** + * The last received error message from the SMTP server. + * + * @var string + */ + public $last_error = ''; + + /** + * Are we keeping the connection to the SMTP server alive? + * + * @var boolean + */ + public $keep_alive = false; + + /** + * Whether to use TLS encryption. + * + * @var boolean + */ + public $use_tls = false; + + function __construct() + { + global $mybb; + + $protocol = ''; + switch($mybb->settings['secure_smtp']) + { + case MYBB_SSL: + $protocol = 'ssl://'; + break; + case MYBB_TLS: + $this->use_tls = true; + break; + } + + if(empty($mybb->settings['smtp_host'])) + { + $this->host = @ini_get('SMTP'); + } + else + { + $this->host = $mybb->settings['smtp_host']; + } + + $local = array('127.0.0.1', '::1', 'localhost'); + if(!in_array($this->host, $local)) + { + if(function_exists('gethostname') && gethostname() !== false) + { + $this->helo = gethostname(); + } + elseif(function_exists('php_uname')) + { + $helo = php_uname('n'); + if(!empty($helo)) + { + $this->helo = $helo; + } + } + elseif(!empty($_SERVER['SERVER_NAME'])) + { + $this->helo = $_SERVER['SERVER_NAME']; + } + } + + $this->host = $protocol . $this->host; + + if(empty($mybb->settings['smtp_port']) && !empty($protocol) && !@ini_get('smtp_port')) + { + $this->port = $this->secure_port; + } + else if(empty($mybb->settings['smtp_port']) && @ini_get('smtp_port')) + { + $this->port = @ini_get('smtp_port'); + } + else if(!empty($mybb->settings['smtp_port'])) + { + $this->port = $mybb->settings['smtp_port']; + } + + $this->password = $mybb->settings['smtp_pass']; + $this->username = $mybb->settings['smtp_user']; + } + + /** + * Sends the email. + * + * @return true/false whether or not the email got sent or not. + */ + function send() + { + global $lang, $mybb; + + if(!$this->connected()) + { + if(!$this->connect()) + { + $this->close(); + } + } + + if($this->connected()) + { + if(!$this->send_data('MAIL FROM:<'.$this->from.'>', '250')) + { + $this->fatal_error("The mail server does not understand the MAIL FROM command. Reason: ".$this->get_error()); + return false; + } + + // Loop through recipients + $emails = explode(',', $this->to); + foreach($emails as $to) + { + $to = trim($to); + if(!$this->send_data('RCPT TO:<'.$to.'>', '250')) + { + $this->fatal_error("The mail server does not understand the RCPT TO command. Reason: ".$this->get_error()); + return false; + } + } + + if($this->send_data('DATA', '354')) + { + $this->send_data('Date: ' . gmdate('r')); + $this->send_data('To: ' . $this->to); + + $this->send_data('Subject: ' . $this->subject); + + // Only send additional headers if we've got any + if(trim($this->headers)) + { + $this->send_data(trim($this->headers)); + } + + $this->send_data(""); + + // Queue the actual message + $this->message = str_replace("\n.", "\n..", $this->message); + $this->send_data($this->message); + } + else + { + $this->fatal_error("The mail server did not understand the DATA command"); + return false; + } + + $this->send_data('.', '250'); + + if(!$this->keep_alive) + { + $this->close(); + } + return true; + } + else + { + return false; + } + } + + /** + * Connect to the SMTP server. + * + * @return boolean True if connection was successful + */ + function connect() + { + global $lang, $mybb; + + $this->connection = @fsockopen($this->host, $this->port, $error_number, $error_string, $this->timeout); + + // DIRECTORY_SEPARATOR checks if running windows + if(function_exists('stream_set_timeout') && DIRECTORY_SEPARATOR != '\\') + { + @stream_set_timeout($this->connection, $this->timeout, 0); + } + + if(is_resource($this->connection)) + { + $this->status = 1; + $this->get_data(); + if(!$this->check_status('220')) + { + $this->fatal_error("The mail server is not ready, it did not respond with a 220 status message."); + return false; + } + + if($this->use_tls || (!empty($this->username) && !empty($this->password))) + { + $helo = 'EHLO'; + } + else + { + $helo = 'HELO'; + } + + $data = $this->send_data("{$helo} {$this->helo}", '250'); + if(!$data) + { + $this->fatal_error("The server did not understand the {$helo} command"); + return false; + } + + if($this->use_tls && preg_match("#250( |-)STARTTLS#mi", $data)) + { + if(!$this->send_data('STARTTLS', '220')) + { + $this->fatal_error("The server did not understand the STARTTLS command. Reason: ".$this->get_error()); + return false; + } + if(!@stream_socket_enable_crypto($this->connection, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) + { + $this->fatal_error("Failed to start TLS encryption"); + return false; + } + // Resend EHLO to get updated service list + $data = $this->send_data("{$helo} {$this->helo}", '250'); + if(!$data) + { + $this->fatal_error("The server did not understand the EHLO command"); + return false; + } + } + + if(!empty($this->username) && !empty($this->password)) + { + preg_match("#250( |-)AUTH( |=)(.+)$#mi", $data, $matches); + if(!$this->auth($matches[3])) + { + return false; + } + } + return true; + } + else + { + $this->fatal_error("Unable to connect to the mail server with the given details. Reason: {$error_number}: {$error_string}"); + return false; + } + } + + /** + * Authenticate against the SMTP server. + * + * @param string A list of authentication methods supported by the server + * @return boolean True on success + */ + function auth($auth_methods) + { + global $lang, $mybb; + + $auth_methods = explode(" ", trim($auth_methods)); + + if(in_array("LOGIN", $auth_methods)) + { + if(!$this->send_data("AUTH LOGIN", 334)) + { + if($this->code == 503) + { + return true; + } + $this->fatal_error("The SMTP server did not respond correctly to the AUTH LOGIN command"); + return false; + } + + if(!$this->send_data(base64_encode($this->username), '334')) + { + $this->fatal_error("The SMTP server rejected the supplied SMTP username. Reason: ".$this->get_error()); + return false; + } + + if(!$this->send_data(base64_encode($this->password), '235')) + { + $this->fatal_error("The SMTP server rejected the supplied SMTP password. Reason: ".$this->get_error()); + return false; + } + } + else if(in_array("PLAIN", $auth_methods)) + { + if(!$this->send_data("AUTH PLAIN", '334')) + { + if($this->code == 503) + { + return true; + } + $this->fatal_error("The SMTP server did not respond correctly to the AUTH PLAIN command"); + return false; + } + $auth = base64_encode(chr(0).$this->username.chr(0).$this->password); + if(!$this->send_data($auth, 235)) + { + $this->fatal_error("The SMTP server rejected the supplied login username and password. Reason: ".$this->get_error()); + return false; + } + } + else + { + $this->fatal_error("The SMTP server does not support any of the AUTH methods that MyBB supports"); + return false; + } + + // Still here, we're authenticated + return true; + } + + /** + * Fetch data from the SMTP server. + * + * @return string The data from the SMTP server + */ + function get_data() + { + $string = ''; + + while((($line = fgets($this->connection, 515)) !== false)) + { + $string .= $line; + if(substr($line, 3, 1) == ' ') + { + break; + } + } + $string = trim($string); + $this->data = $string; + $this->code = substr($this->data, 0, 3); + return $string; + } + + /** + * Check if we're currently connected to an SMTP server + * + * @return boolean true if connected + */ + function connected() + { + if($this->status == 1) + { + return true; + } + return false; + } + + /** + * Send data through to the SMTP server. + * + * @param string The data to be sent + * @param int The response code expected back from the server (if we have one) + * @return boolean True on success + */ + function send_data($data, $status_num = false) + { + if($this->connected()) + { + if(fwrite($this->connection, $data."\r\n")) + { + if($status_num != false) + { + $rec = $this->get_data(); + if($this->check_status($status_num)) + { + return $rec; + } + else + { + $this->set_error($rec); + return false; + } + } + return true; + } + else + { + $this->fatal_error("Unable to send the data to the SMTP server"); + return false; + } + } + return false; + } + + /** + * Checks if the received status code matches the one we expect. + * + * @param int The status code we expected back from the server + * @param boolean True if it matches + */ + function check_status($status_num) + { + if($this->code == $status_num) + { + return $this->data; + } + else + { + return false; + } + } + + /** + * Close the connection to the SMTP server. + */ + function close() + { + if($this->status == 1) + { + $this->send_data('QUIT'); + fclose($this->connection); + $this->status = 0; + } + } + + /** + * Get the last error message response from the SMTP server + * + * @return string The error message response from the SMTP server + */ + function get_error() + { + if(!$this->last_error) + { + $this->last_error = "N/A"; + } + + return $this->last_error; + } + + /** + * Set the last error message response from the SMTP server + * + * @param string The error message response + */ + function set_error($error) + { + $this->last_error = $error; + } +} diff --git a/Upload/inc/mybb_group.php b/Upload/inc/mybb_group.php new file mode 100644 index 0000000..41f6c9f --- /dev/null +++ b/Upload/inc/mybb_group.php @@ -0,0 +1,17 @@ +
    Please make sure IN_MYBB is defined."); +} + +$plugins->add_hook("pre_output_page", "hello_world"); +$plugins->add_hook("postbit", "hello_world_postbit"); + +function hello_info() +{ + /** + * Array of information about the plugin. + * name: The name of the plugin + * description: Description of what the plugin does + * website: The website the plugin is maintained at (Optional) + * author: The name of the author of the plugin + * authorsite: The URL to the website of the author (Optional) + * version: The version number of the plugin + * guid: Unique ID issued by the MyBB Mods site for version checking + * compatibility: A CSV list of MyBB versions supported. Ex, "121,123", "12*". Wildcards supported. + */ + return array( + "name" => "Hello World!", + "description" => "A sample plugin that prints hello world and prepends the content of each post to 'Hello world!'", + "website" => "http://www.mybb.com", + "author" => "MyBB Group", + "authorsite" => "http://www.mybb.com", + "version" => "1.0", + "guid" => "", + "compatibility" => "*" + ); +} + +/** + * ADDITIONAL PLUGIN INSTALL/UNINSTALL ROUTINES + * + * _install(): + * Called whenever a plugin is installed by clicking the "Install" button in the plugin manager. + * If no install routine exists, the install button is not shown and it assumed any work will be + * performed in the _activate() routine. + * + * function hello_install() + * { + * } + * + * _is_installed(): + * Called on the plugin management page to establish if a plugin is already installed or not. + * This should return TRUE if the plugin is installed (by checking tables, fields etc) or FALSE + * if the plugin is not installed. + * + * function hello_is_installed() + * { + * global $db; + * if($db->table_exists("hello_world")) + * { + * return true; + * } + * return false; + * } + * + * _uninstall(): + * Called whenever a plugin is to be uninstalled. This should remove ALL traces of the plugin + * from the installation (tables etc). If it does not exist, uninstall button is not shown. + * + * function hello_uninstall() + * { + * } + * + * _activate(): + * Called whenever a plugin is activated via the Admin CP. This should essentially make a plugin + * "visible" by adding templates/template changes, language changes etc. + * + * function hello_activate() + * { + * } + * + * _deactivate(): + * Called whenever a plugin is deactivated. This should essentially "hide" the plugin from view + * by removing templates/template changes etc. It should not, however, remove any information + * such as tables, fields etc - that should be handled by an _uninstall routine. When a plugin is + * uninstalled, this routine will also be called before _uninstall() if the plugin is active. + * + * function hello_deactivate() + * { + * } + */ + + +function hello_world($page) +{ + $page = str_replace("
    ", "

    Hello World!
    This is a sample MyBB Plugin (which can be disabled!) that displays this message on all pages.

    ", $page); + return $page; +} + +function hello_world_postbit(&$post) +{ + $post['message'] = "Hello world!

    {$post['message']}"; +} diff --git a/Upload/inc/plugins/index.html b/Upload/inc/plugins/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/plugins/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/settings.php b/Upload/inc/settings.php new file mode 100644 index 0000000..e69de29 diff --git a/Upload/inc/tasks/backupdb.php b/Upload/inc/tasks/backupdb.php new file mode 100644 index 0000000..bd1aabc --- /dev/null +++ b/Upload/inc/tasks/backupdb.php @@ -0,0 +1,147 @@ +task_backup_cannot_write_backup); + } + else + { + $db->set_table_prefix(''); + + $file = MYBB_ADMIN_DIR.'backups/backup_'.date("_Ymd_His_").random_str(16); + + if(function_exists('gzopen')) + { + $fp = gzopen($file.'.incomplete.sql.gz', 'w9'); + } + else + { + $fp = fopen($file.'.incomplete.sql', 'w'); + } + + $tables = $db->list_tables($config['database']['database'], $config['database']['table_prefix']); + + $time = date('dS F Y \a\t H:i', TIME_NOW); + $contents = "-- MyBB Database Backup\n-- Generated: {$time}\n-- -------------------------------------\n\n"; + + if(is_object($plugins)) + { + $args = array( + 'task' => &$task, + 'tables' => &$tables, + ); + $plugins->run_hooks('task_backupdb', $args); + } + + foreach($tables as $table) + { + $field_list = array(); + $fields_array = $db->show_fields_from($table); + foreach($fields_array as $field) + { + $field_list[] = $field['Field']; + } + + $fields = "`".implode("`,`", $field_list)."`"; + + $structure = $db->show_create_table($table).";\n"; + $contents .= $structure; + clear_overflow($fp, $contents); + + if($db->engine == 'mysqli') + { + $query = mysqli_query($db->read_link, "SELECT * FROM {$db->table_prefix}{$table}", MYSQLI_USE_RESULT); + } + else + { + $query = $db->simple_select($table); + } + + while($row = $db->fetch_array($query)) + { + $insert = "INSERT INTO {$table} ($fields) VALUES ("; + $comma = ''; + foreach($field_list as $field) + { + if(!isset($row[$field]) || is_null($row[$field])) + { + $insert .= $comma."NULL"; + } + else if($db->engine == 'mysqli') + { + $insert .= $comma."'".mysqli_real_escape_string($db->read_link, $row[$field])."'"; + } + else + { + $insert .= $comma."'".$db->escape_string($row[$field])."'"; + } + $comma = ','; + } + $insert .= ");\n"; + $contents .= $insert; + clear_overflow($fp, $contents); + } + $db->free_result($query); + } + + $db->set_table_prefix(TABLE_PREFIX); + + if(function_exists('gzopen')) + { + gzwrite($fp, $contents); + gzclose($fp); + rename($file.'.incomplete.sql.gz', $file.'.sql.gz'); + } + else + { + fwrite($fp, $contents); + fclose($fp); + rename($file.'.incomplete.sql', $file.'.sql'); + } + + add_task_log($task, $lang->task_backup_ran); + } +} + +// Allows us to refresh cache to prevent over flowing +function clear_overflow($fp, &$contents) +{ + global $mybb; + + if(function_exists('gzopen')) + { + gzwrite($fp, $contents); + } + else + { + fwrite($fp, $contents); + } + + $contents = ''; +} diff --git a/Upload/inc/tasks/checktables.php b/Upload/inc/tasks/checktables.php new file mode 100644 index 0000000..9dc7c32 --- /dev/null +++ b/Upload/inc/tasks/checktables.php @@ -0,0 +1,87 @@ +type == "sqlite") + { + return; + } + + @set_time_limit(0); + + $ok = array( + "The storage engine for the table doesn't support check", + "Table is already up to date", + "OK" + ); + + $comma = ""; + $tables_list = ""; + $repaired = ""; + + $tables = $db->list_tables($mybb->config['database']['database'], $mybb->config['database']['table_prefix']); + foreach($tables as $key => $table) + { + $tables_list .= "{$comma}{$table} "; + $comma = ","; + } + + if($tables_list) + { + $query = $db->query("CHECK TABLE {$tables_list}CHANGED;"); + while($table = $db->fetch_array($query)) + { + if(!in_array($table['Msg_text'], $ok)) + { + if($table['Table'] != $mybb->config['database']['database'].".".TABLE_PREFIX."settings" && $setting_done != true) + { + $boardclosed = $mybb->settings['boardclosed']; + $boardclosed_reason = $mybb->settings['boardclosed_reason']; + + $db->update_query("settings", array('value' => 1), "name='boardclosed'", 1); + $db->update_query("settings", array('value' => $db->escape_string($lang->error_database_repair)), "name='boardclosed_reason'", 1); + rebuild_settings(); + + $setting_done = true; + } + + $db->query("REPAIR TABLE {$table['Table']}"); + $repaired[] = $table['Table']; + } + } + + if($table['Table'] != $mybb->config['database']['table_prefix'].".".TABLE_PREFIX."settings" && $setting_done == true) + { + $db->update_query("settings", array('value' => (int)$boardclosed), "name='boardclosed'", 1); + $db->update_query("settings", array('value' => $db->escape_string($boardclosed_reason)), "name='boardclosed_reason'", 1); + + rebuild_settings(); + } + + } + + if(is_object($plugins)) + { + $plugins->run_hooks('task_checktables', $task); + } + + if(!empty($repaired)) + { + add_task_log($task, $lang->sprintf($lang->task_checktables_ran_found, implode(', ', $repaired))); + } + else + { + add_task_log($task, $lang->task_checktables_ran); + } +} diff --git a/Upload/inc/tasks/dailycleanup.php b/Upload/inc/tasks/dailycleanup.php new file mode 100644 index 0000000..b6198fe --- /dev/null +++ b/Upload/inc/tasks/dailycleanup.php @@ -0,0 +1,92 @@ + TIME_NOW-60*60*24, + 'threadreadcut' => TIME_NOW-(((int)$mybb->settings['threadreadcut'])*60*60*24), + 'privatemessages' => TIME_NOW-(60*60*24*7), + 'deleteinvite' => TIME_NOW-(((int)$mybb->settings['deleteinvites'])*60*60*24), + 'stoppmtracking' => TIME_NOW-(60*60*24*180) + ); + + if(is_object($plugins)) + { + $args = array( + 'task' => &$task, + 'time' => &$time + ); + $plugins->run_hooks('task_dailycleanup_start', $args); + } + + // Clear out sessions older than 24h + $db->delete_query("sessions", "time < '".(int)$time['sessionstime']."'"); + + // Delete old read topics + if($mybb->settings['threadreadcut'] > 0) + { + $db->delete_query("threadsread", "dateline < '".(int)$time['threadreadcut']."'"); + $db->delete_query("forumsread", "dateline < '".(int)$time['threadreadcut']."'"); + } + + // Check PMs moved to trash over a week ago & delete them + $query = $db->simple_select("privatemessages", "pmid, uid, folder", "deletetime<='".(int)$time['privatemessages']."' AND folder='4'"); + while($pm = $db->fetch_array($query)) + { + $user_update[$pm['uid']] = 1; + $pm_update[] = $pm['pmid']; + } + + // Delete old group invites + if($mybb->settings['deleteinvites'] > 0) + { + $db->delete_query("joinrequests", "dateline < '".(int)$time['deleteinvite']."' AND invite='1'"); + } + + // Stop tracking read PMs after 6 months + $sql_array = array( + "receipt" => 0 + ); + $db->update_query("privatemessages", $sql_array, "receipt='2' AND folder!='3' AND status!='0' AND readtime < '".(int)$time['stoppmtracking']."'"); + + if(is_object($plugins)) + { + $args = array( + 'user_update' => &$user_update, + 'pm_update' => &$pm_update + ); + $plugins->run_hooks('task_dailycleanup_end', $args); + } + + if(!empty($pm_update)) + { + $db->delete_query("privatemessages", "pmid IN(".implode(',', $pm_update).")"); + } + + if(!empty($user_update)) + { + foreach($user_update as $uid) + { + update_pm_count($uid); + } + } + + $cache->update_most_replied_threads(); + $cache->update_most_viewed_threads(); + $cache->update_birthdays(); + $cache->update_forumsdisplay(); + + add_task_log($task, $lang->task_dailycleanup_ran); +} diff --git a/Upload/inc/tasks/delayedmoderation.php b/Upload/inc/tasks/delayedmoderation.php new file mode 100644 index 0000000..f2d5d6d --- /dev/null +++ b/Upload/inc/tasks/delayedmoderation.php @@ -0,0 +1,258 @@ +simple_select("delayedmoderation", "*", "delaydateline <= '".TIME_NOW."'"); + while($delayedmoderation = $db->fetch_array($query)) + { + if(is_object($plugins)) + { + $args = array( + 'task' => &$task, + 'delayedmoderation' => &$delayedmoderation, + ); + $plugins->run_hooks('task_delayedmoderation', $args); + } + + $tids = explode(',', $delayedmoderation['tids']); + $input = my_unserialize($delayedmoderation['inputs']); + + if(my_strpos($delayedmoderation['type'], "modtool") !== false) + { + list(, $custom_id) = explode('_', $delayedmoderation['type'], 2); + $custommod->execute($custom_id, $tids); + } + else + { + switch($delayedmoderation['type']) + { + case "openclosethread": + $closed_tids = $open_tids = array(); + $query2 = $db->simple_select("threads", "tid,closed", "tid IN({$delayedmoderation['tids']})"); + while($thread = $db->fetch_array($query2)) + { + if($thread['closed'] == 1) + { + $closed_tids[] = $thread['tid']; + } + else + { + $open_tids[] = $thread['tid']; + } + } + + if(!empty($closed_tids)) + { + $moderation->open_threads($closed_tids); + } + + if(!empty($open_tids)) + { + $moderation->close_threads($open_tids); + } + break; + case "deletethread": + foreach($tids as $tid) + { + $moderation->delete_thread($tid); + } + break; + case "move": + foreach($tids as $tid) + { + $moderation->move_thread($tid, $input['new_forum']); + } + break; + case "stick": + $unstuck_tids = $stuck_tids = array(); + $query2 = $db->simple_select("threads", "tid,sticky", "tid IN({$delayedmoderation['tids']})"); + while($thread = $db->fetch_array($query2)) + { + if($thread['sticky'] == 1) + { + $stuck_tids[] = $thread['tid']; + } + else + { + $unstuck_tids[] = $thread['tid']; + } + } + + if(!empty($stuck_tids)) + { + $moderation->unstick_threads($stuck_tids); + } + + if(!empty($unstuck_tids)) + { + $moderation->stick_threads($unstuck_tids); + } + break; + case "merge": + if(count($tids) != 1) + { + continue; + } + + // explode at # sign in a url (indicates a name reference) and reassign to the url + $realurl = explode("#", $input['threadurl']); + $input['threadurl'] = $realurl[0]; + + // Are we using an SEO URL? + if(substr($input['threadurl'], -4) == "html") + { + // Get thread to merge's tid the SEO way + preg_match("#thread-([0-9]+)?#i", $input['threadurl'], $threadmatch); + preg_match("#post-([0-9]+)?#i", $input['threadurl'], $postmatch); + + if($threadmatch[1]) + { + $parameters['tid'] = $threadmatch[1]; + } + + if($postmatch[1]) + { + $parameters['pid'] = $postmatch[1]; + } + } + else + { + // Get thread to merge's tid the normal way + $splitloc = explode(".php", $input['threadurl']); + $temp = explode("&", my_substr($splitloc[1], 1)); + + if(!empty($temp)) + { + for($i = 0; $i < count($temp); $i++) + { + $temp2 = explode("=", $temp[$i], 2); + $parameters[$temp2[0]] = $temp2[1]; + } + } + else + { + $temp2 = explode("=", $splitloc[1], 2); + $parameters[$temp2[0]] = $temp2[1]; + } + } + + if($parameters['pid'] && !$parameters['tid']) + { + $post = get_post($parameters['pid']); + $mergetid = $post['tid']; + } + else if($parameters['tid']) + { + $mergetid = $parameters['tid']; + } + + $mergetid = (int)$mergetid; + $mergethread = get_thread($mergetid); + + if(!$mergethread['tid']) + { + continue; + } + + if($mergetid == $delayedmoderation['tid']) + { + // sanity check + continue; + } + + if($input['subject']) + { + $subject = $input['subject']; + } + else + { + $query = $db->simple_select("thread", "subject", "tid='{$delayedmoderation['tids']}'"); + $subject = $db->fetch_field($query, "subject"); + } + + $moderation->merge_threads($mergetid, $delayedmoderation['tids'], $subject); + break; + case "removeredirects": + foreach($tids as $tid) + { + $moderation->remove_redirects($tid); + } + break; + case "removesubscriptions": + $moderation->remove_thread_subscriptions($tids, true); + break; + case "approveunapprovethread": + $approved_tids = $unapproved_tids = array(); + $query2 = $db->simple_select("threads", "tid,visible", "tid IN({$delayedmoderation['tids']})"); + while($thread = $db->fetch_array($query2)) + { + if($thread['visible'] == 1) + { + $approved_tids[] = $thread['tid']; + } + else + { + $unapproved_tids[] = $thread['tid']; + } + } + + if(!empty($approved_tids)) + { + $moderation->unapprove_threads($approved_tids); + } + + if(!empty($unapproved_tids)) + { + $moderation->approve_threads($unapproved_tids); + } + break; + case "softdeleterestorethread": + $delete_tids = $restore_tids = array(); + $query2 = $db->simple_select("threads", "tid,visible", "tid IN({$delayedmoderation['tids']})"); + while($thread = $db->fetch_array($query2)) + { + if($thread['visible'] == -1) + { + $restore_tids[] = $thread['tid']; + } + else + { + $delete_tids[] = $thread['tid']; + } + } + + if(!empty($restore_tids)) + { + $moderation->restore_threads($restore_tids); + } + + if(!empty($delete_tids)) + { + $moderation->soft_delete_threads($delete_tids); + } + break; + } + } + + $db->delete_query("delayedmoderation", "did='{$delayedmoderation['did']}'"); + } + + add_task_log($task, $lang->task_delayedmoderation_ran); +} diff --git a/Upload/inc/tasks/hourlycleanup.php b/Upload/inc/tasks/hourlycleanup.php new file mode 100644 index 0000000..464d236 --- /dev/null +++ b/Upload/inc/tasks/hourlycleanup.php @@ -0,0 +1,53 @@ + TIME_NOW, + 'searchlog' => TIME_NOW-(60*60*24), + 'captcha' => TIME_NOW-(60*60*24), + 'question' => TIME_NOW-(60*60*24) + ); + + if(is_object($plugins)) + { + $args = array( + 'task' => &$task, + 'time' => &$time + ); + $plugins->run_hooks('task_hourlycleanup', $args); + } + + require_once MYBB_ROOT."inc/class_moderation.php"; + $moderation = new Moderation; + + // Delete moved threads with time limits + $query = $db->simple_select('threads', 'tid', "deletetime != '0' AND deletetime < '".(int)$time['threads']."'"); + while($tid = $db->fetch_field($query, 'tid')) + { + $moderation->delete_thread($tid); + } + + // Delete old searches + $db->delete_query("searchlog", "dateline < '".(int)$time['searchlog']."'"); + + // Delete old captcha images + $cut = TIME_NOW-(60*60*24*7); + $db->delete_query("captcha", "dateline < '".(int)$time['captcha']."'"); + + // Delete old registration questions + $cut = TIME_NOW-(60*60*24*7); + $db->delete_query("questionsessions", "dateline < '".(int)$time['question']."'"); + + add_task_log($task, $lang->task_hourlycleanup_ran); +} diff --git a/Upload/inc/tasks/index.html b/Upload/inc/tasks/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/inc/tasks/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/inc/tasks/logcleanup.php b/Upload/inc/tasks/logcleanup.php new file mode 100644 index 0000000..b7f0944 --- /dev/null +++ b/Upload/inc/tasks/logcleanup.php @@ -0,0 +1,63 @@ +config['log_pruning']['admin_logs'] > 0) + { + $cut = TIME_NOW-60*60*24*$mybb->config['log_pruning']['admin_logs']; + $db->delete_query("adminlog", "dateline<'{$cut}'"); + } + + // Clear out old moderator logs + if($mybb->config['log_pruning']['mod_logs'] > 0) + { + $cut = TIME_NOW-60*60*24*$mybb->config['log_pruning']['mod_logs']; + $db->delete_query("moderatorlog", "dateline<'{$cut}'"); + } + + // Clear out old task logs + if($mybb->config['log_pruning']['task_logs'] > 0) + { + $cut = TIME_NOW-60*60*24*$mybb->config['log_pruning']['task_logs']; + $db->delete_query("tasklog", "dateline<'{$cut}'"); + } + + // Clear out old mail error logs + if($mybb->config['log_pruning']['mail_logs'] > 0) + { + $cut = TIME_NOW-60*60*24*$mybb->config['log_pruning']['mail_logs']; + $db->delete_query("mailerrors", "dateline<'{$cut}'"); + } + + // Clear out old user mail logs + if($mybb->config['log_pruning']['user_mail_logs'] > 0) + { + $cut = TIME_NOW-60*60*24*$mybb->config['log_pruning']['user_mail_logs']; + $db->delete_query("maillogs", "dateline<'{$cut}'"); + } + + // Clear out old promotion logs + if($mybb->config['log_pruning']['promotion_logs'] > 0) + { + $cut = TIME_NOW-60*60*24*$mybb->config['log_pruning']['promotion_logs']; + $db->delete_query("promotionlogs", "dateline<'{$cut}'"); + } + + if(is_object($plugins)) + { + $plugins->run_hooks('task_logcleanup', $task); + } + + add_task_log($task, $lang->task_logcleanup_ran); +} diff --git a/Upload/inc/tasks/massmail.php b/Upload/inc/tasks/massmail.php new file mode 100644 index 0000000..33e8f23 --- /dev/null +++ b/Upload/inc/tasks/massmail.php @@ -0,0 +1,150 @@ +
    Please make sure IN_MYBB is defined."); +} + +require_once MYBB_ROOT."/inc/functions_massmail.php"; +require_once MYBB_ROOT."inc/datahandlers/pm.php"; + +function task_massmail($task) +{ + global $db, $mybb, $lang, $plugins; + + $query = $db->simple_select("massemails", "*", "senddate <= '".TIME_NOW."' AND status IN (1,2)"); + while($mass_email = $db->fetch_array($query)) + { + if(is_object($plugins)) + { + $args = array( + 'task' => &$task, + 'mass_email' => &$mass_email + ); + $plugins->run_hooks('task_massmail', $args); + } + + if($mass_email['status'] == 1) + { + $db->update_query("massemails", array('status' => 2), "mid='{$mass_email['mid']}'"); + } + + $sentcount = 0; + + if(!$mass_email['perpage']) + { + $mass_email['perpage'] = 50; + } + + if(strpos($mass_email['htmlmessage'], '
    ') === false && strpos($mass_email['htmlmessage'], '
    ') === false) + { + $mass_email['htmlmessage'] = nl2br($mass_email['htmlmessage']); + } + + $mass_email['orig_message'] = $mass_email['message']; + $mass_email['orig_htmlmessage'] = $mass_email['htmlmessage']; + + // Need to perform the search to fetch the number of users we're emailing + $member_query = build_mass_mail_query(my_unserialize($mass_email['conditions'])); + + $count_query = $db->simple_select("users u", "COUNT(uid) AS num", $member_query); + $mass_email['totalcount'] = $db->fetch_field($count_query, "num"); + + $query2 = $db->simple_select("users u", "u.uid, u.language, u.pmnotify, u.lastactive, u.username, u.email", $member_query, array('limit_start' => $mass_email['sentcount'], 'limit' => $mass_email['perpage'], 'order_by' => 'u.uid', 'order_dir' => 'asc')); + while($user = $db->fetch_array($query2)) + { + $replacement_fields = array( + "{uid}" => $user['uid'], + "{username}" => $user['username'], + "{email}" => $user['email'], + "{bbname}" => $mybb->settings['bbname'], + "{bburl}" => $mybb->settings['bburl'], + "[".$lang->massmail_username."]" => $user['username'], + "[".$lang->email_addr."]" => $user['email'], + "[".$lang->board_name."]" => $mybb->settings['bbname'], + "[".$lang->board_url."]" => $mybb->settings['bburl'] + ); + + foreach($replacement_fields as $find => $replace) + { + $mass_email['message'] = str_replace($find, $replace, $mass_email['message']); + $mass_email['htmlmessage'] = str_replace($find, $replace, $mass_email['htmlmessage']); + } + + // Private Message + if($mass_email['type'] == 1) + { + $pm_handler = new PMDataHandler(); + $pm_handler->admin_override = true; + + $pm = array( + "subject" => $mass_email['subject'], + "message" => $mass_email['message'], + "fromid" => $mass_email['uid'], + "options" => array("savecopy" => 0), + ); + + $pm['to'] = explode(",", $user['username']); + $pm_handler->set_data($pm); + if(!$pm_handler->validate_pm()) + { + $friendly_errors = implode('\n', $pm_handler->get_friendly_errors()); + add_task_log($task, $lang->sprintf($lang->task_massmail_ran_errors, htmlspecialchars_uni($user['username']), $friendly_errors)); + $friendly_errors = ""; + } + else + { + $pm_handler->insert_pm(); + } + } + // Normal Email + else + { + switch($mass_email['format']) + { + case 2: + $format = "both"; + $text_message = $mass_email['message']; + $mass_email['message'] = $mass_email['htmlmessage']; + break; + case 1: + $format = "html"; + $text_message = ""; + $mass_email['message'] = $mass_email['htmlmessage']; + break; + default: + $format = "text"; + $text_message = ""; + } + my_mail($user['email'], $mass_email['subject'], $mass_email['message'], "", "", "", false, $format, $text_message); + } + ++$sentcount; + + $mass_email['message'] = $mass_email['orig_message']; + $mass_email['htmlmessage'] = $mass_email['orig_htmlmessage']; + } + + $update_array = array(); + + $update_array['sentcount'] = $mass_email['sentcount'] + $sentcount; + $update_array['totalcount'] = $mass_email['totalcount']; + + if($update_array['sentcount'] >= $mass_email['totalcount']) + { + $update_array['status'] = 3; + } + + $db->update_query("massemails", $update_array, "mid='{$mass_email['mid']}'"); + } + + add_task_log($task, $lang->task_massmail_ran); +} diff --git a/Upload/inc/tasks/promotions.php b/Upload/inc/tasks/promotions.php new file mode 100644 index 0000000..6210e13 --- /dev/null +++ b/Upload/inc/tasks/promotions.php @@ -0,0 +1,255 @@ +read("usergroups"); + // Iterate through all our promotions + $query = $db->simple_select("promotions", "*", "enabled = '1'"); + while($promotion = $db->fetch_array($query)) + { + // Does the destination usergroup even exist?? If it doesn't and it moves a user to it, the user will get PHP errors. + if(!array_key_exists($promotion['newusergroup'], $usergroups)) + { + // Instead of just skipping this promotion, disable it to stop it even being selected when this task is run. + $update = array( + "enabled" => 0 + ); + $db->update_query("promotions", $update, "pid = '" . (int)$promotion['pid'] . "'"); + continue; + } + + $and = ""; + $sql_where = ""; + + // Based on the promotion generate criteria for user selection + $requirements = explode(',', $promotion['requirements']); + if(in_array('postcount', $requirements) && (int)$promotion['posts'] >= 0 && !empty($promotion['posttype'])) + { + $sql_where .= "{$and}postnum {$promotion['posttype']} '{$promotion['posts']}'"; + + $and = " AND "; + } + + if(in_array('threadcount', $requirements) && (int)$promotion['threads'] >= 0 && !empty($promotion['threadtype'])) + { + $sql_where .= "{$and}threadnum {$promotion['threadtype']} '{$promotion['threads']}'"; + + $and = " AND "; + } + + if(in_array('reputation', $requirements) && !empty($promotion['reputationtype'])) + { + $sql_where .= "{$and}reputation {$promotion['reputationtype']} '{$promotion['reputations']}'"; + + $and = " AND "; + } + + if(in_array('referrals', $requirements) && (int)$promotion['referrals'] >= 0 && !empty($promotion['referralstype'])) + { + $sql_where .= "{$and}referrals {$promotion['referralstype']} '{$promotion['referrals']}'"; + + $and = " AND "; + } + + if(in_array('warnings', $requirements) && (int)$promotion['warnings'] >= 0 && !empty($promotion['warningstype'])) + { + $sql_where .= "{$and}warningpoints {$promotion['warningstype']} '{$promotion['warnings']}'"; + + $and = " AND "; + } + + if(in_array('timeregistered', $requirements) && (int)$promotion['registered'] > 0 && !empty($promotion['registeredtype'])) + { + switch($promotion['registeredtype']) + { + case "hours": + $regdate = $promotion['registered']*60*60; + break; + case "days": + $regdate = $promotion['registered']*60*60*24; + break; + case "weeks": + $regdate = $promotion['registered']*60*60*24*7; + break; + case "months": + $regdate = $promotion['registered']*60*60*24*30; + break; + case "years": + $regdate = $promotion['registered']*60*60*24*365; + break; + default: + $regdate = $promotion['registered']*60*60*24; + } + $sql_where .= "{$and}regdate <= '".(TIME_NOW-$regdate)."'"; + $and = " AND "; + } + + if(in_array('timeonline', $requirements) && (int)$promotion['online'] > 0 && !empty($promotion['onlinetype'])) + { + switch($promotion['onlinetype']) + { + case "hours": + $timeonline = $promotion['online']*60*60; + break; + case "days": + $timeonline = $promotion['online']*60*60*24; + break; + case "weeks": + $timeonline = $promotion['online']*60*60*24*7; + break; + case "months": + $timeonline = $promotion['online']*60*60*24*30; + break; + case "years": + $timeonline = $promotion['online']*60*60*24*365; + break; + default: + $timeonline = $promotion['online']*60*60*24; + } + $sql_where .= "{$and}timeonline <= '".(TIME_NOW-$timeonline)."'"; + $and = " AND "; + } + + if(!empty($promotion['originalusergroup']) && $promotion['originalusergroup'] != '*') + { + $sql_where .= "{$and}usergroup IN ({$promotion['originalusergroup']})"; + + $and = " AND "; + } + + if(!empty($promotion['newusergroup'])) + { + // Skip users that are already in the new group + switch($db->type) + { + case "pgsql": + case "sqlite": + $sql_where .= "{$and}usergroup != '{$promotion['newusergroup']}' AND ','||additionalgroups||',' NOT LIKE '%,{$promotion['newusergroup']},%'"; + break; + default: + $sql_where .= "{$and}usergroup != '{$promotion['newusergroup']}' AND CONCAT(',', additionalgroups, ',') NOT LIKE '%,{$promotion['newusergroup']},%'"; + } + + $and = " AND "; + } + + $uid = array(); + $log_inserts = array(); + + if($promotion['usergrouptype'] == "secondary") + { + $usergroup_select = "additionalgroups"; + } + else + { + $usergroup_select = "usergroup"; + } + + if(is_object($plugins)) + { + $args = array( + 'task' => &$task, + 'promotion' => &$promotion, + 'sql_where' => &$sql_where, + 'and' => &$and, + 'usergroup_select' => &$usergroup_select + ); + $plugins->run_hooks('task_promotions', $args); + } + + $query2 = $db->simple_select("users", "uid,{$usergroup_select}", $sql_where); + + $uids = array(); + while($user = $db->fetch_array($query2)) + { + if(is_super_admin($user['uid'])) + { + // Skip super admins + continue; + } + + // super admin check? + if($usergroup_select == "additionalgroups") + { + $log_inserts[] = array( + 'pid' => $promotion['pid'], + 'uid' => $user['uid'], + 'oldusergroup' => $user['additionalgroups'], + 'newusergroup' => $promotion['newusergroup'], + 'dateline' => TIME_NOW, + 'type' => "secondary", + ); + } + else + { + $log_inserts[] = array( + 'pid' => $promotion['pid'], + 'uid' => $user['uid'], + 'oldusergroup' => $user['usergroup'], + 'newusergroup' => $promotion['newusergroup'], + 'dateline' => TIME_NOW, + 'type' => "primary", + ); + } + + $uids[] = $user['uid']; + + + if($usergroup_select == "additionalgroups") + { + if(join_usergroup($user['uid'], $promotion['newusergroup']) === false) + { + // Did the user already have the additional usergroup? + array_pop($log_inserts); + array_pop($uids); + } + } + + if((count($uids) % 20) == 0) + { + if($usergroup_select == "usergroup") + { + $db->update_query("users", array('usergroup' => $promotion['newusergroup']), "uid IN(".implode(",", $uids).")"); + } + + if(!empty($log_inserts)) + { + $db->insert_query_multiple("promotionlogs", $log_inserts); + } + + $uids = array(); + $log_inserts = array(); + } + } + + if(count($uids) > 0) + { + if($usergroup_select == "usergroup") + { + $db->update_query("users", array('usergroup' => $promotion['newusergroup']), "uid IN(".implode(",", $uids).")"); + } + + if(!empty($log_inserts)) + { + $db->insert_query_multiple("promotionlogs", $log_inserts); + } + + $uids = array(); + $log_inserts = array(); + } + } + + $cache->update_moderators(); + + add_task_log($task, $lang->task_promotions_ran); +} diff --git a/Upload/inc/tasks/recachestylesheets.php b/Upload/inc/tasks/recachestylesheets.php new file mode 100644 index 0000000..8ef1cda --- /dev/null +++ b/Upload/inc/tasks/recachestylesheets.php @@ -0,0 +1,39 @@ +config['admin_dir']."/inc/functions_themes.php")) + { + require_once MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions_themes.php"; + } + else if(file_exists(MYBB_ROOT."admin/inc/functions_themes.php")) + { + require_once MYBB_ROOT."admin/inc/functions_themes.php"; + } + + $query = $db->simple_select('themestylesheets', '*'); + + $num_recached = 0; + + while($stylesheet = $db->fetch_array($query)) + { + if(cache_stylesheet($stylesheet['tid'], $stylesheet['name'], $stylesheet['stylesheet'])) + { + $db->update_query("themestylesheets", array('cachefile' => $db->escape_string($stylesheet['name'])), "sid='{$stylesheet['sid']}'", 1); + ++$num_recached; + } + } + + add_task_log($task, $lang->sprintf($lang->task_recachestylesheets_ran, $num_recached)); +} + diff --git a/Upload/inc/tasks/threadviews.php b/Upload/inc/tasks/threadviews.php new file mode 100644 index 0000000..53ee881 --- /dev/null +++ b/Upload/inc/tasks/threadviews.php @@ -0,0 +1,35 @@ +settings['delayedthreadviews'] != 1) + { + return; + } + + // Update thread views + $query = $db->simple_select("threadviews", "tid, COUNT(tid) AS views", "", array('group_by' => 'tid')); + while($threadview = $db->fetch_array($query)) + { + $db->update_query("threads", array('views' => "views+{$threadview['views']}"), "tid='{$threadview['tid']}'", 1, true); + } + + $db->write_query("TRUNCATE TABLE ".TABLE_PREFIX."threadviews"); + + if(is_object($plugins)) + { + $plugins->run_hooks('task_threadviews', $task); + } + + add_task_log($task, $lang->task_threadviews_ran); +} diff --git a/Upload/inc/tasks/usercleanup.php b/Upload/inc/tasks/usercleanup.php new file mode 100644 index 0000000..fc32330 --- /dev/null +++ b/Upload/inc/tasks/usercleanup.php @@ -0,0 +1,74 @@ +expire_warnings(); + + // Expire any post moderation or suspension limits + $query = $db->simple_select("users", "uid, moderationtime, suspensiontime", "(moderationtime!=0 AND moderationtime<".TIME_NOW.") OR (suspensiontime!=0 AND suspensiontime<".TIME_NOW.")"); + while($user = $db->fetch_array($query)) + { + $updated_user = array(); + if($user['moderationtime'] != 0 && $user['moderationtime'] < TIME_NOW) + { + $updated_user['moderateposts'] = 0; + $updated_user['moderationtime'] = 0; + } + if($user['suspensiontime'] != 0 && $user['suspensiontime'] < TIME_NOW) + { + $updated_user['suspendposting'] = 0; + $updated_user['suspensiontime'] = 0; + } + $db->update_query("users", $updated_user, "uid='{$user['uid']}'"); + } + + // Expire any suspended signatures + $query = $db->simple_select("users", "uid, suspendsigtime", "suspendsignature != 0 AND suspendsigtime < '".TIME_NOW."'"); + while($user = $db->fetch_array($query)) + { + if($user['suspendsigtime'] != 0 && $user['suspendsigtime'] < TIME_NOW) + { + $updated_user = array( + "suspendsignature" => 0, + "suspendsigtime" => 0, + ); + $db->update_query("users", $updated_user, "uid='".$user['uid']."'"); + } + } + + // Expire bans + $query = $db->simple_select("banned", "*", "lifted!=0 AND lifted<".TIME_NOW); + while($ban = $db->fetch_array($query)) + { + $updated_user = array( + "usergroup" => $ban['oldgroup'], + "additionalgroups" => $ban['oldadditionalgroups'], + "displaygroup" => $ban['olddisplaygroup'] + ); + $db->update_query("users", $updated_user, "uid='{$ban['uid']}'"); + $db->delete_query("banned", "uid='{$ban['uid']}'"); + } + + $cache->update_moderators(); + + if(is_object($plugins)) + { + $plugins->run_hooks('task_usercleanup', $task); + } + + add_task_log($task, $lang->task_usercleanup_ran); +} diff --git a/Upload/inc/tasks/userpruning.php b/Upload/inc/tasks/userpruning.php new file mode 100644 index 0000000..533a0a4 --- /dev/null +++ b/Upload/inc/tasks/userpruning.php @@ -0,0 +1,84 @@ +settings['enablepruning'] != 1) + { + return; + } + + // Are we pruning by posts? + if($mybb->settings['enableprunebyposts'] == 1) + { + $in_usergroups = array(); + $users = array(); + + $usergroups = $cache->read("usergroups"); + foreach($usergroups as $gid => $usergroup) + { + // Exclude admin, moderators, super moderators, banned + if($usergroup['canmodcp'] == 1 || $usergroup['cancp'] == 1 || $usergroup['issupermod'] == 1 || $usergroup['isbannedgroup'] == 1) + { + continue; + } + $in_usergroups[] = $gid; + } + + // If we're not pruning unactivated users, then remove them from the criteria + if($mybb->settings['pruneunactived'] == 0) + { + $key = array_search('5', $in_usergroups); + unset($in_usergroups[$key]); + } + + $regdate = TIME_NOW-((int)$mybb->settings['dayspruneregistered']*24*60*60); + $query = $db->simple_select("users", "uid", "regdate <= ".(int)$regdate." AND postnum <= ".(int)$mybb->settings['prunepostcount']." AND usergroup IN(".$db->escape_string(implode(',', $in_usergroups)).")"); + while($user = $db->fetch_array($query)) + { + $users[$user['uid']] = $user['uid']; + } + } + + // Are we pruning unactivated users? + if($mybb->settings['pruneunactived'] == 1) + { + $regdate = TIME_NOW-((int)$mybb->settings['dayspruneunactivated']*24*60*60); + $query = $db->simple_select("users", "uid", "regdate <= ".(int)$regdate." AND usergroup='5'"); + while($user = $db->fetch_array($query)) + { + $users[$user['uid']] = $user['uid']; + } + } + + if(is_object($plugins)) + { + $args = array( + 'task' => &$task, + 'in_usergroups' => &$in_usergroups, + 'users' => &$users, + ); + $plugins->run_hooks('task_userpruning', $args); + } + + if(!empty($users)) + { + // Set up user handler. + require_once MYBB_ROOT.'inc/datahandlers/user.php'; + $userhandler = new UserDataHandler('delete'); + + // Delete the prunned users + $userhandler->delete_user($users, $mybb->settings['prunethreads']); + } + + add_task_log($task, $lang->task_userpruning_ran); +} diff --git a/Upload/inc/tasks/versioncheck.php b/Upload/inc/tasks/versioncheck.php new file mode 100644 index 0000000..08109c7 --- /dev/null +++ b/Upload/inc/tasks/versioncheck.php @@ -0,0 +1,99 @@ +version_code); + + $updated_cache = array( + 'last_check' => TIME_NOW + ); + + // Check for the latest version + require_once MYBB_ROOT.'inc/class_xml.php'; + $contents = fetch_remote_file("http://www.mybb.com/version_check.php"); + + if(!$contents) + { + add_task_log($task, $lang->task_versioncheck_ran_errors); + return false; + } + + $pos = strpos($contents, "<"); + if($pos > 1) + { + $contents = substr($contents, $pos); + } + + $pos = strpos(strrev($contents), ">"); + if($pos > 1) + { + $contents = substr($contents, 0, (-1) * ($pos-1)); + } + + $parser = new XMLParser($contents); + $tree = $parser->get_tree(); + + $latest_code = (int)$tree['mybb']['version_code']['value']; + $latest_version = "".htmlspecialchars_uni($tree['mybb']['latest_version']['value'])." (".$latest_code.")"; + if($latest_code > $mybb->version_code) + { + $latest_version = "".$latest_version.""; + $version_warn = 1; + $updated_cache['latest_version'] = $latest_version; + $updated_cache['latest_version_code'] = $latest_code; + } + else + { + $latest_version = "".$latest_version.""; + } + + // Check for the latest news + require_once MYBB_ROOT."inc/class_feedparser.php"; + + $feed_parser = new FeedParser(); + $feed_parser->parse_feed("http://feeds.feedburner.com/MyBBDevelopmentBlog"); + + $updated_cache['news'] = array(); + + require_once MYBB_ROOT . '/inc/class_parser.php'; + $post_parser = new postParser(); + + if($feed_parser->error == '') + { + foreach($feed_parser->items as $item) + { + if (isset($updated_cache['news'][2])) + { + break; + } + + $description = $item['description']; + + $description = $post_parser->parse_message($description, array( + 'allow_html' => true, + ) + ); + + $updated_cache['news'][] = array( + 'title' => htmlspecialchars_uni($item['title']), + 'description' => preg_replace('##', '', $description), + 'link' => htmlspecialchars_uni($item['link']), + 'author' => htmlspecialchars_uni($item['author']), + 'dateline' => $item['date_timestamp'] + ); + } + } + + $cache->update("update_check", $updated_cache); + add_task_log($task, $lang->task_versioncheck_ran); +} diff --git a/Upload/index.php b/Upload/index.php new file mode 100644 index 0000000..f55ffe6 --- /dev/null +++ b/Upload/index.php @@ -0,0 +1,390 @@ +run_hooks('index_start'); + +// Load global language phrases +$lang->load('index'); + +$logoutlink = ''; +if($mybb->user['uid'] != 0) +{ + eval('$logoutlink = "'.$templates->get('index_logoutlink').'";'); +} + +$statspage = ''; +if($mybb->settings['statsenabled'] != 0) +{ + eval('$statspage = "'.$templates->get('index_statspage').'";'); +} + +$whosonline = ''; +if($mybb->settings['showwol'] != 0 && $mybb->usergroup['canviewonline'] != 0) +{ + // Get the online users. + if($mybb->settings['wolorder'] == 'username') + { + $order_by = 'u.username ASC'; + $order_by2 = 's.time DESC'; + } + else + { + $order_by = 's.time DESC'; + $order_by2 = 'u.username ASC'; + } + + $timesearch = TIME_NOW - (int)$mybb->settings['wolcutoff']; + $comma = ''; + $query = $db->query(" + SELECT s.sid, s.ip, s.uid, s.time, s.location, s.location1, u.username, u.invisible, u.usergroup, u.displaygroup + FROM ".TABLE_PREFIX."sessions s + LEFT JOIN ".TABLE_PREFIX."users u ON (s.uid=u.uid) + WHERE s.time > '".$timesearch."' + ORDER BY {$order_by}, {$order_by2} + "); + + $forum_viewers = $doneusers = array(); + $membercount = $guestcount = $anoncount = $botcount = 0; + $onlinemembers = $comma = ''; + + // Fetch spiders + $spiders = $cache->read('spiders'); + + // Loop through all users. + while($user = $db->fetch_array($query)) + { + // Create a key to test if this user is a search bot. + $botkey = my_strtolower(str_replace('bot=', '', $user['sid'])); + + // Decide what type of user we are dealing with. + if($user['uid'] > 0) + { + // The user is registered. + if(empty($doneusers[$user['uid']]) || $doneusers[$user['uid']] < $user['time']) + { + // If the user is logged in anonymously, update the count for that. + if($user['invisible'] == 1) + { + ++$anoncount; + } + ++$membercount; + if($user['invisible'] != 1 || $mybb->usergroup['canviewwolinvis'] == 1 || $user['uid'] == $mybb->user['uid']) + { + // If this usergroup can see anonymously logged-in users, mark them. + if($user['invisible'] == 1) + { + $invisiblemark = '*'; + } + else + { + $invisiblemark = ''; + } + + // Properly format the username and assign the template. + $user['username'] = format_name($user['username'], $user['usergroup'], $user['displaygroup']); + $user['profilelink'] = build_profile_link($user['username'], $user['uid']); + eval('$onlinemembers .= "'.$templates->get('index_whosonline_memberbit', 1, 0).'";'); + $comma = $lang->comma; + } + // This user has been handled. + $doneusers[$user['uid']] = $user['time']; + } + } + elseif(my_strpos($user['sid'], 'bot=') !== false && $spiders[$botkey]) + { + // The user is a search bot. + $onlinemembers .= $comma.format_name($spiders[$botkey]['name'], $spiders[$botkey]['usergroup']); + $comma = $lang->comma; + ++$botcount; + } + else + { + // The user is a guest. + ++$guestcount; + } + + if($user['location1']) + { + ++$forum_viewers[$user['location1']]; + } + } + + // Build the who's online bit on the index page. + $onlinecount = $membercount + $guestcount + $botcount; + + if($onlinecount != 1) + { + $onlinebit = $lang->online_online_plural; + } + else + { + $onlinebit = $lang->online_online_singular; + } + if($membercount != 1) + { + $memberbit = $lang->online_member_plural; + } + else + { + $memberbit = $lang->online_member_singular; + } + if($anoncount != 1) + { + $anonbit = $lang->online_anon_plural; + } + else + { + $anonbit = $lang->online_anon_singular; + } + if($guestcount != 1) + { + $guestbit = $lang->online_guest_plural; + } + else + { + $guestbit = $lang->online_guest_singular; + } + $lang->online_note = $lang->sprintf($lang->online_note, my_number_format($onlinecount), $onlinebit, $mybb->settings['wolcutoffmins'], my_number_format($membercount), $memberbit, my_number_format($anoncount), $anonbit, my_number_format($guestcount), $guestbit); + eval('$whosonline = "'.$templates->get('index_whosonline').'";'); +} + +// Build the birthdays for to show on the index page. +$bdays = $birthdays = ''; +if($mybb->settings['showbirthdays'] != 0) +{ + // First, see what day this is. + $bdaycount = $bdayhidden = 0; + $bdaydate = my_date('j-n', TIME_NOW, '', 0); + $year = my_date('Y', TIME_NOW, '', 0); + + $bdaycache = $cache->read('birthdays'); + + if(!is_array($bdaycache)) + { + $cache->update_birthdays(); + $bdaycache = $cache->read('birthdays'); + } + + $hiddencount = $today_bdays = 0; + if(isset($bdaycache[$bdaydate])) + { + $hiddencount = $bdaycache[$bdaydate]['hiddencount']; + $today_bdays = $bdaycache[$bdaydate]['users']; + } + + $comma = ''; + if(!empty($today_bdays)) + { + if((int)$mybb->settings['showbirthdayspostlimit'] > 0) + { + $bdayusers = array(); + foreach($today_bdays as $key => $bdayuser_pc) + { + $bdayusers[$bdayuser_pc['uid']] = $key; + } + + if(!empty($bdayusers)) + { + // Find out if our users have enough posts to be seen on our birthday list + $bday_sql = implode(',', array_keys($bdayusers)); + $query = $db->simple_select('users', 'uid, postnum', "uid IN ({$bday_sql})"); + + while($bdayuser = $db->fetch_array($query)) + { + if($bdayuser['postnum'] < $mybb->settings['showbirthdayspostlimit']) + { + unset($today_bdays[$bdayusers[$bdayuser['uid']]]); + } + } + } + } + + // We still have birthdays - display them in our list! + if(!empty($today_bdays)) + { + foreach($today_bdays as $bdayuser) + { + if($bdayuser['displaygroup'] == 0) + { + $bdayuser['displaygroup'] = $bdayuser['usergroup']; + } + + // If this user's display group can't be seen in the birthday list, skip it + if($groupscache[$bdayuser['displaygroup']] && $groupscache[$bdayuser['displaygroup']]['showinbirthdaylist'] != 1) + { + continue; + } + + $age = ''; + $bday = explode('-', $bdayuser['birthday']); + if($year > $bday['2'] && $bday['2'] != '') + { + $age = ' ('.($year - $bday['2']).')'; + } + + $bdayuser['username'] = format_name($bdayuser['username'], $bdayuser['usergroup'], $bdayuser['displaygroup']); + $bdayuser['profilelink'] = build_profile_link($bdayuser['username'], $bdayuser['uid']); + eval('$bdays .= "'.$templates->get('index_birthdays_birthday', 1, 0).'";'); + ++$bdaycount; + $comma = $lang->comma; + } + } + } + + if($hiddencount > 0) + { + if($bdaycount > 0) + { + $bdays .= ' - '; + } + + $bdays .= "{$hiddencount} {$lang->birthdayhidden}"; + } + + // If there are one or more birthdays, show them. + if($bdaycount > 0 || $hiddencount > 0) + { + eval('$birthdays = "'.$templates->get('index_birthdays').'";'); + } +} + +// Build the forum statistics to show on the index page. +$forumstats = ''; +if($mybb->settings['showindexstats'] != 0) +{ + // First, load the stats cache. + $stats = $cache->read('stats'); + + // Check who's the newest member. + if(!$stats['lastusername']) + { + $newestmember = $lang->nobody;; + } + else + { + $newestmember = build_profile_link($stats['lastusername'], $stats['lastuid']); + } + + // Format the stats language. + $lang->stats_posts_threads = $lang->sprintf($lang->stats_posts_threads, my_number_format($stats['numposts']), my_number_format($stats['numthreads'])); + $lang->stats_numusers = $lang->sprintf($lang->stats_numusers, my_number_format($stats['numusers'])); + $lang->stats_newestuser = $lang->sprintf($lang->stats_newestuser, $newestmember); + + // Find out what the highest users online count is. + $mostonline = $cache->read('mostonline'); + if($onlinecount > $mostonline['numusers']) + { + $time = TIME_NOW; + $mostonline['numusers'] = $onlinecount; + $mostonline['time'] = $time; + $cache->update('mostonline', $mostonline); + } + $recordcount = $mostonline['numusers']; + $recorddate = my_date($mybb->settings['dateformat'], $mostonline['time']); + $recordtime = my_date($mybb->settings['timeformat'], $mostonline['time']); + + // Then format that language string. + $lang->stats_mostonline = $lang->sprintf($lang->stats_mostonline, my_number_format($recordcount), $recorddate, $recordtime); + + eval('$forumstats = "'.$templates->get('index_stats').'";'); +} + +// Show the board statistics table only if one or more index statistics are enabled. +$boardstats = ''; +if(($mybb->settings['showwol'] != 0 && $mybb->usergroup['canviewonline'] != 0) || $mybb->settings['showindexstats'] != 0 || ($mybb->settings['showbirthdays'] != 0 && $bdaycount > 0)) +{ + if(!isset($stats) || isset($stats) && !is_array($stats)) + { + // Load the stats cache. + $stats = $cache->read('stats'); + } + + $post_code_string = ''; + if($mybb->user['uid']) + { + $post_code_string = '&my_post_key='.$mybb->post_code; + } + + eval('$boardstats = "'.$templates->get('index_boardstats').'";'); +} + +if($mybb->user['uid'] == 0) +{ + // Build a forum cache. + $query = $db->simple_select('forums', '*', 'active!=0', array('order_by' => 'pid, disporder')); + + $forumsread = array(); + if(isset($mybb->cookies['mybb']['forumread'])) + { + $forumsread = my_unserialize($mybb->cookies['mybb']['forumread']); + } +} +else +{ + // Build a forum cache. + $query = $db->query(" + SELECT f.*, fr.dateline AS lastread + FROM ".TABLE_PREFIX."forums f + LEFT JOIN ".TABLE_PREFIX."forumsread fr ON (fr.fid = f.fid AND fr.uid = '{$mybb->user['uid']}') + WHERE f.active != 0 + ORDER BY pid, disporder + "); +} + +while($forum = $db->fetch_array($query)) +{ + if($mybb->user['uid'] == 0) + { + if(!empty($forumsread[$forum['fid']])) + { + $forum['lastread'] = $forumsread[$forum['fid']]; + } + } + $fcache[$forum['pid']][$forum['disporder']][$forum['fid']] = $forum; +} +$forumpermissions = forum_permissions(); + +// Get the forum moderators if the setting is enabled. +$moderatorcache = array(); +if($mybb->settings['modlist'] != 0 && $mybb->settings['modlist'] != 'off') +{ + $moderatorcache = $cache->read('moderators'); +} + +$excols = 'index'; +$permissioncache['-1'] = '1'; +$bgcolor = 'trow1'; + +// Decide if we're showing first-level subforums on the index page. +$showdepth = 2; +if($mybb->settings['subforumsindex'] != 0) +{ + $showdepth = 3; +} + +$forum_list = build_forumbits(); +$forums = $forum_list['forum_list']; + +$plugins->run_hooks('index_end'); + +eval('$index = "'.$templates->get('index').'";'); +output_page($index); diff --git a/Upload/install/images/active.png b/Upload/install/images/active.png new file mode 100644 index 0000000000000000000000000000000000000000..be3f31461bea694713f2d2a460bffd36be3c8573 GIT binary patch literal 5495 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 + + + + +  + + \ No newline at end of file diff --git a/Upload/install/images/logo.png b/Upload/install/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c1193d6c2151528b3a8ef07f255cc207f805bce5 GIT binary patch literal 10286 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 Ar2qf` literal 0 HcmV?d00001 diff --git a/Upload/install/images/submit_bg.png b/Upload/install/images/submit_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..387093b98445806e5782733124a317aa19b9f661 GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{M!3-pCdAEE8QsDtUA+G=b|Nr~%@83UvfB*jd z>-Vo;KY#uB@$>tSAK$-!|MuYb5TXT%^L3Sp2ySvEDVR2*!aySb-B8!2v z2N=7Z%(eqE3_V>OLpZMU9&BZ7FkoO%$Voq*^M8MEW4zMTlcHWzqb_8WRyAKt*%skC z`|iV%owoP*<>DBpd;aw}1=Ors;u=wsl30>zm0Xkxq!^4042^XSEOm`cLJUoZ0002ONklc0EdNGS%ukbt%1^0bZe6H)F;QHDae9te%=R8jej`N`4 zIBX8h$Hw5Ze<(itwo|Ze8wKmSQhb(Wq4>=6O!1kfiQ+SkBL(9yP%sQV#i#E(ici BZ7Bc% literal 0 HcmV?d00001 diff --git a/Upload/install/images/thead.png b/Upload/install/images/thead.png new file mode 100644 index 0000000000000000000000000000000000000000..575dc0e9f1e171fd1548a6c0124b635c427a86b8 GIT binary patch literal 170 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfx!3-ohG7?;Ylx2WVh$}oVgYR)m_ zZDS}o#87{YA#D{y*-?g~{R~-~7%ERQ6z*Xt+{;jPmLYWoW9o8-%Hs@aYxYUX2?Gt$ z@pN$vsfaT@*v`wKz`$g1r}|(0nwBGCf%eCRd-*r9=~`X5x#9Y$Y5J4&-mq)1Fe-L9 S)I|dIF?hQAxvXset_path(MYBB_ROOT.'install/resources'); +$lang->load('language'); + +// Prevent any shut down functions from running +$done_shutdown = 1; + +// Include the necessary contants for installation +$grouppermignore = array('gid', 'type', 'title', 'description', 'namestyle', 'usertitle', 'stars', 'starimage', 'image'); +$groupzerogreater = array('pmquota', 'maxpmrecipients', 'maxreputationsday', 'attachquota', 'maxemails', 'maxwarningsday', 'maxposts', 'edittimelimit', 'canusesigxposts', 'maxreputationsperthread'); +$displaygroupfields = array('title', 'description', 'namestyle', 'usertitle', 'stars', 'starimage', 'image'); +$fpermfields = array('canview', 'candlattachments', 'canpostthreads', 'canpostreplys', 'canpostattachments', 'canratethreads', 'caneditposts', 'candeleteposts', 'candeletethreads', 'caneditattachments', 'canpostpolls', 'canvotepolls', 'cansearch'); + +// Include the installation resources +require_once INSTALL_ROOT.'resources/output.php'; +$output = new installerOutput; + +$dboptions = array(); + +if(function_exists('mysqli_connect')) +{ + $dboptions['mysqli'] = array( + 'class' => 'DB_MySQLi', + 'title' => 'MySQL Improved', + 'short_title' => 'MySQLi', + 'structure_file' => 'mysql_db_tables.php', + 'population_file' => 'mysql_db_inserts.php' + ); +} + +if(function_exists('mysql_connect')) +{ + $dboptions['mysql'] = array( + 'class' => 'DB_MySQL', + 'title' => 'MySQL', + 'short_title' => 'MySQL', + 'structure_file' => 'mysql_db_tables.php', + 'population_file' => 'mysql_db_inserts.php' + ); +} + +if(function_exists('pg_connect')) +{ + $dboptions['pgsql'] = array( + 'class' => 'DB_PgSQL', + 'title' => 'PostgreSQL', + 'short_title' => 'PostgreSQL', + 'structure_file' => 'pgsql_db_tables.php', + 'population_file' => 'mysql_db_inserts.php' + ); +} + +if(class_exists('PDO')) +{ + $supported_dbs = PDO::getAvailableDrivers(); + if(in_array('sqlite', $supported_dbs)) + { + $dboptions['sqlite'] = array( + 'class' => 'DB_SQLite', + 'title' => 'SQLite 3', + 'short_title' => 'SQLite', + 'structure_file' => 'sqlite_db_tables.php', + 'population_file' => 'mysql_db_inserts.php' + ); + } +} + +if(file_exists('lock') && $mybb->dev_mode != true) +{ + $output->print_error($lang->locked); +} +else if($installed == true && empty($mybb->input['action'])) +{ + $output->print_header($lang->already_installed, "errormsg", 0); + echo $lang->sprintf($lang->mybb_already_installed, $mybb->version); + $output->print_footer(); +} +else +{ + $output->steps = array( + 'intro' => $lang->welcome, + 'license' => $lang->license_agreement, + 'requirements_check' => $lang->req_check, + 'database_info' => $lang->db_config, + 'create_tables' => $lang->table_creation, + 'populate_tables' => $lang->data_insertion, + 'templates' => $lang->theme_install, + 'configuration' => $lang->board_config, + 'adminuser' => $lang->admin_user, + 'final' => $lang->finish_setup, + ); + + switch($mybb->get_input('action')) + { + case 'license': + license_agreement(); + break; + case 'requirements_check': + requirements_check(); + break; + case 'database_info': + database_info(); + break; + case 'create_tables': + create_tables(); + break; + case 'populate_tables': + populate_tables(); + break; + case 'templates': + insert_templates(); + break; + case 'configuration': + configure(); + break; + case 'adminuser': + create_admin_user(); + break; + case 'final': + install_done(); + break; + default: + $mybb->input['action'] = 'intro'; + intro(); + break; + } +} + +function intro() +{ + global $output, $mybb, $lang; + + $output->print_header($lang->welcome, 'welcome'); + if(strpos(strtolower($_SERVER['PHP_SELF']), "upload/") !== false) + { + echo $lang->sprintf($lang->mybb_incorrect_folder); + } + echo $lang->sprintf($lang->welcome_step, $mybb->version); + $output->print_footer('license'); +} + +function license_agreement() +{ + global $output, $lang, $mybb; + + ob_start(); + $output->print_header($lang->license_agreement, 'license'); + + if($mybb->get_input('allow_anonymous_info', 1) == 1) + { + require_once MYBB_ROOT."inc/functions_serverstats.php"; + $build_server_stats = build_server_stats(1, '', $mybb->version_code); + + if($build_server_stats['info_sent_success'] == false) + { + echo $build_server_stats['info_image']; + } + } + ob_end_flush(); + + $license = << + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + +EOF; + echo $lang->sprintf($lang->license_step, $license); + $output->print_footer('requirements_check'); +} + +function requirements_check() +{ + global $output, $mybb, $dboptions, $lang; + + $mybb->input['action'] = "requirements_check"; + $output->print_header($lang->req_check, 'requirements'); + echo $lang->req_step_top; + $errors = array(); + $showerror = 0; + + if(!file_exists(MYBB_ROOT."/inc/config.php")) + { + if(!@rename(MYBB_ROOT."/inc/config.default.php", MYBB_ROOT."/inc/config.php")) + { + if(!$configwritable) + { + $errors[] = $lang->sprintf($lang->req_step_error_box, $lang->req_step_error_configdefaultfile); + $configstatus = $lang->sprintf($lang->req_step_span_fail, $lang->not_writable); + $showerror = 1; + } + } + } + + // Check PHP Version + if(version_compare(PHP_VERSION, '5.2.0', "<")) + { + $errors[] = $lang->sprintf($lang->req_step_error_box, $lang->sprintf($lang->req_step_error_phpversion, PHP_VERSION)); + $phpversion = $lang->sprintf($lang->req_step_span_fail, PHP_VERSION); + $showerror = 1; + } + else + { + $phpversion = $lang->sprintf($lang->req_step_span_pass, PHP_VERSION); + } + + $mboptions = array(); + + if(function_exists('mb_detect_encoding')) + { + $mboptions[] = $lang->multi_byte; + } + + if(function_exists('iconv')) + { + $mboptions[] = 'iconv'; + } + + // Check Multibyte extensions + if(count($mboptions) < 1) + { + $mbstatus = $lang->sprintf($lang->req_step_span_fail, $lang->none); + } + else + { + $mbstatus = implode(', ', $mboptions); + } + + // Check database engines + if(count($dboptions) < 1) + { + $errors[] = $lang->sprintf($lang->req_step_error_box, $lang->req_step_error_dboptions); + $dbsupportlist = $lang->sprintf($lang->req_step_span_fail, $lang->none); + $showerror = 1; + } + else + { + foreach($dboptions as $dboption) + { + $dbsupportlist[] = $dboption['title']; + } + $dbsupportlist = implode(', ', $dbsupportlist); + } + + // Check XML parser is installed + if(!function_exists('xml_parser_create')) + { + $errors[] = $lang->sprintf($lang->req_step_error_box, $lang->req_step_error_xmlsupport); + $xmlstatus = $lang->sprintf($lang->req_step_span_fail, $lang->not_installed); + $showerror = 1; + } + else + { + $xmlstatus = $lang->sprintf($lang->req_step_span_pass, $lang->installed); + } + + // Check config file is writable + $configwritable = @fopen(MYBB_ROOT.'inc/config.php', 'w'); + if(!$configwritable) + { + $errors[] = $lang->sprintf($lang->req_step_error_box, $lang->req_step_error_configfile); + $configstatus = $lang->sprintf($lang->req_step_span_fail, $lang->not_writable); + $showerror = 1; + } + else + { + $configstatus = $lang->sprintf($lang->req_step_span_pass, $lang->writable); + } + @fclose($configwritable); + + // Check settings file is writable + $settingswritable = @fopen(MYBB_ROOT.'inc/settings.php', 'w'); + if(!$settingswritable) + { + $errors[] = $lang->sprintf($lang->req_step_error_box, $lang->req_step_error_settingsfile); + $settingsstatus = $lang->sprintf($lang->req_step_span_fail, $lang->not_writable); + $showerror = 1; + } + else + { + $settingsstatus = $lang->sprintf($lang->req_step_span_pass, $lang->writable); + } + @fclose($settingswritable); + + // Check cache directory is writable + $cachewritable = @fopen(MYBB_ROOT.'cache/test.write', 'w'); + if(!$cachewritable) + { + $errors[] = $lang->sprintf($lang->req_step_error_box, $lang->req_step_error_cachedir); + $cachestatus = $lang->sprintf($lang->req_step_span_fail, $lang->not_writable); + $showerror = 1; + @fclose($cachewritable); + } + else + { + $cachestatus = $lang->sprintf($lang->req_step_span_pass, $lang->writable); + @fclose($cachewritable); + @my_chmod(MYBB_ROOT.'cache', '0777'); + @my_chmod(MYBB_ROOT.'cache/test.write', '0777'); + @unlink(MYBB_ROOT.'cache/test.write'); + } + + // Check upload directory is writable + $uploadswritable = @fopen(MYBB_ROOT.'uploads/test.write', 'w'); + if(!$uploadswritable) + { + $errors[] = $lang->sprintf($lang->req_step_error_box, $lang->req_step_error_uploaddir); + $uploadsstatus = $lang->sprintf($lang->req_step_span_fail, $lang->not_writable); + $showerror = 1; + @fclose($uploadswritable); + } + else + { + $uploadsstatus = $lang->sprintf($lang->req_step_span_pass, $lang->writable); + @fclose($uploadswritable); + @my_chmod(MYBB_ROOT.'uploads', '0777'); + @my_chmod(MYBB_ROOT.'uploads/test.write', '0777'); + @unlink(MYBB_ROOT.'uploads/test.write'); + } + + // Check avatar directory is writable + $avatarswritable = @fopen(MYBB_ROOT.'uploads/avatars/test.write', 'w'); + if(!$avatarswritable) + { + $errors[] = $lang->sprintf($lang->req_step_error_box, $lang->req_step_error_avatardir); + $avatarsstatus = $lang->sprintf($lang->req_step_span_fail, $lang->not_writable); + $showerror = 1; + @fclose($avatarswritable); + } + else + { + $avatarsstatus = $lang->sprintf($lang->req_step_span_pass, $lang->writable); + @fclose($avatarswritable); + @my_chmod(MYBB_ROOT.'uploads/avatars', '0777'); + @my_chmod(MYBB_ROOT.'uploads/avatars/test.write', '0777'); + @unlink(MYBB_ROOT.'uploads/avatars/test.write'); + } + + // Output requirements page + echo $lang->sprintf($lang->req_step_reqtable, $phpversion, $dbsupportlist, $mbstatus, $xmlstatus, $configstatus, $settingsstatus, $cachestatus, $uploadsstatus, $avatarsstatus); + + if($showerror == 1) + { + $error_list = error_list($errors); + echo $lang->sprintf($lang->req_step_error_tablelist, $error_list); + echo "\n input['action']}\" />"; + echo "\n


    \n"; + $output->print_footer(); + } + else + { + echo $lang->req_step_reqcomplete; + $output->print_footer('database_info'); + } +} + +function database_info() +{ + global $output, $dbinfo, $errors, $mybb, $dboptions, $lang; + + $mybb->input['action'] = 'database_info'; + $output->print_header($lang->db_config, 'dbconfig'); + + echo ""; + + // Check for errors from this stage + if(is_array($errors)) + { + $error_list = error_list($errors); + echo $lang->sprintf($lang->db_step_error_config, $error_list); + } + else + { + echo $lang->db_step_config_db; + } + + $dbengines = ''; + + // Loop through database engines + foreach($dboptions as $dbfile => $dbtype) + { + if($mybb->get_input('dbengine') == $dbfile) + { + $dbengines .= ""; + } + else + { + $dbengines .= ""; + } + } + + $db_info = array(); + foreach($dboptions as $dbfile => $dbtype) + { + require_once MYBB_ROOT."inc/db_{$dbfile}.php"; + $db = new $dbtype['class']; + $encodings = $db->fetch_db_charsets(); + $encoding_select = ''; + $mybb->input['config'] = $mybb->get_input('config', 2); + if(empty($mybb->input['config'][$dbfile]['dbhost'])) + { + $mybb->input['config'][$dbfile]['dbhost'] = "localhost"; + } + if(empty($mybb->input['config'][$dbfile]['tableprefix'])) + { + $mybb->input['config'][$dbfile]['tableprefix'] = "mybb_"; + } + if(empty($mybb->input['config'][$dbfile]['dbname'])) + { + $mybb->input['config'][$dbfile]['dbname'] = ''; + } + if(empty($mybb->input['config'][$dbfile]['dbuser'])) + { + $mybb->input['config'][$dbfile]['dbuser'] = ''; + } + if(empty($mybb->input['config'][$dbfile]['dbpass'])) + { + $mybb->input['config'][$dbfile]['dbpass'] = ''; + } + if(empty($mybb->input['config'][$dbfile]['encoding'])) + { + $mybb->input['config'][$dbfile]['encoding'] = "utf8"; + } + + $class = ''; + if(empty($first) && !$mybb->get_input('dbengine')) + { + $mybb->input['dbengine'] = $dbfile; + $first = true; + } + if($dbfile == $mybb->input['dbengine']) + { + $class = "_selected"; + } + + $db_info[$dbfile] = " + + + {$dbtype['title']} {$lang->database_settings} + "; + + // SQLite gets some special settings + if($dbfile == 'sqlite') + { + $db_info[$dbfile] .= " + + + input['config'][$dbfile]['dbname'])."\" /> + "; + } + // Others get db host, username, password etc + else + { + $db_info[$dbfile] .= " + + + input['config'][$dbfile]['dbhost'])."\" /> + + + + input['config'][$dbfile]['dbuser'])."\" /> + + + + input['config'][$dbfile]['dbpass'])."\" /> + + + + input['config'][$dbfile]['dbname'])."\" /> + "; + } + + // Now we're up to table settings + $db_info[$dbfile] .= " + + {$dbtype['title']} {$lang->table_settings} + + + + input['config'][$dbfile]['tableprefix'])."\" /> + + "; + + // Encoding selection only if supported + if(is_array($encodings)) + { + $select_options = ""; + foreach($encodings as $encoding => $title) + { + if($mybb->input['config'][$dbfile]['encoding'] == $encoding) + { + $select_options .= ""; + } + else + { + $select_options .= ""; + } + } + $db_info[$dbfile] .= " + + + + + "; + } + } + $dbconfig = implode("", $db_info); + + echo $lang->sprintf($lang->db_step_config_table, $dbengines, $dbconfig); + $output->print_footer('create_tables'); +} + +function create_tables() +{ + global $output, $dbinfo, $errors, $mybb, $dboptions, $lang; + + $mybb->input['dbengine'] = $mybb->get_input('dbengine'); + if(!file_exists(MYBB_ROOT."inc/db_{$mybb->input['dbengine']}.php")) + { + $errors[] = $lang->db_step_error_invalidengine; + database_info(); + } + + $mybb->input['config'] = $mybb->get_input('config', 2); + $config = $mybb->input['config'][$mybb->input['dbengine']]; + + if(strstr($mybb->input['dbengine'], "sqlite") !== false) + { + if(strstr($config['dbname'], "./") !== false || strstr($config['dbname'], "../") !== false || empty($config['dbname'])) + { + $errors[] = $lang->db_step_error_sqlite_invalid_dbname; + database_info(); + } + } + + // Attempt to connect to the db + require_once MYBB_ROOT."inc/db_{$mybb->input['dbengine']}.php"; + switch($mybb->input['dbengine']) + { + case "sqlite": + $db = new DB_SQLite; + break; + case "pgsql": + $db = new DB_PgSQL; + break; + case "mysqli": + $db = new DB_MySQLi; + break; + default: + $db = new DB_MySQL; + } + $db->error_reporting = 0; + + $connect_array = array( + "hostname" => $config['dbhost'], + "username" => $config['dbuser'], + "password" => $config['dbpass'], + "database" => $config['dbname'], + "encoding" => $config['encoding'] + ); + + $connection = $db->connect($connect_array); + if($connection === false) + { + $errors[] = $lang->sprintf($lang->db_step_error_noconnect, $config['dbhost']); + } + // double check if the DB exists for MySQL + elseif(method_exists($db, 'select_db') && !$db->select_db($config['dbname'])) + { + $errors[] = $lang->sprintf($lang->db_step_error_nodbname, $config['dbname']); + } + + // Most DB engines only allow certain characters in the table name. Oracle requires an alphabetic character first. + if((!preg_match("#^[A-Za-z][A-Za-z0-9_]*$#", $config['tableprefix'])) && $config['tableprefix'] != '') + { + $errors[] = $lang->db_step_error_invalid_tableprefix; + } + + // Needs to be smaller then 64 characters total (MySQL Limit). + // This allows 24 characters for the actual table name, which should be sufficient. + if(strlen($config['tableprefix']) > 40) + { + $errors[] = $lang->db_step_error_tableprefix_too_long; + } + + if(($db->engine == 'mysql' || $db->engine == 'mysqli') && $config['encoding'] == 'utf8mb4' && version_compare($db->get_version(), '5.5.3', '<')) + { + $errors[] = $lang->db_step_error_utf8mb4_error; + } + + if(is_array($errors)) + { + database_info(); + } + + // Decide if we can use a database encoding or not + if($db->fetch_db_charsets() != false) + { + $db_encoding = "\$config['database']['encoding'] = '{$config['encoding']}';"; + } + else + { + $db_encoding = "// \$config['database']['encoding'] = '{$config['encoding']}';"; + } + + $config['dbpass'] = addslashes($config['dbpass']); + + // Write the configuration file + $configdata = "input['dbengine']}'; +\$config['database']['database'] = '{$config['dbname']}'; +\$config['database']['table_prefix'] = '{$config['tableprefix']}'; + +\$config['database']['hostname'] = '{$config['dbhost']}'; +\$config['database']['username'] = '{$config['dbuser']}'; +\$config['database']['password'] = '{$config['dbpass']}'; + +/** + * Admin CP directory + * For security reasons, it is recommended you + * rename your Admin CP directory. You then need + * to adjust the value below to point to the + * new directory. + */ + +\$config['admin_dir'] = 'admin'; + +/** + * Hide all Admin CP links + * If you wish to hide all Admin CP links + * on the front end of the board after + * renaming your Admin CP directory, set this + * to 1. + */ + +\$config['hide_admin_links'] = 0; + +/** + * Data-cache configuration + * The data cache is a temporary cache + * of the most commonly accessed data in MyBB. + * By default, the database is used to store this data. + * + * If you wish to use the file system (cache/ directory), MemCache (or MemCached), xcache, APC, or eAccelerator + * you can change the value below to 'files', 'memcache', 'memcached', 'xcache', 'apc' or 'eaccelerator' from 'db'. + */ + +\$config['cache_store'] = 'db'; + +/** + * Memcache configuration + * If you are using memcache or memcached as your + * data-cache, you need to configure the hostname + * and port of your memcache server below. + * + * If not using memcache, ignore this section. + */ + +\$config['memcache']['host'] = 'localhost'; +\$config['memcache']['port'] = 11211; + +/** + * Super Administrators + * A comma separated list of user IDs who cannot + * be edited, deleted or banned in the Admin CP. + * The administrator permissions for these users + * cannot be altered either. + */ + +\$config['super_admins'] = '1'; + +/** + * Database Encoding + * If you wish to set an encoding for MyBB uncomment + * the line below (if it isn't already) and change + * the current value to the mysql charset: + * http://dev.mysql.com/doc/refman/5.1/en/charset-mysql.html + */ + +{$db_encoding} + +/** + * Automatic Log Pruning + * The MyBB task system can automatically prune + * various log files created by MyBB. + * To enable this functionality for the logs below, set the + * the number of days before each log should be pruned. + * If you set the value to 0, the logs will not be pruned. + */ + +\$config['log_pruning'] = array( + 'admin_logs' => 365, // Administrator logs + 'mod_logs' => 365, // Moderator logs + 'task_logs' => 30, // Scheduled task logs + 'mail_logs' => 180, // Mail error logs + 'user_mail_logs' => 180, // User mail logs + 'promotion_logs' => 180 // Promotion logs +); + +"; + + $file = fopen(MYBB_ROOT.'inc/config.php', 'w'); + fwrite($file, $configdata); + fclose($file); + + // Error reporting back on + $db->error_reporting = 1; + + $output->print_header($lang->table_creation, 'createtables'); + echo $lang->sprintf($lang->tablecreate_step_connected, $dboptions[$mybb->input['dbengine']]['short_title'], $db->get_version()); + + if($dboptions[$mybb->input['dbengine']]['structure_file']) + { + $structure_file = $dboptions[$mybb->input['dbengine']]['structure_file']; + } + else + { + $structure_file = 'mysql_db_tables.php'; + } + + require_once INSTALL_ROOT."resources/{$structure_file}"; + foreach($tables as $val) + { + $val = preg_replace('#mybb_(\S+?)([\s\.,\(]|$)#', $config['tableprefix'].'\\1\\2', $val); + $val = preg_replace('#;$#', $db->build_create_table_collation().";", $val); + preg_match('#CREATE TABLE (\S+)(\s?|\(?)\(#i', $val, $match); + if($match[1]) + { + $db->drop_table($match[1], false, false); + echo $lang->sprintf($lang->tablecreate_step_created, $match[1]); + } + $db->query($val); + if($match[1]) + { + echo $lang->done . "
    \n"; + } + } + echo $lang->tablecreate_step_done; + $output->print_footer('populate_tables'); +} + +function populate_tables() +{ + global $output, $lang; + + require MYBB_ROOT.'inc/config.php'; + $db = db_connection($config); + + $output->print_header($lang->table_population, 'tablepopulate'); + echo $lang->sprintf($lang->populate_step_insert); + + if(!empty($dboptions[$db->type]['population_file'])) + { + $population_file = $dboptions[$db->type]['population_file']; + } + else + { + $population_file = 'mysql_db_inserts.php'; + } + + require_once INSTALL_ROOT."resources/{$population_file}"; + foreach($inserts as $val) + { + $val = preg_replace('#mybb_(\S+?)([\s\.,]|$)#', $config['database']['table_prefix'].'\\1\\2', $val); + $db->query($val); + } + + // Update the sequences for PgSQL + if($config['database']['type'] == "pgsql") + { + $db->query("SELECT setval('{$config['database']['table_prefix']}attachtypes_atid_seq', (SELECT max(atid) FROM {$config['database']['table_prefix']}attachtypes));"); + $db->query("SELECT setval('{$config['database']['table_prefix']}forums_fid_seq', (SELECT max(fid) FROM {$config['database']['table_prefix']}forums));"); + $db->query("SELECT setval('{$config['database']['table_prefix']}helpdocs_hid_seq', (SELECT max(hid) FROM {$config['database']['table_prefix']}helpdocs));"); + $db->query("SELECT setval('{$config['database']['table_prefix']}helpsections_sid_seq', (SELECT max(sid) FROM {$config['database']['table_prefix']}helpsections));"); + $db->query("SELECT setval('{$config['database']['table_prefix']}icons_iid_seq', (SELECT max(iid) FROM {$config['database']['table_prefix']}icons));"); + $db->query("SELECT setval('{$config['database']['table_prefix']}profilefields_fid_seq', (SELECT max(fid) FROM {$config['database']['table_prefix']}profilefields));"); + $db->query("SELECT setval('{$config['database']['table_prefix']}smilies_sid_seq', (SELECT max(sid) FROM {$config['database']['table_prefix']}smilies));"); + $db->query("SELECT setval('{$config['database']['table_prefix']}spiders_sid_seq', (SELECT max(sid) FROM {$config['database']['table_prefix']}spiders));"); + $db->query("SELECT setval('{$config['database']['table_prefix']}templategroups_gid_seq', (SELECT max(gid) FROM {$config['database']['table_prefix']}templategroups));"); + } + + echo $lang->populate_step_inserted; + $output->print_footer('templates'); +} + +function insert_templates() +{ + global $mybb, $output, $cache, $db, $lang; + + require MYBB_ROOT.'inc/config.php'; + $db = db_connection($config); + + require_once MYBB_ROOT.'inc/class_datacache.php'; + $cache = new datacache; + + $output->print_header($lang->theme_installation, 'theme'); + + echo $lang->theme_step_importing; + + $db->delete_query("themes"); + $db->delete_query("templates"); + $db->delete_query("themestylesheets"); + my_rmdir_recursive(MYBB_ROOT."cache/themes", array(MYBB_ROOT."cache/themes/index.html")); + + $insert_array = array( + 'title' => 'Default Templates' + ); + $templateset = $db->insert_query("templatesets", $insert_array); + + $contents = @file_get_contents(INSTALL_ROOT.'resources/mybb_theme.xml'); + if(!empty($mybb->config['admin_dir']) && file_exists(MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions_themes.php")) + { + require_once MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions.php"; + require_once MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions_themes.php"; + } + elseif(file_exists(MYBB_ROOT."admin/inc/functions_themes.php")) + { + require_once MYBB_ROOT."admin/inc/functions.php"; + require_once MYBB_ROOT."admin/inc/functions_themes.php"; + } + else + { + $output->print_error("Upewnij się, że folder /admin został poprawnie przesłany na serwer."); + } + $theme_id = import_theme_xml($contents, array("templateset" => -2, "version_compat" => 1)); + $tid = build_new_theme("Default", null, $theme_id); + + // Update our properties template set to the correct one + $query = $db->simple_select("themes", "stylesheets, properties", "tid='{$tid}'", array('limit' => 1)); + + $theme = $db->fetch_array($query); + $properties = my_unserialize($theme['properties']); + $stylesheets = my_unserialize($theme['stylesheets']); + + $properties['templateset'] = $templateset; + unset($properties['inherited']['templateset']); + + // 1.8: Stylesheet Colors + $contents = @file_get_contents(INSTALL_ROOT.'resources/mybb_theme_colors.xml'); + + require_once MYBB_ROOT."inc/class_xml.php"; + $parser = new XMLParser($contents); + $tree = $parser->get_tree(); + + if(is_array($tree) && is_array($tree['colors'])) + { + if(is_array($tree['colors']['scheme'])) + { + foreach($tree['colors']['scheme'] as $tag => $value) + { + $exp = explode("=", $value['value']); + + $properties['colors'][$exp[0]] = $exp[1]; + } + } + + if(is_array($tree['colors']['stylesheets'])) + { + $count = count($properties['disporder']) + 1; + foreach($tree['colors']['stylesheets']['stylesheet'] as $stylesheet) + { + $new_stylesheet = array( + "name" => $db->escape_string($stylesheet['attributes']['name']), + "tid" => $tid, + "attachedto" => $db->escape_string($stylesheet['attributes']['attachedto']), + "stylesheet" => $db->escape_string($stylesheet['value']), + "lastmodified" => TIME_NOW, + "cachefile" => $db->escape_string($stylesheet['attributes']['name']) + ); + + $sid = $db->insert_query("themestylesheets", $new_stylesheet); + $css_url = "css.php?stylesheet={$sid}"; + + $cached = cache_stylesheet($tid, $stylesheet['attributes']['name'], $stylesheet['value']); + + if($cached) + { + $css_url = $cached; + } + + // Add to display and stylesheet list + $properties['disporder'][$stylesheet['attributes']['name']] = $count; + $stylesheets[$stylesheet['attributes']['attachedto']]['global'][] = $css_url; + + ++$count; + } + } + } + + $db->update_query("themes", array("def" => 1, "properties" => $db->escape_string(serialize($properties)), "stylesheets" => $db->escape_string(serialize($stylesheets))), "tid = '{$tid}'"); + + echo $lang->theme_step_imported; + $output->print_footer('configuration'); +} + +function configure() +{ + global $output, $mybb, $errors, $lang; + + $output->print_header($lang->board_config, 'config'); + + echo << + function warnUser(inp, warn) + { + var parenttr = $('#'+inp.id).closest('tr'); + if(inp.value != inp.defaultValue) + { + if(!parenttr.next('.setting_peeker').length) + { + var revertlink = '
    {$lang->config_step_revert}'; + parenttr.removeClass('last').after(''+warn+revertlink+''); + } + } else { + parenttr.next('.setting_peeker').remove(); + if(parenttr.is(':last-child')) + { + parenttr.addClass('last'); + } + } + } + + function revertSetting(defval, inpid) + { + $(inpid).val(defval); + var parenttr = $(inpid).closest('tr'); + parenttr.next('.setting_peeker').remove(); + if(parenttr.is(':last-child')) + { + parenttr.addClass('last'); + } + } + + +EOF; + + // If board configuration errors + if(is_array($errors)) + { + $error_list = error_list($errors); + echo $lang->sprintf($lang->config_step_error_config, $error_list); + + $bbname = htmlspecialchars_uni($mybb->get_input('bbname')); + $bburl = htmlspecialchars_uni($mybb->get_input('bburl')); + $websitename = htmlspecialchars_uni($mybb->get_input('websitename')); + $websiteurl = htmlspecialchars_uni($mybb->get_input('websiteurl')); + $cookiedomain = htmlspecialchars_uni($mybb->get_input('cookiedomain')); + $cookiepath = htmlspecialchars_uni($mybb->get_input('cookiepath')); + $contactemail = htmlspecialchars_uni($mybb->get_input('contactemail')); + } + else + { + $bbname = 'Moje forum'; + $cookiedomain = ''; + $cookiepath = '/'; + $websitename = 'Moja witryna'; + $contactemail = ''; + + $protocol = "http://"; + if((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != "off")) + { + $protocol = "https://"; + } + + // Attempt auto-detection + if($_SERVER['HTTP_HOST']) + { + $hostname = $protocol.$_SERVER['HTTP_HOST']; + $cookiedomain = $_SERVER['HTTP_HOST']; + } + elseif($_SERVER['SERVER_NAME']) + { + $hostname = $protocol.$_SERVER['SERVER_NAME']; + $cookiedomain = $_SERVER['SERVER_NAME']; + } + + if(substr($cookiedomain, 0, 4) == "www.") + { + $cookiedomain = my_substr($cookiedomain, 4); + } + + // IP addresses and hostnames are not valid + if(my_inet_pton($cookiedomain) !== false || strpos($cookiedomain, '.') === false) + { + $cookiedomain = ''; + } + else + { + $cookiedomain = ".{$cookiedomain}"; + } + + if($_SERVER['SERVER_PORT'] && $_SERVER['SERVER_PORT'] != 80 && !preg_match("#:[0-9]#i", $hostname)) + { + $hostname .= ':'.$_SERVER['SERVER_PORT']; + } + $websiteurl = $hostname.'/'; + + $currentlocation = get_current_location(); + if($currentlocation) + { + // TODO: Change this to find the last position of /install/ + $pos = my_strpos($currentlocation, '/install/'); + if($pos === 0) + { + $cookiepath = "/"; + } + else + { + $cookiepath = my_substr($currentlocation, 0, $pos).'/'; + } + } + + $currentscript = $hostname.get_current_location(); + + if($currentscript) + { + $bburl = my_substr($currentscript, 0, my_strpos($currentscript, '/install/')); + } + + if($_SERVER['SERVER_ADMIN']) + { + $contactemail = $_SERVER['SERVER_ADMIN']; + } + } + + echo $lang->sprintf($lang->config_step_table, $bbname, $bburl, $websitename, $websiteurl, $cookiedomain, $cookiepath, $contactemail); + $output->print_footer('adminuser'); +} + +function create_admin_user() +{ + global $output, $mybb, $errors, $db, $lang; + + $mybb->input['action'] = "adminuser"; + // If no errors then check for errors from last step + if(!is_array($errors)) + { + if(empty($mybb->input['bburl'])) + { + $errors[] = $lang->config_step_error_url; + } + if(empty($mybb->input['bbname'])) + { + $errors[] = $lang->config_step_error_name; + } + if(is_array($errors)) + { + configure(); + } + } + $output->print_header($lang->create_admin, 'admin'); + + echo << + function comparePass() + { + var parenttr = $('#adminpass2').closest('tr'); + var passval = $('#adminpass2').val(); + if(passval && passval != $('#adminpass').val()) + { + if(!parenttr.next('.pass_peeker').length) + { + parenttr.removeClass('last').after('{$lang->admin_step_nomatch}'); + } + } else { + parenttr.addClass('last').next('.pass_peeker').remove(); + } + } + + +EOF; + + if(is_array($errors)) + { + $error_list = error_list($errors); + echo $lang->sprintf($lang->admin_step_error_config, $error_list); + $adminuser = $mybb->get_input('adminuser'); + $adminemail = $mybb->get_input('adminemail'); + } + else + { + require MYBB_ROOT.'inc/config.php'; + $db = db_connection($config); + + echo $lang->admin_step_setupsettings; + $adminuser = $adminemail = ''; + + $settings = file_get_contents(INSTALL_ROOT.'resources/settings.xml'); + $parser = new XMLParser($settings); + $parser->collapse_dups = 0; + $tree = $parser->get_tree(); + $groupcount = $settingcount = 0; + + // Insert all the settings + foreach($tree['settings'][0]['settinggroup'] as $settinggroup) + { + $groupdata = array( + 'name' => $db->escape_string($settinggroup['attributes']['name']), + 'title' => $db->escape_string($settinggroup['attributes']['title']), + 'description' => $db->escape_string($settinggroup['attributes']['description']), + 'disporder' => (int)$settinggroup['attributes']['disporder'], + 'isdefault' => $settinggroup['attributes']['isdefault'], + ); + $gid = $db->insert_query('settinggroups', $groupdata); + ++$groupcount; + foreach($settinggroup['setting'] as $setting) + { + $settingdata = array( + 'name' => $db->escape_string($setting['attributes']['name']), + 'title' => $db->escape_string($setting['title'][0]['value']), + 'description' => $db->escape_string($setting['description'][0]['value']), + 'optionscode' => $db->escape_string($setting['optionscode'][0]['value']), + 'value' => $db->escape_string($setting['settingvalue'][0]['value']), + 'disporder' => (int)$setting['disporder'][0]['value'], + 'gid' => $gid, + 'isdefault' => 1 + ); + + $db->insert_query('settings', $settingdata); + $settingcount++; + } + } + + if(my_substr($mybb->get_input('bburl'), -1, 1) == '/') + { + $mybb->input['bburl'] = my_substr($mybb->get_input('bburl'), 0, -1); + } + + $db->update_query("settings", array('value' => $db->escape_string($mybb->get_input('bbname'))), "name='bbname'"); + $db->update_query("settings", array('value' => $db->escape_string($mybb->get_input('bburl'))), "name='bburl'"); + $db->update_query("settings", array('value' => $db->escape_string($mybb->get_input('websitename'))), "name='homename'"); + $db->update_query("settings", array('value' => $db->escape_string($mybb->get_input('websiteurl'))), "name='homeurl'"); + $db->update_query("settings", array('value' => $db->escape_string($mybb->get_input('cookiedomain'))), "name='cookiedomain'"); + $db->update_query("settings", array('value' => $db->escape_string($mybb->get_input('cookiepath'))), "name='cookiepath'"); + $db->update_query("settings", array('value' => $db->escape_string($mybb->get_input('contactemail'))), "name='adminemail'"); + $db->update_query("settings", array('value' => 'contact.php'), "name='contactlink'"); + + write_settings(); + + echo $lang->sprintf($lang->admin_step_insertesettings, $settingcount, $groupcount); + + // Save the acp pin + $pin = addslashes($mybb->get_input('pin')); + + $file = @fopen(MYBB_ROOT."inc/config.php", "a"); + + @fwrite($file, "/** + * Admin CP Secret PIN + * If you wish to request a PIN + * when someone tries to login + * on your Admin CP, enter it below. + */ + +\$config['secret_pin'] = '{$pin}';"); + + @fclose($file); + + include_once MYBB_ROOT."inc/functions_task.php"; + $tasks = file_get_contents(INSTALL_ROOT.'resources/tasks.xml'); + $parser = new XMLParser($tasks); + $parser->collapse_dups = 0; + $tree = $parser->get_tree(); + $taskcount = 0; + + // Insert scheduled tasks + foreach($tree['tasks'][0]['task'] as $task) + { + $new_task = array( + 'title' => $db->escape_string($task['title'][0]['value']), + 'description' => $db->escape_string($task['description'][0]['value']), + 'file' => $db->escape_string($task['file'][0]['value']), + 'minute' => $db->escape_string($task['minute'][0]['value']), + 'hour' => $db->escape_string($task['hour'][0]['value']), + 'day' => $db->escape_string($task['day'][0]['value']), + 'weekday' => $db->escape_string($task['weekday'][0]['value']), + 'month' => $db->escape_string($task['month'][0]['value']), + 'enabled' => $db->escape_string($task['enabled'][0]['value']), + 'logging' => $db->escape_string($task['logging'][0]['value']) + ); + + $new_task['nextrun'] = fetch_next_run($new_task); + + $db->insert_query("tasks", $new_task); + $taskcount++; + } + + // For the version check task, set a random date and hour (so all MyBB installs don't query mybb.com all at the same time) + $update_array = array( + 'hour' => rand(0, 23), + 'weekday' => rand(0, 6) + ); + + $db->update_query("tasks", $update_array, "file = 'versioncheck'"); + + echo $lang->sprintf($lang->admin_step_insertedtasks, $taskcount); + + $views = file_get_contents(INSTALL_ROOT.'resources/adminviews.xml'); + $parser = new XMLParser($views); + $parser->collapse_dups = 0; + $tree = $parser->get_tree(); + $view_count = 0; + + // Insert admin views + foreach($tree['adminviews'][0]['view'] as $view) + { + $fields = array(); + foreach($view['fields'][0]['field'] as $field) + { + $fields[] = $field['attributes']['name']; + } + + $conditions = array(); + if(isset($view['conditions'][0]['condition']) && is_array($view['conditions'][0]['condition'])) + { + foreach($view['conditions'][0]['condition'] as $condition) + { + if(!$condition['value']) continue; + if($condition['attributes']['is_serialized'] == 1) + { + $condition['value'] = my_unserialize($condition['value']); + } + $conditions[$condition['attributes']['name']] = $condition['value']; + } + } + + $custom_profile_fields = array(); + if(isset($view['custom_profile_fields'][0]['field']) && is_array($view['custom_profile_fields'][0]['field'])) + { + foreach($view['custom_profile_fields'][0]['field'] as $field) + { + $custom_profile_fields[] = $field['attributes']['name']; + } + } + + $new_view = array( + "uid" => 0, + "type" => $db->escape_string($view['attributes']['type']), + "visibility" => (int)$view['attributes']['visibility'], + "title" => $db->escape_string($view['title'][0]['value']), + "fields" => $db->escape_string(serialize($fields)), + "conditions" => $db->escape_string(serialize($conditions)), + "custom_profile_fields" => $db->escape_string(serialize($custom_profile_fields)), + "sortby" => $db->escape_string($view['sortby'][0]['value']), + "sortorder" => $db->escape_string($view['sortorder'][0]['value']), + "perpage" => (int)$view['perpage'][0]['value'], + "view_type" => $db->escape_string($view['view_type'][0]['value']) + ); + $db->insert_query("adminviews", $new_view); + $view_count++; + } + + echo $lang->sprintf($lang->admin_step_insertedviews, $view_count); + + echo $lang->admin_step_createadmin; + } + + echo $lang->sprintf($lang->admin_step_admintable, $adminuser, $adminemail); + $output->print_footer('final'); +} + +function install_done() +{ + global $output, $db, $mybb, $errors, $cache, $lang; + + if(empty($mybb->input['adminuser'])) + { + $errors[] = $lang->admin_step_error_nouser; + } + if(empty($mybb->input['adminpass'])) + { + $errors[] = $lang->admin_step_error_nopassword; + } + if($mybb->get_input('adminpass') != $mybb->get_input('adminpass2')) + { + $errors[] = $lang->admin_step_error_nomatch; + } + if(empty($mybb->input['adminemail'])) + { + $errors[] = $lang->admin_step_error_noemail; + } + if(is_array($errors)) + { + create_admin_user(); + } + + require MYBB_ROOT.'inc/config.php'; + $db = db_connection($config); + + require MYBB_ROOT.'inc/settings.php'; + $mybb->settings = &$settings; + + ob_start(); + $output->print_header($lang->finish_setup, 'finish'); + + echo $lang->done_step_usergroupsinserted; + + // Insert all of our user groups from the XML file + $usergroup_settings = file_get_contents(INSTALL_ROOT.'resources/usergroups.xml'); + $parser = new XMLParser($usergroup_settings); + $parser->collapse_dups = 0; + $tree = $parser->get_tree(); + + $admin_gid = ''; + $group_count = 0; + foreach($tree['usergroups'][0]['usergroup'] as $usergroup) + { + // usergroup[cancp][0][value] + $new_group = array(); + foreach($usergroup as $key => $value) + { + if(!is_array($value)) + { + continue; + } + + $new_group[$key] = $db->escape_string($value[0]['value']); + } + $db->insert_query("usergroups", $new_group, false); + + // If this group can access the admin CP and we haven't established the admin group - set it (just in case we ever change IDs) + if($new_group['cancp'] == 1 && !$admin_gid) + { + $admin_gid = $usergroup['gid'][0]['value']; + } + $group_count++; + } + + // Restart usergroup sequence with correct # of groups + if($config['database']['type'] == "pgsql") + { + $db->query("SELECT setval('{$config['database']['table_prefix']}usergroups_gid_seq', (SELECT max(gid) FROM {$config['database']['table_prefix']}usergroups));"); + } + + echo $lang->done . '

    '; + + echo $lang->done_step_admincreated; + $now = TIME_NOW; + $salt = random_str(); + $loginkey = generate_loginkey(); + $saltedpw = md5(md5($salt).md5($mybb->get_input('adminpass'))); + + $newuser = array( + 'username' => $db->escape_string($mybb->get_input('adminuser')), + 'password' => $saltedpw, + 'salt' => $salt, + 'loginkey' => $loginkey, + 'email' => $db->escape_string($mybb->get_input('adminemail')), + 'usergroup' => $admin_gid, // assigned above + 'regdate' => $now, + 'lastactive' => $now, + 'lastvisit' => $now, + 'website' => '', + 'icq' => '', + 'aim' => '', + 'yahoo' => '', + 'skype' =>'', + 'google' =>'', + 'birthday' => '', + 'signature' => '', + 'allownotices' => 1, + 'hideemail' => 0, + 'subscriptionmethod' => '0', + 'receivepms' => 1, + 'pmnotice' => 1, + 'pmnotify' => 1, + 'showimages' => 1, + 'showvideos' => 1, + 'showsigs' => 1, + 'showavatars' => 1, + 'showquickreply' => 1, + 'invisible' => 0, + 'style' => '0', + 'timezone' => 0, + 'dst' => 0, + 'threadmode' => '', + 'daysprune' => 0, + 'regip' => $db->escape_binary(my_inet_pton(get_ip())), + 'language' => '', + 'showcodebuttons' => 1, + 'tpp' => 0, + 'ppp' => 0, + 'referrer' => 0, + 'buddylist' => '', + 'ignorelist' => '', + 'pmfolders' => '', + 'notepad' => '', + 'showredirect' => 1, + 'usernotes' => '' + ); + $db->insert_query('users', $newuser); + + $welcome_post_title = "Witamy w MyBB!"; + $welcome_post_message = "Dziękujemy za wybranie MyBB. Instalacja przebiegła poprawnie i Twoje forum jest gotowe do użytku. Jeżeli podczas pracy z MyBB napotkasz jakiś problem, nie bój się zapytać na forum [url=http://forum.mybboard.pl]oficjalnego Polskiego Supportu MyBB[/url]. Zachęcamy Cię także do zapoznania się z naszym [url=http://mybboard.pl]portalem[/url], gdzie możesz znaleźć najnowsze wiadomości ze świata MyBB, oraz do odwiedzenia [url=http://wiki.mybboard.pl]polskiej Wiki[/url]. Powodzenia w przygodzie z MyBB!"; + + $welcome_post = array( + 'pid' => 1, + 'tid' => 1, + 'fid' => 2, + 'subject' => $welcome_post_title, + 'uid' => 1, + 'username' => $db->escape_string($mybb->get_input('adminuser')), + 'dateline' => $now, + 'message' => $welcome_post_message, + 'ipaddress' => $db->escape_binary(my_inet_pton(get_ip())), + 'visible' => 1); + + $welcome_thread = array( + 'tid' => 1, + 'fid' => 2, + 'subject' => $welcome_post_title, + 'uid' => 1, + 'username' => $db->escape_string($mybb->get_input('adminuser')), + 'dateline' => $now, + 'firstpost' => 1, + 'lastpost' => $now, + 'lastposter' => $db->escape_string($mybb->get_input('adminuser')), + 'lastposteruid' => 1, + 'views' => 1, + 'replies' => 0, + 'notes' => '', + 'visible' => 1 + ); + + $welcome_update = array( + 'threads' => 1, + 'posts' => 1, + 'lastpost' => $now, + 'lastposter' => $db->escape_string($mybb->get_input('adminuser')), + 'lastposteruid' => 1, + 'lastposttid' => 1, + 'lastpostsubject' => $welcome_post_title + ); + + $db->insert_query('posts',$welcome_post); + $db->insert_query('threads',$welcome_thread); + $db->update_query('forums', $welcome_update, 'fid = 2'); + + echo $lang->done . '

    '; + + echo $lang->done_step_adminoptions; + $adminoptions = file_get_contents(INSTALL_ROOT.'resources/adminoptions.xml'); + $parser = new XMLParser($adminoptions); + $parser->collapse_dups = 0; + $tree = $parser->get_tree(); + $insertmodule = array(); + + $db->delete_query("adminoptions"); + + // Insert all the admin permissions + foreach($tree['adminoptions'][0]['user'] as $users) + { + $uid = $users['attributes']['uid']; + + foreach($users['permissions'][0]['module'] as $module) + { + foreach($module['permission'] as $permission) + { + $insertmodule[$module['attributes']['name']][$permission['attributes']['name']] = $permission['value']; + } + } + + $defaultviews = array(); + foreach($users['defaultviews'][0]['view'] as $view) + { + $defaultviews[$view['attributes']['type']] = $view['value']; + } + + $adminoptiondata = array( + 'uid' => (int)$uid, + 'cpstyle' => '', + 'notes' => '', + 'permissions' => $db->escape_string(serialize($insertmodule)), + 'defaultviews' => $db->escape_string(serialize($defaultviews)) + ); + + $insertmodule = array(); + + $db->insert_query('adminoptions', $adminoptiondata); + } + echo $lang->done . '

    '; + + // Automatic Login + my_unsetcookie("sid"); + my_unsetcookie("mybbuser"); + my_setcookie('mybbuser', $uid.'_'.$loginkey, null, true); + ob_end_flush(); + + // Make fulltext columns if supported + if($db->supports_fulltext('threads')) + { + $db->create_fulltext_index('threads', 'subject'); + } + if($db->supports_fulltext_boolean('posts')) + { + $db->create_fulltext_index('posts', 'message'); + } + + echo $lang->done_step_cachebuilding; + require_once MYBB_ROOT.'inc/class_datacache.php'; + $cache = new datacache; + $cache->update_version(); + $cache->update_attachtypes(); + $cache->update_smilies(); + $cache->update_badwords(); + $cache->update_usergroups(); + $cache->update_forumpermissions(); + $cache->update_stats(); + $cache->update_statistics(); + $cache->update_forums(); + $cache->update_moderators(); + $cache->update_usertitles(); + $cache->update_reportedcontent(); + $cache->update_awaitingactivation(); + $cache->update_mycode(); + $cache->update_profilefields(); + $cache->update_posticons(); + $cache->update_spiders(); + $cache->update_bannedips(); + $cache->update_banned(); + $cache->update_bannedemails(); + $cache->update_birthdays(); + $cache->update_groupleaders(); + $cache->update_threadprefixes(); + $cache->update_forumsdisplay(); + $cache->update("plugins", array()); + $cache->update("internal_settings", array('encryption_key' => random_str(32))); + $cache->update_default_theme(); + + $version_history = array(); + $dh = opendir(INSTALL_ROOT."resources"); + while(($file = readdir($dh)) !== false) + { + if(preg_match("#upgrade([0-9]+).php$#i", $file, $match)) + { + $version_history[$match[1]] = $match[1]; + } + } + sort($version_history, SORT_NUMERIC); + $cache->update("version_history", $version_history); + + // Schedule an update check so it occurs an hour ago. Gotta stay up to date! + $update['nextrun'] = TIME_NOW - 3600; + $db->update_query("tasks", $update, "tid='12'"); + + $cache->update_update_check(); + $cache->update_tasks(); + + echo $lang->done . '

    '; + + echo $lang->done_step_success; + + $written = 0; + if(is_writable('./')) + { + $lock = @fopen('./lock', 'w'); + $written = @fwrite($lock, '1'); + @fclose($lock); + if($written) + { + echo $lang->done_step_locked; + } + } + if(!$written) + { + echo $lang->done_step_dirdelete; + } + echo $lang->done_whats_next; + $output->print_footer(''); +} + +function db_connection($config) +{ + require_once MYBB_ROOT."inc/db_{$config['database']['type']}.php"; + switch($config['database']['type']) + { + case "sqlite": + $db = new DB_SQLite; + break; + case "pgsql": + $db = new DB_PgSQL; + break; + case "mysqli": + $db = new DB_MySQLi; + break; + default: + $db = new DB_MySQL; + } + + // Connect to Database + define('TABLE_PREFIX', $config['database']['table_prefix']); + + $db->connect($config['database']); + $db->set_table_prefix(TABLE_PREFIX); + $db->type = $config['database']['type']; + + return $db; +} + +function error_list($array) +{ + $string = "
      \n"; + foreach($array as $error) + { + $string .= "
    • {$error}
    • \n"; + } + $string .= "
    \n"; + return $string; +} + +function write_settings() +{ + global $db; + + $settings = ''; + $query = $db->simple_select('settings', '*', '', array('order_by' => 'title')); + while($setting = $db->fetch_array($query)) + { + $setting['value'] = str_replace("\"", "\\\"", $setting['value']); + $settings .= "\$settings['{$setting['name']}'] = \"{$setting['value']}\";\n"; + } + if(!empty($settings)) + { + $settings = " diff --git a/Upload/install/resources/adminoptions.xml b/Upload/install/resources/adminoptions.xml new file mode 100644 index 0000000..1fedf33 --- /dev/null +++ b/Upload/install/resources/adminoptions.xml @@ -0,0 +1,201 @@ + + + + + 1 + + + + 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 + 1 + 0 + 0 + 0 + 0 + 0 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 1 + + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 1 + 1 + 1 + 1 + 1 + + + 1 + 1 + 1 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + + + + 1 + + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 1 + 1 + 1 + 1 + 1 + + + 1 + 1 + 1 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + + \ No newline at end of file diff --git a/Upload/install/resources/adminviews.xml b/Upload/install/resources/adminviews.xml new file mode 100644 index 0000000..5a40cf1 --- /dev/null +++ b/Upload/install/resources/adminviews.xml @@ -0,0 +1,19 @@ + + + + <![CDATA[All Users]]> + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Upload/install/resources/index.html b/Upload/install/resources/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/install/resources/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/install/resources/language.lang.php b/Upload/install/resources/language.lang.php new file mode 100644 index 0000000..ffe959e --- /dev/null +++ b/Upload/install/resources/language.lang.php @@ -0,0 +1,373 @@ +Witaj w instalatorze MyBB {1}. Kreator instalacji MyBB wykryÅ‚, że MyBB zostaÅ‚o już zainstalowane.

    +

    Wybierz jedną z akcji poniżej:

    + +
    +

    Zaktualizuj istniejÄ…cÄ… instalacjÄ™ MyBB do wersji {1} (zalecane)

    +

    Zaktualizuj istniejącą instalację MyBB do wersji {1}, z zachowaniem istniejących wątków, postów i użytkowników.

    + +
    +
    +
    +
    + +
    +

    Zainstaluj nowÄ… kopiÄ™ MyBB

    +

    Usuń istniejące już forum i zainstaluj nową kopię MyBB.

    + +
    + +
    +
    +
    "; + +$l['mybb_incorrect_folder'] = "
    +

    Kreator instalacji MyBB wykrył, że instalator uruchomiony jest z katalogu \"Upload\".

    +

    Nie ma w tym nic złego, ale zalecane jest, aby na serwerze znajdowała się zawartość katalogu \"Upload\" a nie sam katalog.

    Aby uzyskać więcej informacji odwiedź stronę wiki.

    +
    "; + +$l['welcome_step'] = '

    Witaj w kreatorze instalacji MyBB {1}. Ten kreator pomoże Ci zainstalować i skonfigurować MyBB na Twoim serwerze.

    +

    Teraz, gdy pliki znajdują się na serwerze należy skonfigurować bazę danych i ustawienia. Poniżej znajduje się lista kroków, jakie należy wykonać, aby zainstalować MyBB.

    +
      +
    • Sprawdzenie wymagaÅ„
    • +
    • Konfiguracja silnika bazy danych
    • +
    • Utworzenie tabel w bazie danych
    • +
    • Wprowadzenie domyÅ›lnych danych
    • +
    • Zainstalowanie domyÅ›lnych stylów i szablonów
    • +
    • Utworzenie konta administratora do zarzÄ…dzania forum
    • +
    • WstÄ™pna konfiguracja forum
    • +
    +

    Po pomyślnym zakończeniu każdego z kroków naciśnij przycisk Dalej na dole strony, aby przejść do następnego kroku.

    +

    Naciśnij przycisk Dalej, aby przeczytać licencję MyBB.

    +

    (Jakie informacje zostaną wysłane?)

    '; + +$l['license_step'] = '
    +{1} +
    +

    Poprzez naciśnięcie przycisku Dalej oświadczasz, że zgadzasz się z warunkami umowy licencyjnej MyBB i zobowiązujesz się ich przestrzegać.

    '; + + +$l['req_step_top'] = '

    Zanim będzie możliwe zainstalowanie MyBB kreator sprawdzi, czy Twój serwer spełnia minimalne wymagania do instalacji.

    '; +$l['req_step_reqtable'] = '
    +
    Sprawdzenie wymagań
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Kryteria
    Wersja PHP:{1}
    Obsługiwane rozszerzenia bazy danych:{2}
    Obsługiwane rozszerzenia translacji:{3}
    Rozszerzenia PHP XML:{4}
    Plik konfiguracyjny:{5}
    Plik ustawień:{6}
    Katalog pamięci podręcznej:{7}
    Katalog z załącznikami:{8}
    Katalog z awatarami użytkowników:{9}
    +
    '; +$l['req_step_reqcomplete'] = '

    Gratulacje, Twój serwer spełnia wymagania MyBB.

    +

    Naciśnij przycisk Dalej, aby kontynuować proces instalacji.

    '; + +$l['req_step_span_fail'] = '{1}'; +$l['req_step_span_pass'] = '{1}'; + +$l['req_step_error_box'] = '

    {1}

    '; +$l['req_step_error_phpversion'] = 'Minimalna wersja PHP wymagana do instalacji MyBB to 5.2.0 lub nowsza. Posiadasz zainstalowaną wersję {1}.'; +$l['req_step_error_dboptions'] = 'MyBB wymaga zainstalowanej co najmniej jednej kompatybilnej bazy danych. Twój serwer informuje, że żadna z nich nie jest dostępna.'; +$l['req_step_error_xmlsupport'] = 'MyBB wymaga, aby PHP zostało skompilowane z obsługą danych XML. Odwiedź stronę PHP.net, aby uzyskać więcej informacji.'; +$l['req_step_error_configdefaultfile'] = 'Nazwa pliku konfiguracyjnego (inc/config.default.php) nie mogła zostać zmieniona. Zmień nazwę ręcznie z config.default.php na config.php i zezwól na zapis do tego pliku lub skontaktuj się z pomocą techniczną MyBB.'; +$l['req_step_error_configfile'] = 'Nie można zapisywać do pliku konfiguracyjnego (inc/config.php). Nadaj mu odpowiednie uprawnienia chmod i spróbuj ponownie.'; +$l['req_step_error_settingsfile'] = 'Nie można zapisywać do pliku ustawień (inc/settings.php). Nadaj mu odpowiednie uprawnienia chmod i spróbuj ponownie.'; +$l['req_step_error_cachedir'] = 'Nie można zapisywać do katalogu z pamięcią podręczną (cache/). Nadaj mu odpowiednie uprawnienia chmod i spróbuj ponownie.'; +$l['req_step_error_uploaddir'] = 'Nie można zapisywać do katalogu z plikami nadesłanymi przez użytkowników (uploads/). Nadaj mu odpowiednie uprawnienia chmod i spróbuj ponownie.'; +$l['req_step_error_avatardir'] = 'Nie można zapisywać do folderu z awatarami (uploads/avatars/). Nadaj mu odpowiednie uprawnienia chmod i spróbuj ponownie.'; +$l['req_step_error_cssddir'] = 'Nie można zapisywać do folderu z arkuszami stylów CSS (css/). Nadaj mu odpowiednie uprawnienia chmod i spróbuj ponownie.'; +$l['req_step_error_tablelist'] = '
    +

    BÅ‚Ä…d

    +

    Sprawdzenie wymagań nie powiodło się. Nie można kontynuować instalacji MyBB dopóki poniższe problemy nie zostaną naprawione:

    +{1} +
    '; + + +$l['db_step_config_db'] = '

    Nadszedł czas na ustawienie bazy danych, której MyBB będzie używało do przechowywania danych. Uzupełnij pola danymi udostępnionymi przez Twojego hostingodawcę.

    '; +$l['db_step_config_table'] = '
    +
    Konfiguracja bazy danych
    + + + + + + + + +{2} +
    Ustawienia bazy danych
    +
    +

    Po wypełnieniu wszystkich pól naciśnij przycisk Dalej.

    '; + +$l['database_settings'] = "- ustawienia bazy danych"; +$l['database_path'] = "Ścieżka do bazy danych:"; +$l['database_host'] = "Serwer bazy danych:"; +$l['database_user'] = "Nazwa użytkownika:"; +$l['database_pass'] = "Hasło:"; +$l['database_name'] = "Nazwa bazy danych:"; +$l['table_settings'] = " - ustawienia tabel"; +$l['table_prefix'] = "Prefiks tabel:"; +$l['table_encoding'] = "Kodowanie tabel:"; + +$l['db_step_error_config'] = '
    +

    BÅ‚Ä…d

    +

    Wystąpił jeden lub kilka błędów w konfiguracji bazy danych z informacjami, które podano:

    +{1} +

    Po poprawieniu odpowiednich pól możesz kontynuować instalację.

    +
    '; +$l['db_step_error_invalidengine'] = 'Wybrano niepoprawny silnik bazy danych. Wybierz silnik bazy danych z listy poniżej.'; +$l['db_step_error_noconnect'] = 'Nie można połączyć się z bazą danych na serwerze \'{1}\' z podaną nazwą użytkownika i hasłem. Czy na pewno te dane są poprawne?'; +$l['db_step_error_nodbname'] = 'Nie można wybrać bazy danych \'{1}\'. Czy na pewno baza danych o tej nazwie istnieje i podany użytkownik ma do niej dostęp?'; +$l['db_step_error_missingencoding'] = 'Nie wybrano kodowania tabel. Wybierz kodowanie przed kontynuowaniem. (Jeżeli nie masz pewności co do wyboru, wybierz \'UTF-8 Unicode\')'; +$l['db_step_error_sqlite_invalid_dbname'] = 'Nie można używać relatywnych adresów URL dla baz danych SQLite. Użyj ścieżki systemowej (na przykład: /home/user/database.db) dla bazy danych SQLite.'; +$l['db_step_error_invalid_tableprefix'] = 'W prefiksie tabel można używać tylko liter, cyfr i znaku podkreślenia (_). Popraw prefiks i spróbuj ponownie.'; +$l['db_step_error_tableprefix_too_long'] = 'Wpisany prefiks jest zbyt długi. Maksymalna długość prefiksu to 40 znaków.'; +$l['db_step_error_utf8mb4_error'] = 'Aby używać 4-bajtowego kodowania UTF-8 wymagany jest serwer MySQL w wersji 5.5.3 lub nowszej. Wybierz kodowanie, które jest kompatybilne z używanym przez ciebie serwerem MySQL.'; + +$l['tablecreate_step_connected'] = '

    Połączenie z bazą danych powiodło się.

    +

    Silnik bazy danych: {1} {2}

    +

    ZostanÄ… teraz utworzone tabele w bazie danych.

    '; +$l['tablecreate_step_created'] = 'Tworzenie tabeli {1}...'; +$l['tablecreate_step_done'] = '

    Wszystkie tabele zostały utworzone. Naciśnij przycisk Dalej, aby wypełnić je domyślnymi danymi.

    '; + +$l['populate_step_insert'] = '

    Po utworzeniu tabel należy wprowadzić do nich domyślne dane.

    '; +$l['populate_step_inserted'] = '

    Domyślne dane zostały zapisane w bazie danych. Naciśnij przycisk Dalej, aby zainstalować domyślne style i szablony.

    '; + + +$l['theme_step_importing'] = '

    Załadowano i zaimportowano plik domyślnego stylu.

    '; +$l['theme_step_imported'] = '

    Domyślny styl i szablony zostały zainstalowane. Naciśnij przycisk Dalej, aby ustawić podstawowe opcje Twojego forum.

    '; + +$l['config_step_table'] = '

    Skonfiguruj podstawowe ustawienia takie jak nazwa forum, jego adres a także informacje o Twojej stronie. Te ustawienia mogą później zostać łatwo zmienione w panelu administratora (ACP).

    +
    +
    Konfiguracja forum
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Szczegóły forum
    Informacje o stronie internetowej
    Ustawienia ciasteczek (cookie) (?)
    Dane kontaktowe
    Ustawienia zabezpieczeń

    Pozostaw to pole puste, jeśli nie zamierzasz korzystać z numeru PIN podczas logowania do panelu administratora.
    +
    + +

    Po uzupełnieniu wszystkich pól naciśnij przycisk Dalej.

    '; + +$l['config_step_error_config'] = '
    +

    BÅ‚Ä…d

    +

    Wystąpił jeden lub kilka błędów w danych konfiguracyjnych, które podano:

    +{1} +

    Po poprawieniu odpowiednich pól możesz kontynuować instalację.

    +
    '; +$l['config_step_error_url'] = 'Nie podano adresu forum.'; +$l['config_step_error_name'] = 'Nie podano nazwy forum.'; +$l['config_step_revert'] = 'Kliknij aby przywrócić wstępne wartości.'; + + +$l['admin_step_setupsettings'] = '

    Zapisano wstępną konfigurację.

    '; +$l['admin_step_insertesettings'] = '

    Zapisano {1} ustawień w {2} grupach.

    +

    Zaktualizowano ustawienia danymi podanymi przez użytkownika.

    '; +$l['admin_step_insertedtasks'] = '

    Zapisano {1} zaplanowanych zadań.

    '; +$l['admin_step_insertedviews'] = '

    Zapisano {1} widoków panelu administratora.

    '; +$l['admin_step_createadmin'] ='

    Należy utworzyć konto administratora do zarządzania forum. Wypełnij poniższy formularz, aby to uczynić.

    '; +$l['admin_step_admintable'] = '
    +
    Szczegóły konta administratora
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Szczegóły
    Dane kontaktowe
    +
    + +

    Po uzupełnieniu wszystkich pól naciśnij przycisk Dalej.

    '; + +$l['admin_step_error_config'] = '
    +

    BÅ‚Ä…d

    +

    Wystąpił jeden lub kilka błędów w danych konta administratora, które podano:

    +{1} +

    Po poprawieniu odpowiednich pól możesz kontynuować instalację.

    +
    '; +$l['admin_step_error_nouser'] = 'Nie podano nazwy użytkownika.'; +$l['admin_step_error_nopassword'] = 'Nie podano hasła dla konta administratora.'; +$l['admin_step_error_nomatch'] = 'Podane hasła nie są jednakowe.'; +$l['admin_step_error_noemail'] = 'Nie podano adresu email dla konta administratora.'; +$l['admin_step_nomatch'] = 'Powtórzone hasło nie jest identyczne z tym wpisanym w pierwszym polu. Popraw je aby kontynuować.'; + +$l['done_step_usergroupsinserted'] = "

    Importowanie grup użytkowników -"; +$l['done_step_admincreated'] = '

    Tworzenie konta administratora -'; +$l['done_step_adminoptions'] = '

    Zapisywanie uprawnień administratora -'; +$l['done_step_cachebuilding'] = '

    Tworzenie pamięci podręcznej -'; +$l['done_step_success'] = '

    MyBB zostało poprawnie zainstalowane i skonfigurowane.

    +

    Dziękujemy za wybranie MyBB. Mamy nadzieję, że zechcesz dołączyć do grona społeczności skupionej wokół MyBB. Jeżeli szukasz pomocy w swoim ojczystym języku odwiedź Polski Support MyBB.

    '; +$l['done_step_locked'] = '

    Instalator został zablokowany. Aby go odblokować usuń plik \'lock\' z folderu instalatora.

    Możesz teraz przejść do strony głównej swojego forum lub panelu administratora.

    '; +$l['done_step_dirdelete'] = '

    Usuń ten katalog przed przeglądaniem swojego forum.

    '; +$l['done_whats_next'] = '

    Przenosisz siÄ™ z innego silnika?

    MyBB oferuje pakiet, który umożliwia łatwe przenoszenie danych z innych silników, a także łączenie wielu forów w jedno. Jeśli dopiero zamierzasz dokonać konwersji, szukasz w dobrym miejscu. Odwiedź stronę systemu Merge System aby uzyskać więcej informacji.

    '; + +/* UPGRADE LANGUAGE VARIABLES */ +$l['upgrade'] = "Aktualizacja"; +$l['upgrade_welcome'] = "

    Witaj w kreatorze aktualizacji MyBB {1}.

    Przed kontynuowaniem upewnij się, że znasz wersję MyBB z której chcesz dokonać aktualizacji.

    Zalecane jest wykonanie pełnej kopii bazy danych zanim przystąpisz do procesu aktualizacji. W przypadku, gdy coś pójdzie nie tak, będzie można łatwo przywrócić forum do poprzedniego stanu. Upewnij się, że Twoje kopie zapasowe są kompletne.

    Naciśnij przycisk Dalej dokładnie JEDEN RAZ, aby rozpocząć proces aktualizacji. Załadowanie strony może zająć trochę czasu w zależności od wielkości Twojego forum.

    Wybierz posiadaną aktualnie wersję MyBB i kliknij przycisk Dalej, aby kontynuować.

    "; +$l['upgrade_templates_reverted'] = 'Przywrócono szablony'; +$l['upgrade_templates_reverted_success'] = "

    Niektóre szablony zostały zastąpione przez te dostępne w tej wersji. Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "; +$l['upgrade_settings_sync'] = 'Synchronizacja ustawień'; +$l['upgrade_settings_sync_success'] = "

    Ustawienia forum zostały zsynchronizowane z tymi dostępnymi w najnowszej wersji MyBB.

    Wprowadzono {1} nowych ustawień do {2} grup.

    Aby zakończyć proces aktualizacji naciśnij przycisk Dalej.

    "; +$l['upgrade_datacache_building'] = 'Tworzenie pamięci podręcznej'; +$l['upgrade_building_datacache'] = '

    Tworzenie nowej pamięci podręcznej...'; +$l['upgrade_continue'] = 'Naciśnij przycisk Dalej, aby kontynuować'; +$l['upgrade_locked'] = "

    Instalator został zablokowany. Aby go odblokować, usuń plik 'lock' z folderu instalatora.

    Możesz teraz przejść do strony głównej swojego forum lub panelu administratora.

    "; +$l['upgrade_removedir'] = 'Usuń ten katalog przed przeglądaniem zaktualizowanej wersji MyBB.'; +$l['upgrade_congrats'] = "

    MyBB zostało zaktualizowane do wersji {1}.

    {2}

    Co dalej?

    • Użyj narzÄ™dzia 'Znajdź zmienione' w sekcji Style i szablony w panelu administratora, aby odnaleźć szablony przywrócone do wersji pierwotnej podczas procesu aktualizacji. Możesz je zmienić wedÅ‚ug wÅ‚asnych potrzeb lub przywrócić do stanu oryginalnego.
    • Upewnij siÄ™, że forum jest w peÅ‚ni funkcjonalne.
    "; +$l['upgrade_template_reversion'] = "Ostrzeżenie procesu przywracania szablonów"; +$l['upgrade_template_reversion_success'] = "

    Wszystkie potrzebne zmiany w bazie danych zostały wykonane.

    Ten proces aktualizacji wymaga, aby wszystkie szablony zostały zamienione na te dostępne w paczce z aktualizacją. Wykonaj kopię zmienionych szablonów przed kliknięciem przycisku Dalej."; +$l['upgrade_send_stats'] = "

    (Jakie informacje zostaną wysłane?)

    "; + +$l['please_login'] = "Wymagane zalogowanie"; +$l['login'] = "Zaloguj się"; +$l['login_desc'] = "Wpisz login i hasło, aby rozpocząć proces aktualizacji. Do wykonania tej operacji wymagane jest posiadanie praw administratora."; +$l['login_username'] = "Login"; +$l['login_password'] = "Hasło"; +$l['login_password_desc'] = "Wielkość liter ma znaczenie."; + +/* Error messages */ +$l['development_preview'] = "

    Ostrzeżenie

    Ta wersja MyBB jest oznaczona jako developer preview i powinna być używana jedynie w celach testowych.

    W związku z tym oficjalne wsparcie techniczne dla tej wersji MyBB, oprócz używanych wtyczek i styli, nie jest zapewnione. Poprzez kontynuowanie instalacji/aktualizacji godzisz się na korzystanie z forum na własne ryzyko.

    "; +$l['locked'] = 'Instalator jest zablokowany. Aby go odblokować usuń plik \'lock\' z folderu instalatora'; +$l['no_permision'] = "Do wykonania tej operacji wymagane są uprawnienia administratora, których nie posiadasz.

    Jeśli chcesz spróbować ponownie, wyloguj się i zaloguj ponownie na konto z uprawnieniami administratora."; + +$l['task_versioncheck_ran'] = "Zadanie sprawdzania aktualności wersji zostało pomyślnie uruchomione."; + + diff --git a/Upload/install/resources/mybb_theme.xml b/Upload/install/resources/mybb_theme.xml new file mode 100644 index 0000000..62c2521 --- /dev/null +++ b/Upload/install/resources/mybb_theme.xml @@ -0,0 +1,13947 @@ + + + + + + + + + + + + .expcolimage { + margin-top: 0; +} + +blockquote { + border: 1px solid #ccc; + margin: 0; + background: #fff; + padding: 10px; +} + +blockquote cite { + font-weight: bold; + border-bottom: 1px solid #ccc; + font-style: normal; + display: block; + padding-bottom: 3px; + margin: 0 0 10px 0; +} + +blockquote cite span { + float: right; + font-weight: normal; + font-size: 12px; + color: #666; +} + +blockquote cite span.highlight { + float: none; + font-weight: bold; + padding-bottom: 0; +} + +.codeblock { + background: #fff; + border: 1px solid #ccc; + padding: 10px; +} + +.codeblock .title { + border-bottom: 1px solid #ccc; + font-weight: bold; + padding-bottom: 3px; + margin: 0 0 10px 0; +} + +.codeblock code { + overflow: auto; + height: auto; + max-height: 200px; + display: block; + font-family: Monaco, Consolas, Courier, monospace; + font-size: 13px; +} + +.smilie { + vertical-align: middle; +} + +.smilie_pointer { + cursor: pointer; +} + +.separator { + margin: 5px; + padding: 0; + height: 0px; + font-size: 1px; + list-style-type: none; +} + +.popup_menu .popup_item_container { + margin: 1px; + text-align: left; +} + +.popup_menu .popup_item { + display: block; + padding: 4px; + white-space: nowrap; + text-decoration: none; +} + +.popup_menu a.popup_item:hover { + text-decoration: none; +} + +.subject_new { + font-weight: bold; +} + +.highlight { + background: #FFFFCC; + padding-top: 3px; + padding-bottom: 3px; +} + +.pm_alert { + background: #FFF6BF; + border: 1px solid #FFD324; + text-align: center; + padding: 5px 20px; + margin-bottom: 15px; + font-size: 11px; +} + +.red_alert { + background: #FBE3E4; + border: 1px solid #A5161A; + color: #A5161A; + text-align: center; + padding: 5px 20px; + margin-bottom: 15px; + font-size: 11px; + word-wrap: break-word; +} + +.red_alert a:link, +.red_alert a:visited, +.red_alert a:hover, +.red_alert a:active { + color: #A5161A; +} + +.high_warning { + color: #CC0000; +} + +.moderate_warning { + color: #F3611B; +} + +.low_warning { + color: #AE5700; +} + +.online { + color: #15A018; +} + +.offline { + color: #C7C7C7; +} + +div.error { + padding: 5px 10px; + border-top: 2px solid #FFD324; + border-bottom: 2px solid #FFD324; + background: #FFF6BF; + font-size: 12px; +} + +div.error p { + margin: 0; + color: #333; + font-weight: normal; +} + +div.error p em { + font-style: normal; + font-weight: bold; + padding-left: 24px; + display: block; + color: #C00; + background: url(images/error.png) no-repeat 0; +} + +div.error ul { + margin-left: 24px; +} + +.pagination { + font-size: 11px; + padding-top: 10px; + margin-bottom: 5px; +} + +.tfoot .pagination, +.tcat .pagination { + padding-top: 0; +} + +.pagination .pages { + font-weight: bold; +} + +.pagination .pagination_current, +.pagination a { + padding: 3px 6px; + margin-bottom: 3px; +} + +.pagination a { + background: #f5f5f5; + border: 1px solid #ccc; +} + +.pagination .pagination_current { + background: none; + color: #333; + border: none; + font-weight: bold; +} + +.pagination a:hover { + background: #0072BC; + color: #fff; + border-color: #263c30; + text-decoration: none; +} + +.pagination .go_page img { + margin-bottom: -4px; +} + +.drop_go_page { + background: #f5f5f5; + padding: 4px; +} + +.pagination_breadcrumb { + background-color: #efefef; + border: 1px solid #fff; + outline: 1px solid #ccc; + padding: 5px; + margin-top: 5px; + font-weight: normal; +} + +.pagination_breadcrumb_link { + vertical-align: middle; + cursor: pointer; +} + +.thread_legend, +.thread_legend dd { + margin: 0; + padding: 0; +} + +.thread_legend dd { + padding-bottom: 4px; + margin-right: 15px; +} + +.thread_legend img { + margin-right: 4px; + vertical-align: bottom; +} + +.forum_legend, +.forum_legend dt, +.forum_legend dd { + margin: 0; + padding: 0; +} + +.forum_legend dd { + float: left; + margin-right: 10px; + margin-top: 7px; +} + +.forum_legend dt { + margin-right: 10px; + float: left; +} + +.success_message { + color: #00b200; + font-weight: bold; + font-size: 10px; + margin-bottom: 10px; +} + +.error_message { + color: #C00; + font-weight: bold; + font-size: 10px; + margin-bottom: 10px; +} + +#posts_container { + padding: 0; +} + +.ignored_post { + border-top: 3px solid #333; + padding: 15px; +} + +.ignored_post .show_ignored_post { + margin-top: -15px; +} + +.ignored_post .show_ignored_post a.button span { + background-position: 0 -400px; +} + +.post { + overflow: hidden; +} + +.post.classic { + padding-top: 15px; +} + +.post .post_author { + border-bottom: 1px solid #ccc; + border-top: 2px solid #ccc; + background: #f5f5f5; + padding: 5px; + overflow: hidden; +} + +.post.classic .post_author { + border: 1px solid #ddd; + float: left; + width: 15%; + margin: 0 1% 15px 0; + border-left: 0; + padding: 5px 1%; +} + +.post .post_author .buddy_status { + vertical-align: middle; + margin-top: -4px; +} + +.post .post_author div.author_avatar { + float: left; + margin-right: 3px; +} + +.post.classic .post_author div.author_avatar { + float: none; + text-align: center; + margin-bottom: 8px; +} + +.post .post_author div.author_avatar img { + padding: 5px; + border: 1px solid #ddd; + background: #fff; +} + +.post .post_author div.author_information { + float: left; + padding: 6px 8px; +} + +.post.classic .post_author div.author_information { + float: none; + padding: 0; + text-align: center; +} + +.post .post_author div.author_statistics { + float: right; + font-size: 11px; + padding: 3px 10px 3px 5px; + color: #666; + line-height: 1.3; +} + +.post.classic .post_author div.author_statistics { + border-top: 1px dotted #ccc; + margin: 6px 0 0 0; + padding: 6px 6px 3px 6px; + float: none; +} + +.post .post_head { + font-size: 11px; + padding-bottom: 4px; + border-bottom: 1px dotted #ddd; + margin-bottom: 4px; +} + +.post .post_head span.post_date { + color: #666; +} + +.post .post_head span.edited_post { + font-size: 10px; + color: #999; +} + +.post .post_head span.edited_post a { + color: #666; +} + +.post_body { + font-size: 14px; + padding: 12px 0; +} + +.post.classic .post_content { + float: left; + width: 79%; + padding: 0 1% 5px 1%; +} + +.post_content { + padding: 9px 10px 5px 10px; +} + +.post_content .signature { + margin-top: 5px; + border-top: 1px dotted #ddd; + padding: 10px 0 4px 0; +} + +.post .post_meta { + margin: 4px 0; + font-size: 11px; + color: #999; +} + +.post .post_meta a:link, +.post .post_meta a:visited { + color: #777; +} + +.post .post_meta a:hover, +.post .post_meta a:active { + color: #777; +} + +.post_controls { + clear: both; + background: #f5f5f5; + border-bottom: 1px solid #ccc; + padding: 5px; + overflow: hidden; +} + +.postbit_buttons > a:link, +.postbit_buttons > a:hover, +.postbit_buttons > a:visited, +.postbit_buttons > a:active { + display: inline-block; + padding: 2px 5px; + margin: 2px; + font-size: 11px; + background: #eee url(images/buttons_bg.png) repeat-x; + border: 1px solid #ccc; + color: #555; +} + +.postbit_buttons > a:hover { + border-color: #bbb; +} + +.postbit_buttons a span { + padding-left: 20px; + display: inline-block; + height: 16px; + background-image: url(images/buttons_sprite.png); + background-repeat: no-repeat; +} + +.postbit_buttons a.postbit_find span { + background-position: 0 0; +} + +.postbit_buttons a.postbit_reputation_add span { + background-position: 0 -20px; +} + +.postbit_buttons a.postbit_email span { + background-position: 0 -40px; +} + +.postbit_buttons a.postbit_website span { + background-position: 0 -60px; +} + +.postbit_buttons a.postbit_pm span { + background-position: 0 -80px; +} + +.postbit_buttons a.postbit_quote span { + background-position: 0 -100px; +} + +.postbit_buttons a.postbit_multiquote span { + background-position: 0 -120px; +} + +.postbit_buttons a.postbit_multiquote_on span { + background-position: 0 -140px; +} + +.postbit_buttons a.postbit_edit span { + background-position: 0 -160px; +} + +.postbit_buttons a.postbit_qdelete span { + background-position: 0 -180px; +} + +.postbit_buttons a.postbit_qrestore span { + background-position: 0 -200px; +} + +.postbit_buttons a.postbit_report span { + background-position: 0 -220px; +} + +.postbit_buttons a.postbit_warn span { + background-position: 0 -240px; +} + +.postbit_buttons a.postbit_purgespammer span { + background-position: 0 -540px; +} + +.postbit_buttons a.postbit_reply_pm span { + background-position: 0 -260px; +} + +.postbit_buttons a.postbit_reply_all span { + background-position: 0 -280px; +} + +.postbit_buttons a.postbit_forward_pm span { + background-position: 0 -300px; +} + +.postbit_buttons a.postbit_delete_pm span { + background-position: 0 -320px; +} + +a.button:link, +a.button:hover, +a.button:visited, +a.button:active { + background: #0f0f0f url(images/tcat.png) repeat-x; + color: #fff; + display: inline-block; + padding: 4px 8px; + margin: 2px 2px 6px 2px; + border: 1px solid #000; + font-size: 14px; +} + +a.button.small_button { + font-size: 13px; + margin: 0; + padding: 3px 6px; +} + +a.button span { + padding-left: 20px; + display: inline-block; + background-image: url(images/buttons_sprite.png); + background-repeat: no-repeat; +} + +a.button.new_thread_button span { + background-position: 0 -340px; +} + +a.button.new_reply_button span { + background-position: 0 -360px; +} + +a.button.closed_button span { + background-position: 0 -380px; +} + +a.button.rate_user_button span { + background-position: 0 -400px; +} + +a.button.add_buddy_button span { + background-position: 0 -440px; +} + +a.button.remove_buddy_button span { + background-position: 0 -480px; +} + +a.button.add_ignore_button span { + background-position: 0 -460px; +} + +a.button.remove_ignore_button span { + background-position: 0 -500px; +} + +a.button.report_user_button span { + background-position: 0 -520px; +} + +.quick_jump { + background: url(images/jump.png) no-repeat 0; + width: 13px; + height: 13px; + padding-left: 13px; /* amount of padding needed for image to fully show */ + margin-top: -3px; + border: none; +} + +.pollbar { + background: url(images/pollbar.png) top left repeat-x; + border: 1px solid #3f3f3f; + height: 10px; +} + +.pollbar .percent { + display: none; +} + +.posticons_label { + white-space: nowrap; +} + +/** jGrowl Start **/ + +/** Special IE6 Style Positioning **/ +.ie6 { + position: absolute; +} + +.ie6.top-right { + right: auto; + bottom: auto; + left: expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +.ie6.top-left { + left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +.ie6.bottom-right { + left: expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +.ie6.bottom-left { + left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +.ie6.center { + left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); + width: 100%; +} + +/** jGrowl Styling **/ +.jGrowl { + z-index: 9999; + color: #fff; + font-size: 12px; + position: fixed; +} + +.jGrowl.top-left { + left: 0px; + top: 0px; +} + +.jGrowl.top-right { + right: 0px; + top: 0px; +} + +.jGrowl.bottom-left { + left: 0px; + bottom: 0px; +} + +.jGrowl.bottom-right { + right: 0px; + bottom: 0px; +} + +.jGrowl.center { + top: 0px; + width: 50%; + left: 25%; +} + +/** Cross Browser Styling **/ + +.center .jGrowl-notification, +.center .jGrowl-closer { + margin-left: auto; + margin-right: auto; +} + +.jGrowl .jGrowl-notification, +.jGrowl .jGrowl-closer { + background-color: #000; + opacity: .85; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=85); + zoom: 1; + width: 235px; + padding: 10px; + margin-top: 5px; + margin-bottom: 5px; + font-family: Tahoma, Arial, Helvetica, sans-serif; + font-size: 1em; + text-align: left; + display: none; + border-radius: 5px; +} + +.jGrowl .jGrowl-notification { + min-height: 40px; +} + +.jGrowl .jGrowl-notification, +.jGrowl .jGrowl-closer { + margin: 10px; +} + +.jGrowl .jGrowl-notification .jGrowl-header { + font-weight: bold; + font-size: .85em; +} + +.jGrowl .jGrowl-notification .jGrowl-close { + z-index: 99; + float: right; + font-weight: bold; + font-size: 1em; + cursor: pointer; +} + +.jGrowl .jGrowl-closer { + padding-top: 4px; + padding-bottom: 4px; + cursor: pointer; + font-size: .9em; + font-weight: bold; + text-align: center; +} + +/** Hide jGrowl when printing **/ +@media print { + .jGrowl { + display: none; + } +} + +/** jGrowl End **/ + +/** Modal Start **/ + +.modal { + display: none; + width: 400px; + text-align: left; + background: #fff; + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + -o-border-radius: 8px; + -ms-border-radius: 8px; + border-radius: 8px; + -webkit-box-shadow: 0 0 10px #000; + -moz-box-shadow: 0 0 10px #000; + -o-box-shadow: 0 0 10px #000; + -ms-box-shadow: 0 0 10px #000; + box-shadow: 0 0 10px #000; +} + +.modal a.close-modal { + position: absolute; + top: -12.5px; + right: -12.5px; + display: block; + width: 30px; + height: 30px; + text-indent: -9999px; + background: url(images/close.png) no-repeat 0 0; +} + +.modal-spinner { + display: none; + width: 64px; + height: 64px; + position: fixed; + top: 50%; + left: 50%; + margin-right: -32px; + margin-top: -32px; + background: url(images/spinner_big.gif) no-repeat center center; + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + -o-border-radius: 8px; + -ms-border-radius: 8px; + border-radius: 8px; +} + +/** Modal End **/ + +/** Impromptu Start **/ + +/*! jQuery-Impromptu - v5.2.4 - 2014-05-26 +* http://trentrichardson.com/Impromptu +* Copyright (c) 2014 Trent Richardson; Licensed MIT */ + +.jqifade { + position: absolute; + background-color: #777777; +} + +div.jqi { + width: 400px; + max-width:90%; + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + position: absolute; + background-color: #ffffff; + font-size: 11px; + text-align: left; + border: solid 1px #eeeeee; + border-radius: 6px; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + padding: 7px; +} + +div.jqi .jqiclose { + position: absolute; + top: 4px; right: -2px; + width: 18px; + cursor: default; + color: #bbbbbb; + font-weight: bold; +} + +div.jqi .jqistate { + background-color: #fff; +} + +div.jqi .jqititle { + padding: 5px 10px; + font-size: 16px; + line-height: 20px; + border-bottom: solid 1px #eeeeee; +} + +div.jqi .jqimessage { + padding: 10px; + line-height: 20px; + color: #444444; +} + +div.jqi .jqibuttons { + text-align: right; + margin: 0 -7px -7px -7px; + border-top: solid 1px #e4e4e4; + background-color: #f4f4f4; + border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + -webkit-border-radius: 0 0 6px 6px; +} + +div.jqi .jqibuttons button { + margin: 0; + padding: 6px 20px; + background-color: transparent; + font-weight: normal; + border: none; + border-left: solid 1px #e4e4e4; + color: #777; + font-weight: bold; + font-size: 12px; +} + +div.jqi .jqibuttons button.jqidefaultbutton { + color: #489afe; +} + +div.jqi .jqibuttons button:hover, +div.jqi .jqibuttons button:focus { + color: #287ade; + outline: none; +} + +.jqiwarning .jqi .jqibuttons { + background-color: #b95656; +} + +/* sub states */ + +div.jqi .jqiparentstate::after { + background-color: #777; + opacity: 0.6; + filter: alpha(opacity=60); + content: ''; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + border-radius: 6px; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; +} + +div.jqi .jqisubstate { + position: absolute; + top: 0; + left: 20%; + width: 60%; + padding: 7px; + border: solid 1px #eeeeee; + border-top: none; + border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + -webkit-border-radius: 0 0 6px 6px; +} + +div.jqi .jqisubstate .jqibuttons button { + padding: 10px 18px; +} + +/* arrows for tooltips/tours */ + +.jqi .jqiarrow { + position: absolute; + height: 0; width: 0; + line-height: 0; + font-size: 0; + border: solid 10px transparent; +} + +.jqi .jqiarrowtl { + left: 10px; + top: -20px; + border-bottom-color: #ffffff; +} + +.jqi .jqiarrowtc { + left: 50%; + top: -20px; + border-bottom-color: #ffffff; + margin-left: -10px; +} + +.jqi .jqiarrowtr { + right: 10px; + top: -20px; + border-bottom-color: #ffffff; +} + +.jqi .jqiarrowbl { + left: 10px; + bottom: -20px; + border-top-color: #ffffff; +} + +.jqi .jqiarrowbc { + left: 50%; + bottom: -20px; + border-top-color: #ffffff; + margin-left: -10px; +} + +.jqi .jqiarrowbr { + right: 10px; + bottom: -20px; + border-top-color: #ffffff; +} + +.jqi .jqiarrowlt { + left: -20px; + top: 10px; + border-right-color: #ffffff; +} + +.jqi .jqiarrowlm { + left: -20px; + top: 50%; + border-right-color: #ffffff; + margin-top: -10px; +} + +.jqi .jqiarrowlb { + left: -20px; + bottom: 10px; + border-right-color: #ffffff; +} + +.jqi .jqiarrowrt { + right: -20px; + top: 10px; + border-left-color: #ffffff; +} + +.jqi .jqiarrowrm { + right: -20px; + top: 50%; + border-left-color: #ffffff; + margin-top: -10px; +} + +.jqi .jqiarrowrb { + right: -20px; + bottom: 10px; + border-left-color: #ffffff; +} + +/** Impromptu End */ +]]> + + + + + + + a, +a.button { + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; +} + +.post.classic .post_author { + -moz-border-radius: 0 6px 6px 0; + -webkit-border-radius: 0 6px 6px 0; + border-radius: 0 6px 6px 0; +} + +.popup_menu .popup_item_container:first-child .popup_item { + -moz-border-radius-topleft: 6px; + -moz-border-radius-topright: 6px; + -webkit-border-top-left-radius: 6px; + -webkit-border-top-right-radius: 6px; + border-top-left-radius: 6px; + border-top-right-radius: 6px; +} + +.popup_menu .popup_item_container:last-child .popup_item { + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-bottomright: 6px; + -webkit-border-bottom-left-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; +} + +.pagination a { + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; +} + +.pollbar { + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; +}]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Upload/install/resources/mybb_theme_colors.xml b/Upload/install/resources/mybb_theme_colors.xml new file mode 100644 index 0000000..d04103b --- /dev/null +++ b/Upload/install/resources/mybb_theme_colors.xml @@ -0,0 +1,519 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Upload/install/resources/mysql_db_inserts.php b/Upload/install/resources/mysql_db_inserts.php new file mode 100644 index 0000000..464a361 --- /dev/null +++ b/Upload/install/resources/mysql_db_inserts.php @@ -0,0 +1,177 @@ +tutaj.', 1, 1, 3);"; +$inserts[] = "INSERT INTO mybb_helpdocs (hid, sid, name, description, document, usetranslation, enabled, disporder) VALUES (4, 1, 'Logowanie i wylogowywanie', 'Jak się zalogować i wylogować.', 'Gdy się zalogujesz, ciasteczka na Twoim komputerze zostaną ustawione tak, abyś mógł przeglądać forum zalogowany bez ciągłej potrzeby logowania. Wylogowanie czyści Twoje ciasteczka dotyczące logowania. Aby zalogować, kliknij [Logowanie] u góry, pod nawigacją. Aby się wylogować, kliknij [Wyloguj] w tym samym miejscu. Wyczyszczenie ciasteczek w Twojej przeglądarce da ten sam efekt.', 1, 1, 4);"; +$inserts[] = "INSERT INTO mybb_helpdocs (hid, sid, name, description, document, usetranslation, enabled, disporder) VALUES (5, 2, 'Pisanie nowego wątku', 'Rozpoczynanie wątku na forum.', 'Jeśli chcesz utworzyć nowy wątek na forum, wybierz dział w którym chcesz go napisać, a następnie kliknij na przycisk [Nowy wątek]. Jeśli zobaczysz komunikat \"Nie masz uprawnień\" oznacza to, że nie masz uprawnień na pisanie w danym dziale.', 1, 1, 1);"; +$inserts[] = "INSERT INTO mybb_helpdocs (hid, sid, name, description, document, usetranslation, enabled, disporder) VALUES (6, 2, 'Odpowiadanie w wątku', 'Odpowiadanie na forum.', 'Wybierz wątek, w którym chcesz odpowiedzieć. Kliknij na przycisk [Odpowiedz] znajdujący się u góry ekranu. Pamiętaj również, że administrator mógł nałożyć restrykcje, więc możliwe, że nie będziesz mieć możliwości odpowiadania w niektórych działach. Moderator może usunąć wątek, w którym przez określony czas nie będzie odpowiedzi.', 1, 1, 2);"; +$inserts[] = "INSERT INTO mybb_helpdocs (hid, sid, name, description, document, usetranslation, enabled, disporder) VALUES (7, 2, 'MyCode', 'Wszystko o MyCode.', 'Możesz używać MyCode - to uproszczona wersja HTML.

    \n\r[b]Pogrubiony tekst[/b]\n\r   Pogrubiony tekst

    [i]Kursywa[/i]\n\r   Kursywa

    [u]PodkreÅ›lenie[/u]\n\r   PodkreÅ›lenie

    [s]PrzekreÅ›lenie[/s]\n\r   PrzekreÅ›lenie

    \n\r[url]http://www.przykladowy.adres.pl/[/url]\n\r   http://www.przykladowy.adres.pl/

    [url=http://www.strona.pl/]TytuÅ‚[/url]\n\r   TytuÅ‚

    [email]mojemail@serwer.pl[/email]\n\r   mojemail@serwer.pl

    [email=mojemail@serwer.pl]Napisz do mnie![/email]\n\r   Napisz do mnie!

    [email=mojemail@serwer.pl?subject=temat]e-mail z tematem[/email]\n\r   email z tematem

    \n\r[quote]Cytat[/quote]\n\r   Cytat

    [code]kod[/code]\n\r   kod

    \n\r[img]http://www.php.net/images/php.gif[/img]\n\r   

    [img=50x50]http://www.php.net/images/php.gif[/img]\n\r   

    \n\r[color=red]Czerwony kolor[/color]\n\r   Czerwony kolor

    [size=medium]Rozmiar medium[/size]\n\r   Rozmiar medium

    [font=Tahoma]Czcionka Tahoma[/font]\n\r   Czcionka Tahoma

    \n\r[align=center]Wycentrowany[/align]

    Wycentrowany

    [align=right]Wyrównany do prawej[/align]

    Wyrównany do prawej

    \n\r[list]
    [*]Punkt #1\n\r[*]Punkt #2\n\r[*]Punkt #3\n\r[/list]\n\r

    • Punkt #1
    • Punkt #2
    • Punkt #3

    Możesz również ustalić typ punktowania - dostępne typy: liczbowy [list=1] i alfabetyczny [list=a].

    ', 1, 1, 3);"; + +$inserts[] = "INSERT INTO mybb_helpsections (sid, name, description, usetranslation, enabled, disporder) VALUES (1, 'Rejestracja i podstawy', 'Podstawowe informacje, pomocne w rejestracji i tworzeniu profilu.', 1, 1, 1);"; +$inserts[] = "INSERT INTO mybb_helpsections (sid, name, description, usetranslation, enabled, disporder) VALUES (2, 'Pisanie', 'Podstawy używania forum - tworzenie wątków, odpowiadanie itp.', 1, 1, 2);"; + +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(1, 'Błąd', 'images/icons/bug.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(2, 'Ostrzeżenie', 'images/icons/exclamation.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(3, 'Pytanie', 'images/icons/question.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(4, 'Uśmiech', 'images/icons/smile.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(5, 'Smutek', 'images/icons/sad.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(6, 'Oczko', 'images/icons/wink.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(7, 'Duży uśmiech', 'images/icons/biggrin.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(8, 'Język', 'images/icons/tongue.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(9, 'Kostka', 'images/icons/brick.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(10, 'Serce', 'images/icons/heart.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(11, 'Informacja', 'images/icons/information.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(12, 'Żarówka', 'images/icons/lightbulb.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(13, 'Muzyka', 'images/icons/music.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(14, 'Zdjęcie', 'images/icons/photo.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(15, 'Tęcza', 'images/icons/rainbow.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(16, 'Szok', 'images/icons/shocked.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(17, 'Gwiazdka', 'images/icons/star.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(18, 'Kciuk w górę', 'images/icons/thumbsdown.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(19, 'Kciuk w dół', 'images/icons/thumbsup.png');"; +$inserts[] = "INSERT INTO mybb_icons (iid, name, path) VALUES(20, 'Wideo', 'images/icons/video.png');"; + +$inserts[] = "INSERT INTO mybb_profilefields (fid, name, description, disporder, type, regex, length, maxlength, required, registration, profile, postbit, viewableby, editableby, postnum) VALUES (1, 'Miejscowość', 'Gdzie mieszkasz?', 1, 'text', '', 0, 255, 0, 0, 1, 0, -1, -1, 0);"; +$inserts[] = "INSERT INTO mybb_profilefields (fid, name, description, disporder, type, regex, length, maxlength, required, registration, profile, postbit, viewableby, editableby, postnum) VALUES (2, 'O sobie', 'Wpisz kilka zdań o swojej osobie.', 2, 'textarea', '', 0, 0, 0, 0, 1, 0, -1, -1, 0);"; +$inserts[] = "INSERT INTO mybb_profilefields (fid, name, description, disporder, type, regex, length, maxlength, required, registration, profile, postbit, viewableby, editableby, postnum) VALUES (3, 'Płeć', 'Wybierz swoją płeć z listy.', 0, 'select\nnie wybrano\nmężczyzna\nkobieta\ninna', '', 0, 0, 0, 0, 1, 0, -1, -1, 0);"; + +$inserts[] = "INSERT INTO mybb_questions (qid, question, answer, shown, correct, incorrect, active) VALUES(1, 'Jaki jest wynik działania 2+2?', '4\ncztery', 0, 0, 0, 1);"; + +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(1, 'Uśmiech', ':)', 'images/smilies/smile.gif', 1, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(2, 'Oczko', ';)', 'images/smilies/wink.gif', 2, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(3, 'Cwaniak', ':cool:', 'images/smilies/cool.gif', 3, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(4, 'Duży uśmiech', ':D', 'images/smilies/biggrin.gif', 4, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(5, 'Język', ':P', 'images/smilies/tongue.gif', 5, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(6, 'Wywracanie oczami', ':rolleyes:', 'images/smilies/rolleyes.gif', 6, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(7, 'Nieśmiały', ':shy:', 'images/smilies/shy.gif', 7, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(8, 'Smutny', ':(', 'images/smilies/sad.gif', 8, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(9, 'Małpka', ':at:', 'images/smilies/at.png', 9, 0);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(10, 'Anioł', ':angel:', 'images/smilies/angel.gif', 10, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(11, 'Zły', ':@', 'images/smilies/angry.gif', 11, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(12, 'Zawstydzony', ':blush:', 'images/smilies/blush.gif', 12, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(13, 'Zdezorientowany', ':s', 'images/smilies/confused.gif', 13, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(14, 'Podejrzany', ':dodgy:', 'images/smilies/dodgy.gif', 14, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(15, 'Wykrzyknik', ':exclamation:', 'images/smilies/exclamation.png', 15, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(16, 'Serce', ':heart:', 'images/smilies/heart.gif', 16, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(17, 'Huh', ':huh:', 'images/smilies/huh.gif', 17, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(18, 'Pomysł', ':idea:', 'images/smilies/lightbulb.png', 18, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(19, 'Śpiący', ':sleepy:', 'images/smilies/sleepy.gif', 19, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(20, 'Niezdecydowany', ':-/', 'images/smilies/undecided.gif', 20, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(21, 'Płacz', ':cry:', 'images/smilies/cry.png', 21, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(22, 'Chory', ':sick:', 'images/smilies/sick.png', 22, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(23, 'Strzałka', ':arrow:', 'images/smilies/arrow.png', 23, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(24, 'Moje', ':my:', 'images/smilies/my.png', 24, 1);"; + +#Emotikony wykonane przez Polski Support MyBB - http://www.mybboard.pl +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(25, 'Cyklop', ':cyklop:', 'images/smilies/cyklop.gif', 25, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(26, 'Diabeł', ':diabel:', 'images/smilies/devil.gif', 26, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(27, 'O matko', ':facepalm:', 'images/smilies/facepalm.gif', 27, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(28, 'Firefox', ':ff:', 'images/smilies/ff.gif', 28, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(29, 'Szczęśliwy', ':lol:', 'images/smilies/happy.gif', 29, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(30, 'Ninja', ':ninja:', 'images/smilies/ninja.gif', 30, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(31, 'Opera', ':opera:', 'images/smilies/opera.gif', 31, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(32, 'Plask', ':plask:', 'images/smilies/plask.gif', 32, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(33, 'Zawstydzony', ':zawstydzony:', 'images/smilies/shamefaced.gif', 33, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(34, 'Szczerbol', ':szczerbol:', 'images/smilies/szczerbol.gif', 34, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(35, 'Szczerbol', ':E', 'images/smilies/szczerbol2.gif', 35, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(36, 'Ściana', ':sciana:', 'images/smilies/wall.gif', 36, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(37, 'Zdziwko', ':zdziwko:', 'images/smilies/wow.gif', 37, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(38, 'Przytulanie', ':przytul:', 'images/smilies/wub.gif', 38, 1);"; +$inserts[] = "INSERT INTO mybb_smilies (sid, name, find, image, disporder, showclickable) VALUES(39, 'xD', 'xD', 'images/smilies/xd.gif', 39, 1);"; + + +$inserts[] = "INSERT INTO mybb_spiders (name,useragent) VALUES ('Google','Googlebot');"; +$inserts[] = "INSERT INTO mybb_spiders (name,useragent) VALUES ('Bing','bingbot');"; +$inserts[] = "INSERT INTO mybb_spiders (name,useragent) VALUES ('Alexa Internet','ia_archiver');"; +$inserts[] = "INSERT INTO mybb_spiders (name,useragent) VALUES ('Ask.com','Teoma');"; +$inserts[] = "INSERT INTO mybb_spiders (name,useragent) VALUES ('Baidu','Baiduspider');"; +$inserts[] = "INSERT INTO mybb_spiders (name,useragent) VALUES ('Yandex','YandexBot');"; +$inserts[] = "INSERT INTO mybb_spiders (name,useragent) VALUES ('Blekko','Blekkobot');"; +$inserts[] = "INSERT INTO mybb_spiders (name,useragent) VALUES ('Facebook','facebookexternalhit');"; +$inserts[] = "INSERT INTO mybb_spiders (name,useragent) VALUES ('Twitter','Twitterbot');"; +$inserts[] = "INSERT INTO mybb_spiders (name,useragent) VALUES ('Internet Archive','archive.org_bot');"; + +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('1','calendar','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('2','editpost','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('3','forumbit','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('4','forumjump','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('5','forumdisplay','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('6','index','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('7','error','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('8','memberlist','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('9','multipage','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('10','private','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('11','portal','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('12','postbit','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('13','posticons','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('14','showthread','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('15','usercp','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('16','online','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('17','moderation','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('18','nav','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('19','search','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('20','showteam','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('21','reputation','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('22','newthread','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('23','newreply','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('24','member','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('25','warnings','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('26','global','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('27','header','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('28','managegroup','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('29','misc','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('30','modcp','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('31','announcement','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('32','polls','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('33','post','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('34','printthread','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('35','report','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('36','smilieinsert','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('37','stats','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('38','xmlhttp','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('39','footer','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('40','video','','1');"; +$inserts[] = "INSERT INTO mybb_templategroups (gid,prefix,title,isdefault) VALUES ('41','sendthread','','1');"; + +$inserts[] = "INSERT INTO mybb_usertitles (utid, posts, title, stars, starimage) VALUES (1, 0, 'Świeżo zarejestrowany', 1, '');"; +$inserts[] = "INSERT INTO mybb_usertitles (utid, posts, title, stars, starimage) VALUES (2, 1, 'Początkujący', 2, '');"; +$inserts[] = "INSERT INTO mybb_usertitles (utid, posts, title, stars, starimage) VALUES (3, 50, 'Użytkownik', 3, '');"; +$inserts[] = "INSERT INTO mybb_usertitles (utid, posts, title, stars, starimage) VALUES (4, 250, 'Dużo pisze', 4, '');"; +$inserts[] = "INSERT INTO mybb_usertitles (utid, posts, title, stars, starimage) VALUES (5, 750, 'Stały bywalec', 5, '');"; + diff --git a/Upload/install/resources/mysql_db_tables.php b/Upload/install/resources/mysql_db_tables.php new file mode 100644 index 0000000..73e2f4d --- /dev/null +++ b/Upload/install/resources/mysql_db_tables.php @@ -0,0 +1,1165 @@ +title) + { + $this->title = $lang->title; + } + + @header("Content-type: text/html; charset=utf-8"); + + $this->doneheader = 1; + $dbconfig_add = ''; + if($image == "dbconfig") + { + $dbconfig_add = ""; + } + echo << + + + {$this->title} > {$title} + + + + {$dbconfig_add} + + +END; + if($form) + { + echo "\n
    script."\">\n"; + $this->openedform = 1; + } + + echo << + +
    + +END; + if($mybb->version_code >= 1700 && $mybb->version_code < 1800) + { + echo $lang->development_preview; + } + if(empty($this->steps)) + { + $this->steps = array(); + } + if(is_array($this->steps)) + { + echo "\n
    "; + echo "\n
      \n"; + foreach($this->steps as $action => $step) + { + if($action == $mybb->input['action']) + { + echo "
    • {$step}
    • \n"; + } + else + { + echo "
    • {$step}
    • \n"; + } + } + echo "
    "; + echo "\n
    "; + echo "\n
    \n"; + } + else + { + echo "\n
    "; + echo "\n
    \n"; + } + if($title != "") + { + echo <<{$title}\n +END; + } + } + + function print_contents($contents) + { + echo $contents; + } + + function print_error($message) + { + global $lang; + if(!$this->doneheader) + { + $this->print_header($lang->error, "", 0, 1); + } + echo "
    \n "; + echo "

    ".$lang->error."

    "; + $this->print_contents($message); + echo "\n
    "; + $this->print_footer(); + } + + function print_footer($nextact="") + { + global $lang, $footer_extra; + if($nextact && $this->openedform) + { + echo "\n "; + echo "\n
    next." »\" />

    \n"; + $formend = ""; + } + else + { + $formend = ""; + } + + echo << + +
    +
    +
    + {$formend} + {$footer_extra} + + +END; + exit; + } +} diff --git a/Upload/install/resources/pgsql_db_tables.php b/Upload/install/resources/pgsql_db_tables.php new file mode 100644 index 0000000..0b182fd --- /dev/null +++ b/Upload/install/resources/pgsql_db_tables.php @@ -0,0 +1,1123 @@ +
    Please make sure IN_MYBB is defined."); +} + +$tables[] = "CREATE TABLE mybb_adminlog ( + uid int NOT NULL default '0', + ipaddress bytea NOT NULL default '', + dateline int NOT NULL default '0', + module varchar(50) NOT NULL default '', + action varchar(50) NOT NULL default '', + data text NOT NULL default '' +);"; + +$tables[] = "CREATE TABLE mybb_adminoptions ( + uid int NOT NULL default '0', + cpstyle varchar(50) NOT NULL default '', + cplanguage varchar(50) NOT NULL default '', + codepress smallint NOT NULL default '1', + notes text NOT NULL default '', + permissions text NOT NULL default '', + defaultviews text NOT NULL, + loginattempts smallint NOT NULL default '0', + loginlockoutexpiry int NOT NULL default '0', + UNIQUE (uid) +);"; + +$tables[] = "CREATE TABLE mybb_adminsessions ( + sid varchar(32) NOT NULL default '', + uid int NOT NULL default '0', + loginkey varchar(50) NOT NULL default '', + ip bytea NOT NULL default '', + dateline int NOT NULL default '0', + lastactive int NOT NULL default '0', + data text NOT NULL default '', + useragent varchar(100) NOT NULL default '' +);"; + +$tables[] = "CREATE TABLE mybb_adminviews ( + vid serial, + uid int NOT NULL default '0', + title varchar(100) NOT NULL default '', + type varchar(6) NOT NULL default '', + visibility smallint NOT NULL default '0', + fields text NOT NULL, + conditions text NOT NULL, + custom_profile_fields text NOT NULL, + sortby varchar(20) NOT NULL default '', + sortorder varchar(4) NOT NULL default '', + perpage smallint NOT NULL default '0', + view_type varchar(6) NOT NULL default '', + PRIMARY KEY (vid) +);"; + +$tables[] = "CREATE TABLE mybb_announcements ( + aid serial, + fid int NOT NULL default '0', + uid int NOT NULL default '0', + subject varchar(120) NOT NULL default '', + message text NOT NULL default '', + startdate int NOT NULL default '0', + enddate int NOT NULL default '0', + allowhtml smallint NOT NULL default '0', + allowmycode smallint NOT NULL default '0', + allowsmilies smallint NOT NULL default '0', + PRIMARY KEY (aid) +);"; + +$tables[] = "CREATE TABLE mybb_attachments ( + aid serial, + pid int NOT NULL default '0', + posthash varchar(50) NOT NULL default '', + uid int NOT NULL default '0', + filename varchar(120) NOT NULL default '', + filetype varchar(120) NOT NULL default '', + filesize int NOT NULL default '0', + attachname varchar(120) NOT NULL default '', + downloads int NOT NULL default '0', + dateuploaded int NOT NULL default '0', + visible smallint NOT NULL default '0', + thumbnail varchar(120) NOT NULL default '', + PRIMARY KEY (aid) +);"; + +$tables[] = "CREATE TABLE mybb_attachtypes ( + atid serial, + name varchar(120) NOT NULL default '', + mimetype varchar(120) NOT NULL default '', + extension varchar(10) NOT NULL default '', + maxsize int NOT NULL default '0', + icon varchar(100) NOT NULL default '', + PRIMARY KEY (atid) +);"; + +$tables[] = "CREATE TABLE mybb_awaitingactivation ( + aid serial, + uid int NOT NULL default '0', + dateline int NOT NULL default '0', + code varchar(100) NOT NULL default '', + type char(1) NOT NULL default '', + validated smallint NOT NULL default '0', + misc varchar(255) NOT NULL default '', + PRIMARY KEY (aid) +);"; + +$tables[] = "CREATE TABLE mybb_badwords ( + bid serial, + badword varchar(100) NOT NULL default '', + replacement varchar(100) NOT NULL default '', + PRIMARY KEY (bid) +);"; + +$tables[] = "CREATE TABLE mybb_banfilters ( + fid serial, + filter varchar(200) NOT NULL default '', + type smallint NOT NULL default '0', + lastuse int NOT NULL default '0', + dateline int NOT NULL default '0', + PRIMARY KEY (fid) +);"; + +$tables[] = "CREATE TABLE mybb_banned ( + uid int NOT NULL default '0', + gid int NOT NULL default '0', + oldgroup int NOT NULL default '0', + oldadditionalgroups text NOT NULL default '', + olddisplaygroup int NOT NULL default '0', + admin int NOT NULL default '0', + dateline int NOT NULL default '0', + bantime varchar(50) NOT NULL default '', + lifted int NOT NULL default '0', + reason varchar(255) NOT NULL default '' +);"; + +$tables[] = "CREATE TABLE mybb_buddyrequests ( + id serial, + uid int NOT NULL, + touid int NOT NULL, + date int NOT NULL, + PRIMARY KEY (id) +);"; + +$tables[] = "CREATE TABLE mybb_calendars ( + cid serial, + name varchar(100) NOT NULL default '', + disporder smallint NOT NULL default '0', + startofweek smallint NOT NULL default '0', + showbirthdays smallint NOT NULL default '0', + eventlimit smallint NOT NULL default '0', + moderation smallint NOT NULL default '0', + allowhtml smallint NOT NULL default '0', + allowmycode smallint NOT NULL default '0', + allowimgcode smallint NOT NULL default '0', + allowvideocode smallint NOT NULL default '0', + allowsmilies smallint NOT NULL default '0', + PRIMARY KEY(cid) +);"; + +$tables[] = "CREATE TABLE mybb_calendarpermissions ( + cid serial, + gid int NOT NULL default '0', + canviewcalendar smallint NOT NULL default '0', + canaddevents smallint NOT NULL default '0', + canbypasseventmod smallint NOT NULL default '0', + canmoderateevents smallint NOT NULL default '0' +);"; + +$tables[] = "CREATE TABLE mybb_captcha ( + imagehash varchar(32) NOT NULL default '', + imagestring varchar(8) NOT NULL default '', + dateline int NOT NULL default '0', + used smallint NOT NULL default '0' +);"; + +$tables[] = "CREATE TABLE mybb_datacache ( + title varchar(50) NOT NULL default '', + cache text NOT NULL default '', + PRIMARY KEY (title) +);"; + +$tables[] = "CREATE TABLE mybb_delayedmoderation ( + did serial, + type varchar(30) NOT NULL default '', + delaydateline int NOT NULL default '0', + uid int NOT NULL default '0', + fid smallint NOT NULL default '0', + tids text NOT NULL, + dateline int NOT NULL default '0', + inputs text NOT NULL default '', + PRIMARY KEY (did) +);"; + +$tables[] = "CREATE TABLE mybb_events ( + eid serial, + cid int NOT NULL default '0', + uid int NOT NULL default '0', + name varchar(120) NOT NULL default '', + description text NOT NULL, + visible smallint NOT NULL default '0', + private smallint NOT NULL default '0', + dateline int NOT NULL default '0', + starttime int NOT NULL default '0', + endtime int NOT NULL default '0', + timezone varchar(5) NOT NULL default '', + ignoretimezone smallint NOT NULL default '0', + usingtime smallint NOT NULL default '0', + repeats text NOT NULL, + PRIMARY KEY (eid) +);"; + +$tables[] = "CREATE TABLE mybb_forumpermissions ( + pid serial, + fid int NOT NULL default '0', + gid int NOT NULL default '0', + canview smallint NOT NULL default '0', + canviewthreads smallint NOT NULL default '0', + canonlyviewownthreads smallint NOT NULL default '0', + candlattachments smallint NOT NULL default '0', + canpostthreads smallint NOT NULL default '0', + canpostreplys smallint NOT NULL default '0', + canonlyreplyownthreads smallint NOT NULL default '0', + canpostattachments smallint NOT NULL default '0', + canratethreads smallint NOT NULL default '0', + caneditposts smallint NOT NULL default '0', + candeleteposts smallint NOT NULL default '0', + candeletethreads smallint NOT NULL default '0', + caneditattachments smallint NOT NULL default '0', + modposts smallint NOT NULL default '0', + modthreads smallint NOT NULL default '0', + mod_edit_posts smallint NOT NULL default '0', + modattachments smallint NOT NULL default '0', + canpostpolls smallint NOT NULL default '0', + canvotepolls smallint NOT NULL default '0', + cansearch smallint NOT NULL default '0', + PRIMARY KEY (pid) +);"; + +$tables[] = "CREATE TABLE mybb_forums ( + fid serial, + name varchar(120) NOT NULL default '', + description text NOT NULL default '', + linkto varchar(180) NOT NULL default '', + type char(1) NOT NULL default '', + pid smallint NOT NULL default '0', + parentlist text NOT NULL default '', + disporder smallint NOT NULL default '0', + active smallint NOT NULL default '0', + open smallint NOT NULL default '0', + threads int NOT NULL default '0', + posts int NOT NULL default '0', + lastpost int NOT NULL default '0', + lastposter varchar(120) NOT NULL default '', + lastposteruid int NOT NULL default '0', + lastposttid int NOT NULL default '0', + lastpostsubject varchar(120) NOT NULL default '', + allowhtml smallint NOT NULL default '0', + allowmycode smallint NOT NULL default '0', + allowsmilies smallint NOT NULL default '0', + allowimgcode smallint NOT NULL default '0', + allowvideocode smallint NOT NULL default '0', + allowpicons smallint NOT NULL default '0', + allowtratings smallint NOT NULL default '0', + usepostcounts smallint NOT NULL default '0', + usethreadcounts smallint NOT NULL default '0', + requireprefix smallint NOT NULL default '0', + password varchar(50) NOT NULL default '', + showinjump smallint NOT NULL default '0', + style smallint NOT NULL default '0', + overridestyle smallint NOT NULL default '0', + rulestype smallint NOT NULL default '0', + rulestitle varchar(200) NOT NULL default '', + rules text NOT NULL default '', + unapprovedthreads int NOT NULL default '0', + unapprovedposts int NOT NULL default '0', + deletedthreads int NOT NULL default '0', + deletedposts int NOT NULL default '0', + defaultdatecut smallint NOT NULL default '0', + defaultsortby varchar(10) NOT NULL default '', + defaultsortorder varchar(4) NOT NULL default '', + PRIMARY KEY (fid) +);"; + +$tables[] = "CREATE TABLE mybb_forumsread ( + fid int NOT NULL default '0', + uid int NOT NULL default '0', + dateline int NOT NULL default '0' +);"; + +$tables[] = "CREATE TABLE mybb_forumsubscriptions ( + fsid serial, + fid smallint NOT NULL default '0', + uid int NOT NULL default '0', + PRIMARY KEY (fsid) +);"; + +$tables[] = "CREATE TABLE mybb_groupleaders ( + lid serial, + gid smallint NOT NULL default '0', + uid int NOT NULL default '0', + canmanagemembers smallint NOT NULL default '0', + canmanagerequests smallint NOT NULL default '0', + caninvitemembers smallint NOT NULL default '0', + PRIMARY KEY (lid) +);"; + +$tables[] = "CREATE TABLE mybb_helpdocs ( + hid serial, + sid smallint NOT NULL default '0', + name varchar(120) NOT NULL default '', + description text NOT NULL default '', + document text NOT NULL default '', + usetranslation smallint NOT NULL default '0', + enabled smallint NOT NULL default '0', + disporder smallint NOT NULL default '0', + PRIMARY KEY (hid) +);"; + +$tables[] = "CREATE TABLE mybb_helpsections ( + sid serial, + name varchar(120) NOT NULL default '', + description text NOT NULL default '', + usetranslation smallint NOT NULL default '0', + enabled smallint NOT NULL default '0', + disporder smallint NOT NULL default '0', + PRIMARY KEY (sid) +);"; + +$tables[] = "CREATE TABLE mybb_icons ( + iid serial, + name varchar(120) NOT NULL default '', + path varchar(220) NOT NULL default '', + PRIMARY KEY (iid) +);"; + +$tables[] = "CREATE TABLE mybb_joinrequests ( + rid serial, + uid int NOT NULL default '0', + gid smallint NOT NULL default '0', + reason varchar(250) NOT NULL default '', + dateline int NOT NULL default '0', + invite smallint NOT NULL default '0', + PRIMARY KEY (rid) +);"; + +$tables[] = "CREATE TABLE mybb_massemails ( + mid serial, + uid int NOT NULL default '0', + subject varchar(200) NOT NULL default '', + message text NOT NULL, + htmlmessage text NOT NULL, + type smallint NOT NULL default '0', + format smallint NOT NULL default '0', + dateline numeric(30,0) NOT NULL default '0', + senddate numeric(30,0) NOT NULL default '0', + status smallint NOT NULL default '0', + sentcount int NOT NULL default '0', + totalcount int NOT NULL default '0', + conditions text NOT NULL, + perpage int NOT NULL default '50', + PRIMARY KEY(mid) +);"; + +$tables[] = "CREATE TABLE mybb_mailerrors ( + eid serial, + subject varchar(200) NOT NULL default '', + message text NOT NULL default '', + toaddress varchar(150) NOT NULL default '', + fromaddress varchar(150) NOT NULL default '', + dateline int NOT NULL default '0', + error text NOT NULL default '', + smtperror varchar(200) NOT NULL default '', + smtpcode smallint NOT NULL default '0', + PRIMARY KEY(eid) +);"; + +$tables[] = "CREATE TABLE mybb_maillogs ( + mid serial, + subject varchar(200) not null default '', + message text NOT NULL default '', + dateline int NOT NULL default '0', + fromuid int NOT NULL default '0', + fromemail varchar(200) not null default '', + touid int NOT NULL default '0', + toemail varchar(200) NOT NULL default '', + tid int NOT NULL default '0', + ipaddress bytea NOT NULL default '', + type smallint NOT NULL default '0', + PRIMARY KEY(mid) +);"; + +$tables[] = "CREATE TABLE mybb_mailqueue ( + mid serial, + mailto varchar(200) NOT NULL, + mailfrom varchar(200) NOT NULL, + subject varchar(200) NOT NULL, + message text NOT NULL default '', + headers text NOT NULL default '', + PRIMARY KEY(mid) +);"; + +$tables[] = "CREATE TABLE mybb_moderatorlog ( + uid int NOT NULL default '0', + dateline int NOT NULL default '0', + fid smallint NOT NULL default '0', + tid int NOT NULL default '0', + pid int NOT NULL default '0', + action text NOT NULL default '', + data text NOT NULL, + ipaddress bytea NOT NULL default '' +);"; + +$tables[] = "CREATE TABLE mybb_moderators ( + mid serial, + fid smallint NOT NULL default '0', + id int NOT NULL default '0', + isgroup smallint NOT NULL default '0', + caneditposts smallint NOT NULL default '0', + cansoftdeleteposts smallint NOT NULL default '0', + canrestoreposts smallint NOT NULL default '0', + candeleteposts smallint NOT NULL default '0', + cansoftdeletethreads smallint NOT NULL default '0', + canrestorethreads smallint NOT NULL default '0', + candeletethreads smallint NOT NULL default '0', + canviewips smallint NOT NULL default '0', + canviewunapprove smallint NOT NULL default '0', + canviewdeleted smallint NOT NULL default '0', + canopenclosethreads smallint NOT NULL default '0', + canstickunstickthreads smallint NOT NULL default '0', + canapproveunapprovethreads smallint NOT NULL default '0', + canapproveunapproveposts smallint NOT NULL default '0', + canapproveunapproveattachs smallint NOT NULL default '0', + canmanagethreads smallint NOT NULL default '0', + canmanagepolls smallint NOT NULL default '0', + canpostclosedthreads smallint NOT NULL default '0', + canmovetononmodforum smallint NOT NULL default '0', + canusecustomtools smallint NOT NULL default '0', + canmanageannouncements smallint NOT NULL default '0', + canmanagereportedposts smallint NOT NULL default '0', + canviewmodlog smallint NOT NULL default '0', + PRIMARY KEY (mid) +);"; + +$tables[] = "CREATE TABLE mybb_modtools ( + tid serial, + name varchar(200) NOT NULL, + description text NOT NULL default '', + forums text NOT NULL default '', + groups text NOT NULL default '', + type char(1) NOT NULL default '', + postoptions text NOT NULL default '', + threadoptions text NOT NULL default '', + PRIMARY KEY (tid) +);"; + +$tables[] = "CREATE TABLE mybb_mycode ( + cid serial, + title varchar(100) NOT NULL default '', + description text NOT NULL default '', + regex text NOT NULL default '', + replacement text NOT NULL default '', + active smallint NOT NULL default '0', + parseorder smallint NOT NULL default '0', + PRIMARY KEY(cid) +);"; + +$tables[] = "CREATE TABLE mybb_polls ( + pid serial, + tid int NOT NULL default '0', + question varchar(200) NOT NULL default '', + dateline int NOT NULL default '0', + options text NOT NULL default '', + votes text NOT NULL default '', + numoptions smallint NOT NULL default '0', + numvotes int NOT NULL default '0', + timeout int NOT NULL default '0', + closed smallint NOT NULL default '0', + multiple smallint NOT NULL default '0', + public smallint NOT NULL default '0', + maxoptions smallint NOT NULL default '0', + PRIMARY KEY (pid) +);"; + +$tables[] = "CREATE TABLE mybb_pollvotes ( + vid serial, + pid int NOT NULL default '0', + uid int NOT NULL default '0', + voteoption smallint NOT NULL default '0', + dateline int NOT NULL default '0', + PRIMARY KEY (vid) +);"; + +$tables[] = "CREATE TABLE mybb_posts ( + pid serial, + tid int NOT NULL default '0', + replyto int NOT NULL default '0', + fid smallint NOT NULL default '0', + subject varchar(120) NOT NULL default '', + icon smallint NOT NULL default '0', + uid int NOT NULL default '0', + username varchar(80) NOT NULL default '', + dateline int NOT NULL default '0', + message text NOT NULL default '', + ipaddress bytea NOT NULL default '', + includesig smallint NOT NULL default '0', + smilieoff smallint NOT NULL default '0', + edituid int NOT NULL default '0', + edittime int NOT NULL default '0', + editreason varchar(150) NOT NULL default '', + visible smallint NOT NULL default '0', + PRIMARY KEY (pid) +);"; + +$tables[] = "CREATE TABLE mybb_privatemessages ( + pmid serial, + uid int NOT NULL default '0', + toid int NOT NULL default '0', + fromid int NOT NULL default '0', + recipients text NOT NULL default '', + folder smallint NOT NULL default '1', + subject varchar(120) NOT NULL default '', + icon smallint NOT NULL default '0', + message text NOT NULL default '', + dateline int NOT NULL default '0', + deletetime int NOT NULL default '0', + status smallint NOT NULL default '0', + statustime int NOT NULL default '0', + includesig smallint NOT NULL default '0', + smilieoff smallint NOT NULL default '0', + receipt smallint NOT NULL default '0', + readtime int NOT NULL default '0', + ipaddress bytea NOT NULL default '', + PRIMARY KEY (pmid) +);"; + +$tables[] = "CREATE TABLE mybb_profilefields ( + fid serial, + name varchar(100) NOT NULL default '', + description text NOT NULL default '', + disporder smallint NOT NULL default '0', + type text NOT NULL default '', + regex text NOT NULL default '', + length smallint NOT NULL default '0', + maxlength smallint NOT NULL default '0', + required smallint NOT NULL default '0', + registration smallint NOT NULL default '0', + profile smallint NOT NULL default '0', + postbit smallint NOT NULL default '0', + viewableby text NOT NULL default '-1', + editableby text NOT NULL default '-1', + postnum smallint NOT NULL default '0', + allowhtml smallint NOT NULL default '0', + allowmycode smallint NOT NULL default '0', + allowsmilies smallint NOT NULL default '0', + allowimgcode smallint NOT NULL default '0', + allowvideocode smallint NOT NULL default '0', + PRIMARY KEY (fid) +);"; + +$tables[] = "CREATE TABLE mybb_promotions ( + pid serial, + title varchar(120) NOT NULL default '', + description text NOT NULL default '', + enabled smallint NOT NULL default '1', + logging smallint NOT NULL default '0', + posts int NOT NULL default '0', + posttype varchar(2) NOT NULL default '', + threads int NOT NULL default '0', + threadtype varchar(2) NOT NULL default '', + registered int NOT NULL default '0', + registeredtype varchar(20) NOT NULL default '', + online int NOT NULL default '0', + onlinetype varchar(20) NOT NULL default '', + reputations int NOT NULL default '0', + reputationtype varchar(2) NOT NULL default '', + referrals int NOT NULL default '0', + referralstype varchar(2) NOT NULL default '', + warnings int NOT NULL default '0', + warningstype varchar(2) NOT NULL default '', + requirements varchar(200) NOT NULL default '', + originalusergroup varchar(120) NOT NULL default '0', + newusergroup smallint NOT NULL default '0', + usergrouptype varchar(120) NOT NULL default '0', + PRIMARY KEY(pid) +);"; + +$tables[] = "CREATE TABLE mybb_promotionlogs ( + plid serial, + pid int NOT NULL default '0', + uid int NOT NULL default '0', + oldusergroup varchar(200) NOT NULL default '0', + newusergroup smallint NOT NULL default '0', + dateline int NOT NULL default '0', + type varchar(9) NOT NULL default 'primary', + PRIMARY KEY(plid) +);"; + +$tables[] = "CREATE TABLE mybb_questions ( + qid serial, + question varchar(200) NOT NULL default '', + answer varchar(150) NOT NULL default '', + shown int NOT NULL default 0, + correct int NOT NULL default 0, + incorrect int NOT NULL default 0, + active smallint NOT NULL default '0', + PRIMARY KEY (qid) +);"; + +$tables[] = "CREATE TABLE mybb_questionsessions ( + sid varchar(32) NOT NULL default '', + qid int NOT NULL default '0', + dateline int NOT NULL default '0', + UNIQUE (sid) +);"; + +$tables[] = "CREATE TABLE mybb_reportedcontent ( + rid serial, + id int NOT NULL default '0', + id2 int NOT NULL default '0', + id3 int NOT NULL default '0', + uid int NOT NULL default '0', + reportstatus smallint NOT NULL default '0', + reason varchar(250) NOT NULL default '', + type varchar(50) NOT NULL default '', + reports int NOT NULL default '0', + reporters text NOT NULL default '', + dateline int NOT NULL default '0', + lastreport int NOT NULL default '0', + PRIMARY KEY (rid) +);"; + +$tables[] = "CREATE TABLE mybb_reputation ( + rid serial, + uid int NOT NULL default '0', + adduid int NOT NULL default '0', + pid int NOT NULL default '0', + reputation smallint NOT NULL default '0', + dateline int NOT NULL default '0', + comments text NOT NULL default '', + PRIMARY KEY(rid) +);"; + +$tables[] = "CREATE TABLE mybb_searchlog ( + sid varchar(32) NOT NULL default '', + uid int NOT NULL default '0', + dateline int NOT NULL default '0', + ipaddress bytea NOT NULL default '', + threads text NOT NULL default '', + posts text NOT NULL default '', + resulttype varchar(10) NOT NULL default '', + querycache text NOT NULL default '', + keywords text NOT NULL default '', + UNIQUE (sid) +);"; + +$tables[] = "CREATE TABLE mybb_sessions ( + sid varchar(32) NOT NULL default '', + uid int NOT NULL default '0', + ip bytea NOT NULL default '', + time int NOT NULL default '0', + location varchar(150) NOT NULL default '', + useragent varchar(100) NOT NULL default '', + anonymous smallint NOT NULL default '0', + nopermission smallint NOT NULL default '0', + location1 int NOT NULL default '0', + location2 int NOT NULL default '0', + UNIQUE (sid) +);"; + +$tables[] = "CREATE TABLE mybb_settinggroups ( + gid serial, + name varchar(100) NOT NULL default '', + title varchar(220) NOT NULL default '', + description text NOT NULL default '', + disporder smallint NOT NULL default '0', + isdefault smallint NOT NULL default '0', + PRIMARY KEY (gid) +);"; + +$tables[] = "CREATE TABLE mybb_settings ( + sid serial, + name varchar(120) NOT NULL default '', + title varchar(120) NOT NULL default '', + description text NOT NULL default '', + optionscode text NOT NULL default '', + value text NOT NULL default '', + disporder smallint NOT NULL default '0', + gid smallint NOT NULL default '0', + isdefault smallint NOT NULL default '0', + PRIMARY KEY (sid) +);"; + +$tables[] = "CREATE TABLE mybb_smilies ( + sid serial, + name varchar(120) NOT NULL default '', + find text NOT NULL, + image varchar(220) NOT NULL default '', + disporder smallint NOT NULL default '0', + showclickable smallint NOT NULL default '0', + PRIMARY KEY (sid) +);"; + +$tables[] = "CREATE TABLE mybb_spamlog ( + sid serial, + username varchar(120) NOT NULL DEFAULT '', + email varchar(220) NOT NULL DEFAULT '', + ipaddress bytea NOT NULL default '', + dateline numeric(30,0) NOT NULL default '0', + data text NOT NULL default '', + PRIMARY KEY (sid) +);"; + +$tables[] = "CREATE TABLE mybb_spiders ( + sid serial, + name varchar(100) NOT NULL default '', + theme smallint NOT NULL default '0', + language varchar(20) NOT NULL default '', + usergroup smallint NOT NULL default '0', + useragent varchar(200) NOT NULL default '', + lastvisit int NOT NULL default '0', + PRIMARY KEY(sid) +);"; + +$tables[] = "CREATE TABLE mybb_stats ( + dateline numeric(30,0) NOT NULL default '0', + numusers numeric(10,0) NOT NULL default '0', + numthreads numeric(10,0) NOT NULL default '0', + numposts numeric(10,0) NOT NULL default '0', + UNIQUE (dateline) +);"; + +$tables[] = "CREATE TABLE mybb_tasks ( + tid serial, + title varchar(120) NOT NULL default '', + description text NOT NULL default '', + file varchar(30) NOT NULL default '', + minute varchar(200) NOT NULL default '', + hour varchar(200) NOT NULL default '', + day varchar(100) NOT NULL default '', + month varchar(30) NOT NULL default '', + weekday varchar(15) NOT NULL default '', + nextrun int NOT NULL default '0', + lastrun int NOT NULL default '0', + enabled smallint NOT NULL default '1', + logging smallint NOT NULL default '0', + locked int NOT NULL default '0', + PRIMARY KEY(tid) +);"; + +$tables[] = "CREATE TABLE mybb_tasklog ( + lid serial, + tid int NOT NULL default '0', + dateline int NOT NULL default '0', + data text NOT NULL, + PRIMARY KEY(lid) +);"; + +$tables[] = "CREATE TABLE mybb_templategroups ( + gid serial, + prefix varchar(50) NOT NULL default '', + title varchar(100) NOT NULL default '', + isdefault smallint NOT NULL default '0', + PRIMARY KEY (gid) +);"; + +$tables[] = "CREATE TABLE mybb_templates ( + tid serial, + title varchar(120) NOT NULL default '', + template text NOT NULL default '', + sid smallint NOT NULL default '0', + version varchar(20) NOT NULL default '0', + status varchar(10) NOT NULL default '', + dateline int NOT NULL default '0', + PRIMARY KEY (tid) +);"; + +$tables[] = "CREATE TABLE mybb_templatesets ( + sid serial, + title varchar(120) NOT NULL default '', + PRIMARY KEY (sid) +);"; + +$tables[] = "CREATE TABLE mybb_themes ( + tid serial, + name varchar(100) NOT NULL default '', + pid smallint NOT NULL default '0', + def smallint NOT NULL default '0', + properties text NOT NULL default '', + stylesheets text NOT NULL default '', + allowedgroups text NOT NULL default '', + PRIMARY KEY (tid) +);"; + +$tables[] = "CREATE TABLE mybb_themestylesheets( + sid serial, + name varchar(30) NOT NULL default '', + tid numeric(10,0) NOT NULL default '0', + attachedto text NOT NULL, + stylesheet text NOT NULL, + cachefile varchar(100) NOT NULL default '', + lastmodified numeric(30,0) NOT NULL default '0', + PRIMARY KEY(sid) +);"; + +$tables[] = "CREATE TABLE mybb_threadprefixes ( + pid serial, + prefix varchar(120) NOT NULL default '', + displaystyle varchar(200) NOT NULL default '', + forums text NOT NULL, + groups text NOT NULL, + PRIMARY KEY(pid) +);"; + +$tables[] = "CREATE TABLE mybb_threadratings ( + rid serial, + tid int NOT NULL default '0', + uid int NOT NULL default '0', + rating smallint NOT NULL default '0', + ipaddress bytea NOT NULL default '', + PRIMARY KEY (rid) +);"; + +$tables[] = "CREATE TABLE mybb_threadviews ( + tid int NOT NULL default '0' +);"; + +$tables[] = "CREATE TABLE mybb_threads ( + tid serial, + fid smallint NOT NULL default '0', + subject varchar(120) NOT NULL default '', + prefix smallint NOT NULL default '0', + icon smallint NOT NULL default '0', + poll int NOT NULL default '0', + uid int NOT NULL default '0', + username varchar(80) NOT NULL default '', + dateline int NOT NULL default '0', + firstpost int NOT NULL default '0', + lastpost int NOT NULL default '0', + lastposter varchar(120) NOT NULL default '', + lastposteruid int NOT NULL default '0', + views int NOT NULL default '0', + replies int NOT NULL default '0', + closed varchar(30) NOT NULL default '', + sticky smallint NOT NULL default '0', + numratings smallint NOT NULL default '0', + totalratings smallint NOT NULL default '0', + notes text NOT NULL default '', + visible smallint NOT NULL default '0', + unapprovedposts int NOT NULL default '0', + deletedposts int NOT NULL default '0', + attachmentcount int NOT NULL default '0', + deletetime int NOT NULL default '0', + PRIMARY KEY (tid) +);"; + +$tables[] = "CREATE TABLE mybb_threadsread ( + tid int NOT NULL default '0', + uid int NOT NULL default '0', + dateline int NOT NULL default '0' +);"; + +$tables[] = "CREATE TABLE mybb_threadsubscriptions ( + sid serial, + uid int NOT NULL default '0', + tid int NOT NULL default '0', + notification smallint NOT NULL default '0', + dateline int NOT NULL default '0', + subscriptionkey varchar(32) NOT NULL default '', + PRIMARY KEY (sid) +);"; + +$tables[] = "CREATE TABLE mybb_userfields ( + ufid int NOT NULL default '0', + fid1 text NOT NULL default '', + fid2 text NOT NULL default '', + fid3 text NOT NULL default '', + PRIMARY KEY (ufid) +);"; +$query = $db->write_query("SELECT column_name + FROM information_schema.constraint_column_usage + WHERE table_name = '".$config['tableprefix']."userfields' + AND constraint_name = '".$config['tableprefix']."userfields_pkey' + LIMIT 1"); +$main_field = $db->fetch_field($query, 'column_name'); +if(!empty($main_field)) +{ + $tables[] = "DROP SEQUENCE mybb_userfields_ufid_seq;"; +} +$tables[] = "CREATE SEQUENCE mybb_userfields_ufid_seq;"; + +$tables[] = "CREATE TABLE mybb_usergroups ( + gid serial, + type smallint NOT NULL default '2', + title varchar(120) NOT NULL default '', + description text NOT NULL default '', + namestyle varchar(200) NOT NULL default '{username}', + usertitle varchar(120) NOT NULL default '', + stars smallint NOT NULL default '0', + starimage varchar(120) NOT NULL default '', + image varchar(120) NOT NULL default '', + disporder smallint NOT NULL default '0', + isbannedgroup smallint NOT NULL default '0', + canview smallint NOT NULL default '0', + canviewthreads smallint NOT NULL default '0', + canviewprofiles smallint NOT NULL default '0', + candlattachments smallint NOT NULL default '0', + canviewboardclosed smallint NOT NULL default '0', + canpostthreads smallint NOT NULL default '0', + canpostreplys smallint NOT NULL default '0', + canpostattachments smallint NOT NULL default '0', + canratethreads smallint NOT NULL default '0', + modposts smallint NOT NULL default '0', + modthreads smallint NOT NULL default '0', + mod_edit_posts smallint NOT NULL default '0', + modattachments smallint NOT NULL default '0', + caneditposts smallint NOT NULL default '0', + candeleteposts smallint NOT NULL default '0', + candeletethreads smallint NOT NULL default '0', + caneditattachments smallint NOT NULL default '0', + canpostpolls smallint NOT NULL default '0', + canvotepolls smallint NOT NULL default '0', + canundovotes smallint NOT NULL default '0', + canusepms smallint NOT NULL default '0', + cansendpms smallint NOT NULL default '0', + cantrackpms smallint NOT NULL default '0', + candenypmreceipts smallint NOT NULL default '0', + pmquota int NOT NULL default '0', + maxpmrecipients int NOT NULL default '5', + cansendemail smallint NOT NULL default '0', + cansendemailoverride smallint NOT NULL default '0', + maxemails int NOT NULL default '5', + emailfloodtime int NOT NULL default '5', + canviewmemberlist smallint NOT NULL default '0', + canviewcalendar smallint NOT NULL default '0', + canaddevents smallint NOT NULL default '0', + canbypasseventmod smallint NOT NULL default '0', + canmoderateevents smallint NOT NULL default '0', + canviewonline smallint NOT NULL default '0', + canviewwolinvis smallint NOT NULL default '0', + canviewonlineips smallint NOT NULL default '0', + cancp smallint NOT NULL default '0', + issupermod smallint NOT NULL default '0', + cansearch smallint NOT NULL default '0', + canusercp smallint NOT NULL default '0', + canuploadavatars smallint NOT NULL default '0', + canratemembers smallint NOT NULL default '0', + canchangename smallint NOT NULL default '0', + canbereported smallint NOT NULL default '0', + canchangewebsite smallint NOT NULL default '1', + showforumteam smallint NOT NULL default '0', + usereputationsystem smallint NOT NULL default '0', + cangivereputations smallint NOT NULL default '0', + reputationpower int NOT NULL default '0', + maxreputationsday int NOT NULL default '0', + maxreputationsperuser int NOT NULL default '0', + maxreputationsperthread int NOT NULL default '0', + candisplaygroup smallint NOT NULL default '0', + attachquota int NOT NULL default '0', + cancustomtitle smallint NOT NULL default '0', + canwarnusers smallint NOT NULL default '0', + canreceivewarnings smallint NOT NULL default '0', + maxwarningsday int NOT NULL default '3', + canmodcp smallint NOT NULL default '0', + showinbirthdaylist smallint NOT NULL default '0', + canoverridepm smallint NOT NULL default '0', + canusesig smallint NOT NULL default '0', + canusesigxposts smallint NOT NULL default '0', + signofollow smallint NOT NULL default '0', + edittimelimit smallint NOT NULL default '0', + maxposts smallint NOT NULL default '0', + showmemberlist smallint NOT NULL default '1', + canmanageannounce smallint NOT NULL default '0', + canmanagemodqueue smallint NOT NULL default '0', + canmanagereportedcontent smallint NOT NULL default '0', + canviewmodlogs smallint NOT NULL default '0', + caneditprofiles smallint NOT NULL default '0', + canbanusers smallint NOT NULL default '0', + canviewwarnlogs smallint NOT NULL default '0', + canuseipsearch smallint NOT NULL default '0', + PRIMARY KEY (gid) +);"; + +$tables[] = "CREATE TABLE mybb_users ( + uid serial, + username varchar(120) NOT NULL default '', + password varchar(120) NOT NULL default '', + salt varchar(10) NOT NULL default '', + loginkey varchar(50) NOT NULL default '', + email varchar(220) NOT NULL default '', + postnum int NOT NULL default '0', + threadnum int NOT NULL default '0', + avatar varchar(200) NOT NULL default '', + avatardimensions varchar(10) NOT NULL default '', + avatartype varchar(10) NOT NULL default '0', + usergroup smallint NOT NULL default '0', + additionalgroups varchar(200) NOT NULL default '', + displaygroup smallint NOT NULL default '0', + usertitle varchar(250) NOT NULL default '', + regdate int NOT NULL default '0', + lastactive int NOT NULL default '0', + lastvisit int NOT NULL default '0', + lastpost int NOT NULL default '0', + website varchar(200) NOT NULL default '', + icq varchar(10) NOT NULL default '', + aim varchar(50) NOT NULL default '', + yahoo varchar(50) NOT NULL default '', + skype varchar(75) NOT NULL default '', + google varchar(75) NOT NULL default '', + birthday varchar(15) NOT NULL default '', + birthdayprivacy varchar(4) NOT NULL default 'all', + signature text NOT NULL default '', + allownotices smallint NOT NULL default '0', + hideemail smallint NOT NULL default '0', + subscriptionmethod smallint NOT NULL default '0', + invisible smallint NOT NULL default '0', + receivepms smallint NOT NULL default '0', + receivefrombuddy smallint NOT NULL default '0', + pmnotice smallint NOT NULL default '0', + pmnotify smallint NOT NULL default '0', + buddyrequestspm smallint NOT NULL default '1', + buddyrequestsauto smallint NOT NULL default '0', + threadmode varchar(8) NOT NULL default '', + showimages smallint NOT NULL default '0', + showvideos smallint NOT NULL default '0', + showsigs smallint NOT NULL default '0', + showavatars smallint NOT NULL default '0', + showquickreply smallint NOT NULL default '0', + showredirect smallint NOT NULL default '0', + ppp smallint NOT NULL default '0', + tpp smallint NOT NULL default '0', + daysprune smallint NOT NULL default '0', + dateformat varchar(4) NOT NULL default '', + timeformat varchar(4) NOT NULL default '', + timezone varchar(5) NOT NULL default '', + dst smallint NOT NULL default '0', + dstcorrection smallint NOT NULL default '0', + buddylist text NOT NULL default '', + ignorelist text NOT NULL default '', + style smallint NOT NULL default '0', + away smallint NOT NULL default '0', + awaydate int NOT NULL default '0', + returndate varchar(15) NOT NULL default '', + awayreason varchar(200) NOT NULL default '', + pmfolders text NOT NULL default '', + notepad text NOT NULL default '', + referrer int NOT NULL default '0', + referrals int NOT NULL default '0', + reputation int NOT NULL default '0', + regip bytea NOT NULL default '', + lastip bytea NOT NULL default '', + language varchar(50) NOT NULL default '', + timeonline int NOT NULL default '0', + showcodebuttons smallint NOT NULL default '1', + totalpms int NOT NULL default '0', + unreadpms int NOT NULL default '0', + warningpoints int NOT NULL default '0', + moderateposts int NOT NULL default '0', + moderationtime int NOT NULL default '0', + suspendposting smallint NOT NULL default '0', + suspensiontime int NOT NULL default '0', + suspendsignature smallint NOT NULL default '0', + suspendsigtime int NOT NULL default '0', + coppauser smallint NOT NULL default '0', + classicpostbit smallint NOT NULL default '0', + loginattempts smallint NOT NULL default '1', + usernotes text NOT NULL default '', + sourceeditor smallint NOT NULL default '0', + PRIMARY KEY (uid) +);"; + +$tables[] = "CREATE TABLE mybb_usertitles ( + utid serial, + posts int NOT NULL default '0', + title varchar(250) NOT NULL default '', + stars smallint NOT NULL default '0', + starimage varchar(120) NOT NULL default '', + PRIMARY KEY (utid) +);"; + +$tables[] = "CREATE TABLE mybb_warninglevels ( + lid serial, + percentage smallint NOT NULL default '0', + action text NOT NULL, + PRIMARY KEY(lid) +);"; + +$tables[] = "CREATE TABLE mybb_warningtypes ( + tid serial, + title varchar(120) NOT NULL default '', + points smallint NOT NULL default '0', + expirationtime int NOT NULL default '0', + PRIMARY KEY(tid) +);"; + +$tables[] = "CREATE TABLE mybb_warnings ( + wid serial, + uid int NOT NULL default '0', + tid int NOT NULL default '0', + pid int NOT NULL default '0', + title varchar(120) NOT NULL default '', + points smallint NOT NULL default '0', + dateline int NOT NULL default '0', + issuedby int NOT NULL default '0', + expires int NOT NULL default '0', + expired smallint NOT NULL default '0', + daterevoked int NOT NULL default '0', + revokedby int NOT NULL default '0', + revokereason text NOT NULL default '', + notes text NOT NULL default '', + PRIMARY KEY(wid) +);"; + + diff --git a/Upload/install/resources/settings.xml b/Upload/install/resources/settings.xml new file mode 100644 index 0000000..0e2bd39 --- /dev/null +++ b/Upload/install/resources/settings.xml @@ -0,0 +1,2434 @@ + + + + + Board Closed + + 1 + + + 1 + + + Board Closed Reason + + 2 + + + 1 + + + + + Board Name + + 1 + + + 1 + + + Board URL + Include the http://. Do NOT include a trailing slash.]]> + 2 + + + 1 + + + Homepage Name + + 3 + + + 1 + + + Homepage URL + + 4 + + + 1 + + + Admin Email + + 5 + + + 1 + + + Return Email + + 6 + + + 1 + + + Contact Us Link + + 7 + + + 1 + + + Cookie Domain + + 8 + + + 1 + + + Cookie Path + + 9 + + + 1 + + + Cookie Prefix + + 10 + + + 1 + + + Show Version Numbers + + 11 + + + 1 + + + Mailing Address + + 12 + + + 1 + + + Contact Fax No + + 13 + + + 1 + + + + + Default Language + + 1 + + + 1 + + + <![CDATA[CAPTCHA Images for Registration & Posting]]> + + 2 + + + 1 + + + <![CDATA[reCAPTCHA Public Key]]> + + 3 + + + 1 + + + <![CDATA[reCAPTCHA Private Key]]> + + 4 + + + 1 + + + <![CDATA[Are You a Human Publisher Key]]> + + 5 + + + 1 + + + <![CDATA[Are You a Human Scoring Key]]> + + 6 + + + 1 + + + Reported Posts Medium + + 7 + + + 1 + + + Stats Limit + + 8 + + + 1 + + + Show Top Referrer on Statistics Page + + 9 + + + 1 + + + Decimal Point + + 10 + + + 1 + + + Thousands Numeric Separator + + 11 + + + 1 + + + Show Language Selector in Footer + + 12 + + + 1 + + + Show Theme Selector in Footer + + 13 + + + 1 + + + Maximum Page Links in Pagination + + 14 + + + 1 + + + Show Jump To Page form in Pagination + + 15 + + + 1 + + + Disable All Plugins + + 16 + + + 1 + + + Enable Soft Delete + + 17 + + + 1 + + + Enable Help Documents Search + + 18 + + + 1 + + + Expire Old Group Invites + + 19 + + + 1 + + + Hide Websites To Groups + + 20 + + + 1 + + + Hide Signatures To Groups + + 21 + + + 1 + + + + + Enable search engine friendly URLs? + Once this setting is enabled you need to make sure you have the MyBB .htaccess in your MyBB root directory (or the equivalent for your web server). Automatic detection may not work on all servers. Please see the MyBB Docs for assistance.]]> + 1 + + + 1 + + + Enable search engine friendly URLs in Archive? + Once this setting is enabled ensure the archive still works as expected.]]> + 2 + + + 1 + + + Use GZip Page Compression? + + 3 + + + 1 + + + GZip Page Compression Level + + 4 + + + 1 + + + Send No Cache Headers + + 5 + + + 1 + + + Friendly Redirection Pages + + 6 + + + 1 + + + *NIX Load Limiting + + 7 + + + 1 + + + Output template start/end comments? + + 8 + + + 1 + + + Enable XMLHttp request features? + + 9 + + + 1 + + + Advanced Stats / Debug information + + 10 + + + 1 + + + Uploads Path + must be chmod 777 (on *nix servers).]]> + 11 + + + 1 + + + Use Error Handling + + 12 + + + 1 + + + Error Logging Medium + + 13 + + + 1 + + + Error Type Medium + + 14 + + + 1 + + + Error Logging Location + + 15 + + + 1 + + + Enable Forum Jump Menu? + + 16 + + + 1 + + + Scrutinize User's IP address? + + 17 + + + 1 + + + Minify Stylesheets? + + 18 + + + 1 + + + + Use a CDN? + + 19 + + + 1 + + + + URL to use for static files + + 20 + + + 1 + + + + Path to store static files + + 21 + + + 1 + + + + + + Date Format + + 1 + + + 1 + + + Time Format + + 2 + + + 1 + + + Date/Time Separator + + 3 + + + 1 + + + Registered Date Format + + 4 + + + 1 + + + Default Timezone Offset + + 5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + 1 + + + Day Light Savings Time + + 6 + + + 1 + + + + + Show Forum Descriptions? + + 1 + + + 1 + + + Subforums to show on Index listing + + 2 + + + 1 + + + Show Subforum Status Icons? + + 3 + + + 1 + + + Hide Private Forums? + + 4 + + + 1 + + + Forums' Moderator Listing + + 5 + + + 1 + + + Show Today's Birthdays? + + 6 + + + 1 + + + Only Show Birthdays with x Posts + + 7 + + + 1 + + + Show Who's Online? + + 8 + + + 1 + + + Show Small Stats Section + + 9 + + + 1 + + + Show x viewing forum + + 10 + + + 1 + + + + + Threads Per Page + + 1 + + + 1 + + + Replies For Hot Topic + + 2 + + + 1 + + + Views For Hot Topic + + 3 + + + 1 + + + User Selectable Threads Per Page + + 4 + + + 1 + + + Use 'dot' Icons + + 5 + + + 1 + + + Use Thread Ratings? + + 6 + + + 1 + + + Users Browsing this Forum + + 7 + + + 1 + + + Announcements Limit + + 8 + + + 1 + + + Attempt to Mark Parent Forums as Read + MyBB Docs for more information regarding this change.]]> + 9 + + + 1 + + + + + Post Layout + + 1 + + + 1 + + + Posts Per Page: + + 2 + + + 1 + + + User Selectable Posts Per Page + + 3 + + + 1 + + + Maximum Avatar Dimensions in Posts + + 4 + + + 1 + + + Read Threads in Database (Days) + + 5 + + + 1 + + + Usenet Style Thread View + + 6 + + + 1 + + + Show Quick Reply Form + + 7 + + + 1 + + + Show Multi-quote Buttons + + 8 + + + 1 + + + Show 'Similar Threads' Table + + 9 + + + 1 + + + Similar Threads Relevancy Rating + + 10 + + + 1 + + + Similar Threads Limit + + 11 + + + 1 + + + Show Forum Multipage Dropdown + + 12 + + + 1 + + + Users Browsing this Thread + + 13 + + + 1 + + + Delayed Thread View Updates + + 14 + + + 1 + + + + + Disable Registrations + + 1 + + + 1 + + + Registration Method + + 2 + + + 1 + + + Force Users to Login + + 3 + + + 1 + + + Minimum Username Length + + 4 + + + 1 + + + Maximum Username Length + + 5 + + + 1 + + + Minimum Password Length + + 6 + + + 1 + + + Maximum Password Length + + 7 + + + 1 + + + Require a complex password? + + 8 + + + 1 + + + Time Between Registrations + + 9 + + + 1 + + + Maximum Registrations Per IP Address + + 10 + + + 1 + + + <![CDATA[Allow emails to be registered multiple times?]]> + + 11 + + + 1 + + + Users Keep Email + + 12 + + + 1 + + + Display a hidden CAPTCHA + + 13 + + + 1 + + + Hidden CAPTCHA field + + 14 + + + 1 + + + Use Referrals System + + 15 + + + 1 + + + COPPA Compliance + COPPA support on your forums, please select the registration allowance below.]]> + 16 + + + 1 + + + Allowed Login Methods + + 17 + + + 0 + + + Number of failed logins before verification required + + 18 + + + 1 + + + Number of times to allow failed logins + + 19 + + + 1 + + + Time between failed logins + + 20 + + + 1 + + + Display number of failed logins + + 21 + + + 1 + + + Minimum Registration Time + + 22 + + + 1 + + + Show Security Question + + 23 + + + 1 + + + + + Allow MyCode in Signatures + + 1 + + + 1 + + + MyCode affects signature length + + 2 + + + 1 + + + Allow Smilies in Signatures + + 3 + + + 1 + + + Allow HTML in Signatures + + 4 + + + 1 + + + Allow [img] Code in Signatures + + 5 + + + 1 + + + Maximum Number of Images per Signature + + 6 + + + 1 + + + Length limit in Signatures + + 7 + + + 1 + + + Default User Avatar + + 8 + + + 1 + + + Default Avatar Dimensions + + 9 + + + 1 + + + Gravatar Rating + +
  • G: suitable for display on all websites with any audience type
  • +
  • PG: may contain rude gestures, provocatively dressed individuals, the lesser swear words or mild violence
  • +
  • R: may contain such things as harsh profanity, intense violence, nudity or hard drug use
  • +
  • X: may contain hardcore sexual imagery or extremely disturbing violence
  • +]]>
    + 10 + + + 1 +
    + + Maximum Avatar Dimensions + xheight. If this is left blank then there will be no dimension restriction.]]> + 11 + + + 1 + + + Max Uploaded Avatar Size + + 12 + + + 1 + + + Avatar Resizing Mode + + 13 + + + 1 + + + Avatar Upload Path + must be chmod 777 (writable) for uploads to work.]]> + 14 + + + 1 + + + Custom User Title Maximum Length + + 15 + + + 1 + + + Allow Away Statuses? + + 16 + + + 1 + + + Allow Buddy-Only Messaging? + + 17 + + + 1 + +
    + + + Minimum Message Length + + 1 + + + 1 + + + Maximum Message Length + This should correlate with the message column type in the posts database table, and adjust accordingly. Below are the maximum lengths for each column type. +
      +
    • TEXT: 65535 (default)
    • +
    • MEDIUMTEXT: 16777215
    • +
    • LONGTEXT: 4294967295
    • +
    ]]>
    + 2 + + + 1 +
    + + MyCode Affects Minimum Message Length? + + 3 + + + 1 + + + Post Flood Checking + + 4 + + + 1 + + + Post Flood Time + + 5 + + + 1 + + + Post Merge Time + + 6 + + + 1 + + + Merge Forums to Ignore + + 7 + + + 1 + + + Merge User Groups to Ignore + + 8 + + + 1 + + + Merge Separator + + 9 + + + 1 + + + Show Posting IP Addresses + + 10 + + + 1 + + + Show 'edited by' Messages + + 11 + + + 1 + + + Show 'edited by' Message for Administrators + + 12 + + + 1 + + + Maximum Images per Post + + 13 + + + 1 + + + Maximum Videos per Post + + 14 + + + 1 + + + Amount of Characters for Subscription Previews + + 15 + + + 1 + + + Number of Characters before Word Wrapping Occurs + + 16 + + + 1 + + + Maximum Nested Quote Tags + + 17 + + + 1 + + + Maximum Poll Option Length + + 18 + + + 1 + + + Maximum Number of Poll Options + + 19 + + + 1 + + + Poll Time Limit + + 20 + + + 1 + + + Show Thread Review + + 21 + + + 1 + + + Allow Edit Reason + + 22 + + + 1 + +
    + + + Enable Attachment Functionality + + 1 + + + 1 + + + Maximum Attachments Per Post + + 2 + + + 1 + + + Show Attached Thumbnails in Posts + + 3 + + + 1 + + + Attached Thumbnail Maximum Height + + 4 + + + 1 + + + Attached Thumbnail Maximum Width + + 5 + + + 1 + + + + + Enable Member List Functionality + + 1 + + + 1 + + + Members Per Page + + 2 + + + 1 + + + Default Sort Field + + 3 + + + 1 + + + Default Sort Order + Ascending: A-Z / beginning-end
    Descending: Z-A / end-beginning]]>
    + 4 + + + 1 +
    + + Maximum Display Avatar Dimensions + + 5 + + + 1 + +
    + + + Enable Reputation Functionality + + 1 + + + 1 + + + Allow Positive Reputation + + 2 + + + 1 + + + Allow Negative Reputation + + 3 + + + 1 + + + Allow Neutral Reputation + + 4 + + + 1 + + + Allow Multiple Reputation + Note: Does not effect "Post" reputation]]> + 5 + + + 1 + + + Allow Post Reputations + + 6 + + + 1 + + + Reputation Comments Per Page + + 7 + + + 1 + + + Maximum Reputation Length + + 8 + + + 1 + + + Minimum Reputation Length + + 9 + + + 1 + + + + + Enable Warning System? + + 1 + + + 1 + + + Allow Custom Warning Types? + + 2 + + + 1 + + + Can Users View Own Warnings? + + 3 + + + 1 + + + Allow Anonymous Warning PMs + + 4 + + + 1 + + + Maximum Warning Points + + 5 + + + 1 + + + + + Enable Private Messaging Functionality + + 1 + + + 1 + + + Show Quick Reply Form + + 2 + + + 1 + + + Allow HTML + + 3 + + + 1 + + + Allow MyCode + + 4 + + + 1 + + + Allow Smilies + + 5 + + + 1 + + + Allow [img] Code + + 6 + + + 1 + + + Allow [video] Code + + 7 + + + 1 + + + Private Message Flood Time + + 8 + + + 1 + + + Show Private Message IP Addresses + + 9 + + + 1 + + + Maximum PM Nested Quote Tags + + 10 + + + 1 + + + + + Enable Calendar Functionality + + 1 + + + 1 + + + + + Cut-off Time (mins) + + 1 + + + 1 + + + Refresh Who's online page Time (mins) + + 2 + + + 1 + + + Who's Online Order + + 3 + + + 1 + + + + + Enable user pruning? + + 1 + + + 1 + + + Prune user by post count? + + 2 + + + 1 + + + Post count to prune by + + 3 + + + 1 + + + Days registered before pruning by post count + + 4 + + + 1 + + + Prune unactivated users? + + 5 + + + 1 + + + Days registered before pruning unactivated users + + 6 + + + 1 + + + Prune User Posts/Threads + + 7 + + + 1 + + + + + Enable Portal + + 1 + + + 1 + + + Forums to pull announcements from + + 2 + + + 1 + + + Number of announcements to show + + 3 + + + 1 + + + Show the Welcome box + + 4 + + + 1 + + + Show the number of PMs to users + + 5 + + + 1 + + + Show forum statistics + + 6 + + + 1 + + + Show Who's Online + + 7 + + + 1 + + + Show Search Box + + 8 + + + 1 + + + Show Latest Discussions + + 9 + + + 1 + + + Number of latest discussions to show + + 10 + + + 1 + + + Forums to exclude latest discussions from + + 11 + + + 1 + + + + + Search Type + + 1 + ".($db->supports_fulltext("threads") && $db->supports_fulltext_boolean("posts")?"":"")."]]> + + 1 + + + Search Flood Time (seconds) + + 2 + + + 1 + + + Minimum Search Word Length + + 3 + + + 1 + + + Hard Limit for Maximum Search Results + + 4 + + + 1 + + + + + Clickable MyCode Editor + + 1 + + + 1 + + + Clickable MyCode Editor in Partial Mode + + 2 + + + 0 + + + Clickable Smilies Inserter + + 3 + + + 1 + + + No. of Smilies to show + + 4 + + + 1 + + + No. of Smilie Cols to Show + + 5 + + + 1 + + + Allow Basic MyCodes + + 6 + + + 1 + + + Allow Color MyCode + + 7 + + + 1 + + + Allow Size MyCode + + 8 + + + 1 + + + Allow Font MyCode + + 9 + + + 1 + + + Allow Link MyCode + + 10 + + + 1 + + + Allow Email MyCode + + 11 + + + 1 + + + Allow Alignment MyCode + + 12 + + + 1 + + + Allow List MyCode + + 13 + + + 1 + + + Allow Code MyCodes + + 14 + + + 1 + + + Allow Symbol MyCodes + + 15 + + + 1 + + + Allow Me MyCodes + + 16 + + + 1 + + + Parse [img] MyCode To Guests + + 17 + + + 1 + + + Parse [video] MyCode To Guests + + 18 + + + 1 + + + + + Control Panel Language + + 1 + + + 1 + + + Control Panel Style + + 2 + + + 1 + + + Max Number of Login Attempts + + 3 + + + 1 + + + Login Attempts Timeout + + 4 + + + 1 + + + + + Mail handler + + 1 + + + 1 + + + SMTP hostname + Only required if SMTP Mail is selected as the Mail Handler.]]> + 2 + + + 1 + + + SMTP port + Only required if SMTP Mail is selected as the Mail Handler.]]> + 3 + + + 1 + + + SMTP username + Only required if SMTP Mail is selected as the Mail Handler, and the SMTP server requires authentication.]]> + 4 + + + 1 + + + SMTP password + Only required if SMTP Mail is selected as the Mail Handler, and the SMTP server requires authentication.]]> + 5 + + + 1 + + + SMTP Encryption Mode + Only required if SMTP Mail is selected as the Mail Handler.]]> + 6 + + + 1 + + + Additional Parameters for PHP's mail() + More information]]> + 7 + + + 1 + + + Mail Logging + + 8 + + + 1 + + + Add message ID in mail headers + + 9 + + + 1 + + + + + Enable Contact Page + + 1 + + + 1 + + + Disable Contact Page to Guests + + 2 + + + 1 + + + Enable Word Filter on Contact Page + + 3 + + + 1 + + + Maximum Subject Length on Contact Page + + 4 + + + 1 + + + Minimum Message Length on Contact Page + + 5 + + + 1 + + + Maximum Message Length on Contact Page + + 6 + + + 1 + + + + + Allowed Usergroups + + 1 + + + 1 + + + + Post Limit + + 2 + + + 1 + + + + Ban or Delete Spammers + + 3 + + + 1 + + + + Ban Usergroup + + 4 + + + 1 + + + + Ban Reason + + 5 + + + 1 + + + + Stop Forum Spam API Key + here. When you have your key, paste it into the box below.]]> + 6 + + + 1 + + + + + + Check Registrations Against StopForumSpam.com? + + + 1 + + + 1 + + + Check Guest Contact Submissions Against StopForumSpam? + + + 2 + + + 1 + + + Check Guest Replies Against StopForumSpam? + + + 3 + + + 1 + + + Check Guest Threads Against StopForumSpam? + + + 4 + + + 1 + + + Minimum stop forum spam weighting? + + + 5 + + + 1 + + + Check usernames? + + + 6 + + + 1 + + + Check email addresses? + + + 7 + + + 1 + + + Check IP addresses? + + + 8 + + + 1 + + + Block on StopForumSpam error? + + + 9 + + + 1 + + + Log StopForumSpam blocks? + + + 10 + + + 1 + + + + + Allow ICQ Number Field To Usergroups + + 1 + + + 1 + + + + Allow AIM Screen Name To Usergroups + + 2 + + + 1 + + + + Allow Yahoo ID Field To Usergroups + + 3 + + + 1 + + + + Allow Skype ID Field To Usergroups + + 4 + + + 1 + + + + Allow Google Talk ID Field To Usergroups + + 5 + + + 1 + + + + + + Enable Statistics Pages + + 1 + + + 1 + + + + Statistics Cache Time + + 2 + + + 1 + + + +
    diff --git a/Upload/install/resources/sqlite_db_tables.php b/Upload/install/resources/sqlite_db_tables.php new file mode 100644 index 0000000..7107b3a --- /dev/null +++ b/Upload/install/resources/sqlite_db_tables.php @@ -0,0 +1,1040 @@ + + + + Czyszczenie cogodzinne + + hourlycleanup + 0 + * + * + * + * + 1 + 1 + + + Dziennie czyszczenie + + dailycleanup + 0 + 0 + * + * + * + 1 + 1 + + + Czyszczenie użytkowników co pół godziny + + usercleanup + 30,59 + * + * + * + * + 1 + 1 + + + Tygodniowa kopia zapasowa + + backupdb + 0 + 0 + * + 0 + * + 0 + 1 + + + System awansów + + promotions + 5,25,45 + * + * + * + * + 1 + 1 + + + Liczba wyświetleń wątków + + threadviews + 10,25,40,55 + * + * + * + * + 0 + 1 + + + Sprawdzenie tabel + + checktables + 0 + * + * + * + * + 0 + 1 + + + Czyszczenie logów + + logcleanup + 21 + 5 + * + * + * + 1 + 1 + + + Masowa korespondencja + + massmail + 10,25,40,55 + * + * + * + * + 1 + 1 + + + Czyszczenie użytkowników + + userpruning + * + 2 + * + * + * + 1 + 1 + + + Opóźniona moderacja + + delayedmoderation + 0 + 0 + * + * + * + 1 + 1 + + + Sprawdzanie wersji + + versioncheck + 0 + 0 + * + * + * + 1 + 1 + + + Przebudowa cache arkuszy stylów + + recachestylesheets + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + \ No newline at end of file diff --git a/Upload/install/resources/upgrade1.php b/Upload/install/resources/upgrade1.php new file mode 100644 index 0000000..9463659 --- /dev/null +++ b/Upload/install/resources/upgrade1.php @@ -0,0 +1,408 @@ + 1, + "revert_all_themes" => 1, + "revert_all_settings" => 1, + "requires_deactivated_plugins" => 1, +); + +function upgrade1_dbchanges() +{ + global $db, $output; + + $output->print_header("Dokonywanie zmian w bazie danych"); + + $contents .= "

    Trwa dokonywanie wymaganych zmian w bazie danych..."; + + if($db->field_exists('regip', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP regid;"); + } + $db->write_query("ALTER TABLE users ADD regip varchar(50) NOT NULL;"); + + $db->write_query("ALTER TABLE banned CHANGE lifted lifted varchar(40) NOT NULL;"); + + if($db->field_exists('posthash', "attachments")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments DROP posthash;"); + } + $db->write_query("ALTER TABLE attachments ADD posthash varchar(50) NOT NULL AFTER pid;"); + + if($db->field_exists('thumbnail', "attachments")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments DROP thumbnail;"); + } + $db->write_query("ALTER TABLE attachments ADD thumbnail blob NOT NULL"); + + if($db->field_exists('thumbnailsm', "attachments")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments DROP thumbnailsm;"); + } + $db->write_query("ALTER TABLE attachments ADD thumbnailsm char(3) NOT NULL;"); + + $db->write_query("DELETE FROM attachtypes"); + $db->write_query("INSERT INTO attachtypes VALUES(NULL,'Archiwum skompresowane','','zip gz tar rar ace cab','1024');"); + $db->write_query("INSERT INTO attachtypes VALUES(NULL,'Obraz JPEG','','jpg jpe jpeg','500');"); + $db->write_query("INSERT INTO attachtypes VALUES(NULL,'Dokument tekstowy','text/plain','txt','200');"); + $db->write_query("INSERT INTO attachtypes VALUES(NULL,'Obraz GIF','image/gif','gif','500');"); + $db->write_query("INSERT INTO attachtypes VALUES(NULL,'Mapa bitowa','','bmp','500');"); + $db->write_query("INSERT INTO attachtypes VALUES(NULL,'Plik PHP','','php phps php3 php4','500');"); + $db->write_query("INSERT INTO attachtypes VALUES(NULL,'Obraz PNG','image/png image/x-png','png','50');"); + $db->write_query("INSERT INTO attachtypes VALUES(NULL,'Dokument Microsoft Word','','doc rtf','1024');"); + $db->write_query("INSERT INTO attachtypes VALUES(NULL,'Plik wykonywalny','','exe com bat','1024');"); + + if($db->field_exists('small', "themes")) + { + $db->write_query("ALTER TABLE themes DROP small;"); + } + if($db->field_exists('smallend', "themes")) + { + $db->write_query("ALTER TABLE themes DROP smallend;"); + } + if($db->field_exists('font', "themes")) + { + $db->write_query("ALTER TABLE themes DROP font;"); + } + if($db->field_exists('frontend', "themes")) + { + $db->write_query("ALTER TABLE themes DROP fontend;"); + } + if($db->field_exists('large', "themes")) + { + $db->write_query("ALTER TABLE themes DROP large;"); + } + if($db->field_exists('largeend', "themes")) + { + $db->write_query("ALTER TABLE themes DROP largeend;"); + } + + if($db->field_exists('smallfont', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP smallfont;"); + } + $db->write_query("ALTER TABLE themes ADD smallfont varchar(150) NOT NULL;"); + + if($db->field_exists('smallfontsize', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP smallfontsize;"); + } + $db->write_query("ALTER TABLE themes ADD smallfontsize varchar(20) NOT NULL;"); + + if($db->field_exists('normalfont', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP normalfont;"); + } + $db->write_query("ALTER TABLE themes ADD normalfont varchar(150) NOT NULL;"); + + if($db->field_exists('normalfontsize', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP normalfontsize;"); + } + $db->write_query("ALTER TABLE themes ADD normalfontsize varchar(20) NOT NULL;"); + + if($db->field_exists('largefont', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP largefont;"); + } + $db->write_query("ALTER TABLE themes ADD largefont varchar(150) NOT NULL;"); + + if($db->field_exists('largefontsize', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP largefontsize;"); + } + $db->write_query("ALTER TABLE themes ADD largefontsize varchar(20) NOT NULL;"); + + if($db->field_exists('menubgcolor', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP menubgcolor;"); + } + $db->write_query("ALTER TABLE themes ADD menubgcolor varchar(15) NOT NULL;"); + + if($db->field_exists('menubgimage', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP menubgimage;"); + } + $db->write_query("ALTER TABLE themes ADD menubgimage varchar(100) NOT NULL;"); + + if($db->field_exists('menucolor', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP menucolor;"); + } + $db->write_query("ALTER TABLE themes ADD menucolor varchar(15) NOT NULL;"); + + if($db->field_exists('menuhoverbgcolor', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP menuhoverbgcolor;"); + } + $db->write_query("ALTER TABLE themes ADD menuhoverbgcolor varchar(15) NOT NULL;"); + + if($db->field_exists('menuhoverbgimage', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP menuhoverbgimage;"); + } + $db->write_query("ALTER TABLE themes ADD menuhoverbgimage varchar(100) NOT NULL;"); + + if($db->field_exists('menuhovercolor', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP menuhovercolor;"); + } + $db->write_query("ALTER TABLE themes ADD menuhovercolor varchar(15) NOT NULL;"); + + if($db->field_exists('panelbgcolor', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP panelbgcolor;"); + } + $db->write_query("ALTER TABLE themes ADD panelbgcolor varchar(15) NOT NULL;"); + + if($db->field_exists('panelbgimage', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP panelbgimage;"); + } + $db->write_query("ALTER TABLE themes ADD panelbgimage varchar(100) NOT NULL;"); + + if($db->field_exists('linkhover', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP linkhover;"); + } + $db->write_query("ALTER TABLE themes ADD linkhover varchar(15) NOT NULL AFTER link;"); + + if($db->field_exists('extracss', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP extracss;"); + } + $db->write_query("ALTER TABLE themes ADD extracss varchar(10) NOT NULL AFTER linkhover;"); + + + $db->write_query("UPDATE themes SET linkhover='#000000'"); + + $db->write_query("UPDATE themes SET smallfont='Verdana', smallfontsize='11px', normalfont='Verdana', normalfontsize='13px', largefont='Verdana', largefontsize='20px';"); + + $contents .= "zakończono

    "; + + $db->drop_table("settinggroups", false, false); + $db->write_query("CREATE TABLE settinggroups ( + gid smallint(6) NOT NULL auto_increment, + name varchar(220) NOT NULL default '', + description text NOT NULL, + disporder smallint(6) NOT NULL default '0', + isdefault char(3) NOT NULL default '', + PRIMARY KEY (gid) + );"); + + $db->drop_table("settings", false, false); + $db->write_query("CREATE TABLE settings ( + sid smallint(6) NOT NULL auto_increment, + name varchar(120) NOT NULL default '', + title varchar(120) NOT NULL default '', + description text NOT NULL, + optionscode text NOT NULL, + value text NOT NULL, + disporder smallint(6) NOT NULL default '0', + gid smallint(6) NOT NULL default '0', + PRIMARY KEY (sid) + );"); + + $output->print_contents("$contents

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "); + $output->print_footer("1_dbchanges2"); +} +function upgrade1_dbchanges2() +{ + global $db, $output; + + $output->print_header("Dokonywanie zmian w bazie danych"); + + $db->write_query("DELETE FROM themes"); + $arr = @file("./resources/theme.mybb"); + $contents = @implode("", $arr); + + // now we have $contents we can start dealing with the .theme file! + $themee = explode("(_!&!_)", $contents); + $thver = $themee[0]; + $thname = "Light"; + $thcontents = $themee[2]; + $thtemplates = $themee[3]; + + // go through the actual theme part (colours etc) + $themefile = explode("|#*^^&&^^*#|", $thcontents); + $themeq1 = ""; + $themeq2 = ""; + foreach($themefile as $key => $val) + { + list($item, $value) = explode("|#*!!**!!*#|", $val); + if($db->field_exists($item, "themes")) + { + $themebits[$item] = $value; + } + } + + // add the theme set + $tquery1 = ""; + $tquery2 = ""; + unset($themebits['templateset']); + foreach($themebits as $key => $val) + { + if($key && $val) + { + $tquery1 .= ",$key"; + $tquery2 .= ",'$val'"; + } + } + $db->write_query("INSERT INTO themes (tid,name,templateset$tquery1) VALUES ('','((master))','$sid'$tquery2)"); + $thetid = $db->write_query("INSERT INTO themes (tid,name,templateset$tquery1) VALUES ('','$thname','$sid2'$tquery2)"); + $db->write_query("UPDATE themes SET def='1' WHERE tid='$thetid'"); + + $output->print_contents("Domyślny styl został zaimportowany

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "); + $output->print_footer("1_dbchanges3"); +} +function upgrade1_dbchanges3() +{ + + global $db, $output; + + $output->print_header("Dokonywanie zmian w bazie danych"); + + $contents .= "

    Ponowne tworzenie ustawień..."; + + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (1, 'General Configuration', 'This section contains various settings such as your board name and url, as well as your website name and url.', 2, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (3, 'Date and Time Formats', 'Here you can specify the different date and time formats used to display dates and times on the forums.', 4, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (7, 'Forum Display Options', 'This section allows you to manage the various settings used on the forum fisplay (forumdisplay.php) of your boards such as enabling and disabling different features.', 6, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (8, 'Show Thread Options', 'This section allows you to manage the various settings used on the thread display page (showthread.php) of your boards such as enabling and disabling different features.', 7, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (10, 'MyCode and Formatting Options', '', 16, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (11, 'Private Messaging', 'Various options with relation to the MyBB Private Messaging system (private.php) can be managed and set here.', 11, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (12, 'Member List', 'This section allows you to control various aspects of the board member listing (memberlist.php), such as how many members to show per page, and which features to enable or disable.', 10, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (13, 'Posting', 'These options control the various elements in relation to posting messages on the forums.', 9, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (14, 'Banning Options', '', 15, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (16, 'Forum Home Options', 'This section allows you to manage the various settings used on the forum home (index.php) of your boards such as enabling and disabling different features.', 5, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (17, 'Calendar', 'The board calendar allows the public and private listing of events and members\' birthdays. This section allows you to control and manage the settings for the Calendar.', 12, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (27, 'Server and Optimization Options', 'These options allow you to set various server and optimization preferences allowing you to reduce the load on your server, and gain better performance on your board.', 3, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (19, 'User Registration and Profile Options', 'Here you can control various settings with relation to user account registration and account management.', 8, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (20, 'Clickable Smilies and BB Code', '', 17, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (21, 'Common Language Bits', '', 18, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (23, 'Who\'s Online', '', 13, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (26, 'Board Online / Offline', 'These settings allow you to globally turn your forums online or offline, and allow you to specify a reason for turning them off.', 1, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (28, 'Control Panel Preferences (Global)', '', 19, 'yes');"); + $db->write_query("INSERT INTO `settinggroups` (`gid`, `name`, `description`, `disporder`, `isdefault`) VALUES (30, 'Portal Settings', '', 14, 'yes');"); + + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (1, 'boardclosed', 'Board Closed', 'If you need to close your forums to make some changes or perform an upgrade, this is the global switch. Viewers will not be able to view your forums, however, they will see a message with the reason you specify below.
    \r\n
    \r\nAdministrators will still be able to view the forums.', 'yesno', 'no', 1, 26);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (2, 'boardclosed_reason', 'Board Closed Reason', 'If your forum is closed, you can set a message here that your visitors will be able to see when they visit your forums.', 'textarea', 'These forums are currently closed for maintenance. Please check back later.', 2, 26);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (3, 'bbname', 'Board Name', 'The name of your message boards. We recommend that it is not over 75 characters.', 'text', 'MyBB Community Forums', 1, 1);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (4, 'bburl', 'Board URL', 'The url to your forums.
    Include the http://. Do NOT include a trailing slash.', 'text', 'http://www.mybb.com/community', 2, 1);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (5, 'homename', 'Homepage Name', 'The name of your homepage. This will appear in the footer with a link to it.', 'text', 'MyBB', 3, 1);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (6, 'homeurl', 'Homepage URL', 'The full URL of your homepage. This will be linked to in the footer along with its name.', 'text', 'http://www.mybb.com', 4, 1);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (7, 'reportviapms', 'Send Reported Posts via PMS', 'Do you want to send reported post messages via the private messaging function to moderators?', 'yesno', 'yes', 5, 8);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (8, 'dateformat', 'Date Format', 'The format of the dates used on the forum. This format uses the PHP date() function. We recommend not changing this unless you know what you\'re doing.', 'text', 'm-d-Y', 1, 3);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (9, 'adminemail', 'Admin Email', 'The administrator\'s email address. This will be used for outgoing emails sent via the forums.', 'text', 'contact@mybb.com', 1, 1);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (10, 'timeformat', 'Time Format', 'The format of the times used on the forum. This format uses PHP\'s date() function. We recommend not changing this unless you know what you\'re doing.', 'text', 'h:i A', 2, 3);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (11, 'threadsperpage', 'Threads Per Page', '', 'text', '20', 1, 7);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (12, 'stickyprefix', 'Sticky Threads Prefix', 'The prefix of topics which have been made sticky by a moderator or administrator.', 'text', 'Sticky:', 2, 7);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (13, 'hottopic', 'Replys For Hot Topic', 'The number of replies that is needed for a topic to be considered \'hot\'.', 'text', '20', 3, 7);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (14, 'cookiedomain', 'Cookie Domain', 'The domain which cookies should be set to. This can remain blank. It should also start with a . so it covers all subdomains.', 'text', '', 5, 1);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (15, 'cookiepath', 'Cookie Path', 'The path which cookies are set to, we recommend setting this to the full directory path to your forums with a trailing slash.', 'text', '', 6, 1);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (16, 'pollprefix', 'Poll Prefix', 'The prefix on forum display which contain polls.', 'text', 'Poll:', 4, 7);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (17, 'postsperpage', 'Posts Per Page:', 'The number of posts to display per page. We recommend its not higher than 20 for people with slower connections.', 'text', '10', 1, 8);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (18, 'regdateformat', 'Registered Date Format', 'The format used on showthread where it shows when the user registered.', 'text', 'M Y', 3, 3);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (19, 'sigmycode', 'Allow MyCode in Signatures', 'Do you want to allow MyCode to be used in users\' signatures?', 'yesno', 'yes', 1, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (20, 'sigsmilies', 'Allow Smilies in Signatures', 'Do you want to allow smilies to be used in users\' signatures?', 'yesno', 'yes', 3, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (21, 'sightml', 'Allow HTML in Signatures', 'Do you want to allow HTML to be used in users\' signatures?', 'yesno', 'no', 4, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (22, 'sigimgcode', 'Allow [img] Code in Signatures', 'Do you want to allow [img] code to be used in users\' signatures?', 'yesno', 'yes', 5, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (23, 'quoteboxstyle', 'Fancy Quote Boxes', 'Selecting yes will cause quotes to be in a table and look more professional. Selecting no will show quotes in the traditional way.', 'yesno', 'yes', 1, 10);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (24, 'codeboxstyle', 'Fancy Code Boxes', 'Selecting yes will cause code to be in a table and look more professional. Selecting no will show code in the traditional way.', 'yesno', 'yes', 2, 10);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (25, 'threadusenetstyle', 'Usenet Style Thread View', 'Selecting yes will cause posts to look similar to how posts look in USENET. No will cause posts to look the modern way.', 'yesno', 'no', 3, 8);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (26, 'pmsallowhtml', 'Allow HTML', 'Selecting yes will allow HTML to be used in private messages.', 'yesno', 'no', 1, 11);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (27, 'pmsallowmycode', 'Allow MyCode', 'Selecting yes will allow MyCode to be used in private messages.', 'yesno', 'yes', 2, 11);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (28, 'pmsallowsmilies', 'Allow Smilies', 'Selecting yes will allow Smilies to be used in private messages.', 'yesno', 'yes', 3, 11);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (29, 'pmsallowimgcode', 'Allow [img] Code', 'Selecting yes will allow [img] Code to be used in private messages.', 'yesno', 'yes', 4, 11);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (30, 'siglength', 'Length limit in Signatures', 'The maximum number of characters a user can place in a signature.', 'text', '255', 6, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (31, 'messagelength', 'Maximum Message Length', 'The maximum number of characters to allow in a message. A setting of 0 allows an unlimited length.', 'text', '0', 1, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (32, 'membersperpage', 'Members Per Page', 'The number of members to show per page on the member list.', 'text', '20', 1, 12);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (33, 'load', '*NIX Load Limiting', 'Limit the maximum server load before myBB rejects people. 0 for none. Recommended limit is 5.0.', 'text', '0', 5, 27);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (34, 'emailkeep', 'Users Keep Email', 'If a current user has an email already registered in your banned list, should he be allowed to keep it.', 'yesno', 'no', 4, 14);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (35, 'ipban', 'Ban by IP', 'Here, you may specify IP addresses or a range of IP addresses. You must separate each IP with a space.', 'textarea', '', 2, 14);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (36, 'emailban', 'Ban by Email', 'You may specify specific email addresses to ban, or you may specify a domain. You must separate email addresses and domains with a space.', 'textarea', '', 3, 14);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (37, 'avatarsize', 'Max Uploaded Avatar Size', 'Maximum file size (in kilobytes) of uploaded avatars.', 'text', '10', 8, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (38, 'avatardir', 'Avatar Directory', 'The directory where your avatars are stored. These are used in the avatar list in the User CP.', 'text', 'images/avatars', 7, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (39, 'showeditedby', 'Show \'edited by\' Messages', 'Once a post is edited by a regular user, do you want to show the edited by message?', 'yesno', 'yes', 6, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (40, 'maxposts', 'Maximum Posts Per Day', 'This is the total number of posts allowed per user per day. 0 for unlimited.', 'text', '0', 2, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (41, 'showeditedbyadmin', 'Show \'edited by\' Message for Forum Staff', 'Do you want to show edited by messages for forum staff when they edit their posts?', 'yesno', 'yes', 7, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (42, 'bannedusernames', 'Banned Usernames', 'Ban users from registering certain usernames. Seperate them with a space.', 'textarea', 'drcracker Oops! hmmm', 1, 14);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (43, 'maxpolloptions', 'Maximum Number of Poll Options', 'The maximum number of options for polls that users can post.', 'text', '10', 3, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (44, 'dotfolders', 'Use \'dot\' Icons', 'Do you want to show dots on the thread indicators of threads users have participated in.', 'yesno', 'yes', 8, 7);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (45, 'contactlink', 'Contact Us Link', 'This will be used for the Contact Us link on the bottom of all the forum pages. Can either be an email address (using mailto:email@website.com) or a hyperlink.', 'text', 'mailto:contact@mybb.com', 2, 1);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (46, 'showdescriptions', 'Show Forum Descriptions?', 'This option will allow you to turn off showing the descriptions for forums.', 'yesno', 'yes', 1, 16);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (47, 'showbirthdays', 'Show Today\'s Birthdays?', 'Do you want to show today\'s birthdays on the forum homepage?', 'yesno', 'yes', 2, 16);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (48, 'showwol', 'Show Who\'s Online?', 'Display the currently active users on the forum home page.', 'yesno', 'yes', 4, 16);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (49, 'hideprivateforums', 'Hide Private Forums?', 'You can hide private forums by turning this option on. This option also hides forums on the forum jump and all subforums.', 'yesno', 'yes', 3, 16);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (50, 'showsimilarthreads', 'Show \'Similar Threads\' Table', 'The Similar Threads table shows threads that are relevant to the thread being read. You can set the relevancy below.', 'yesno', 'no', 4, 8);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (51, 'similarityrating', 'Similar Threads Relevancy Rating', 'This allows you to limit similar threads to ones more relevant (0 being not relevant). This number should not be over 10 and should not be set low (<5) for large forums.', 'text', '1', 6, 8);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (52, 'similarlimit', 'Similar Threads Limit', 'Here you can change the total amount of similar threads to be shown in the similar threads table. It is recommended that it is not over 15 for 56k users.', 'text', '10', 7, 8);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (53, 'privateeventcolor', 'Private Events Color', 'The color that private events will be shown in on the main calendar page.', 'text', 'red', 2, 17);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (54, 'publiceventcolor', 'Public Events Color', 'The color that public events will be shown in on the main calendar page.', 'text', 'green', 1, 17);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (55, 'movedprefix', 'Moved Threads Prefix', 'The prefix that threads that have been moved to another forum should have.', 'text', 'Moved:', 5, 7);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (56, 'hottopicviews', 'Views For Hot Topic', 'The number of views a thread can have before it is considered \'hot\'.', 'text', '150', 7, 7);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (59, 'logip', 'Log Posting IP Addresses', 'Do you wish to log ip addresses of users who post, and who you want to show ip addresses to.', 'radio\r\nno=Do not log IP\r\nhide=Show to Admins & Mods\r\nshow=Show to all Users', 'hide', 3, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (60, 'statslimit', 'Stats Limit', 'The number of threads to show on the stats page for most replies and most views.', 'text', '15', 5, 1);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (65, 'modlist', 'Forums\' Moderator Listing', 'Here you can turn on or off the listing of moderators for each forum on index.php and forumdisplay.php', 'onoff', 'on', 5, 16);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (66, 'smilieinserter', 'Clickable Smilies Inserter', 'Clickable smilies will appear on the posting pages if this option is set to \'on\'.', 'onoff', 'on', 1, 20);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (67, 'smilieinsertertot', 'No. of Smilies to show', 'Enter the total number of smilies to show on the clickable smilie inserter.', 'text', '20', 2, 20);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (68, 'smilieinsertercols', 'No. of Smilie Cols to Show', 'Enter the number of columns you wish to show on the clickable smilie inserter.', 'text', '4', 3, 20);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (69, 'cantext', '\'Can\' text', 'The text that will be used in templates when the user has permission to perform an action (eg. post new threads).', 'text', 'can', 1, 21);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (70, 'canttext', '\'Cannot\' text', 'The text that will be used in templates when the user does not have permission to perform an action (eg. post new threads).', 'text', 'cannot', 2, 21);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (71, 'ontext', '\'On\' text', 'The text that will be used when a feature is turned On (eg. BB Code in posts).', 'text', 'On', 3, 21);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (72, 'offtext', '\'Off\' text', 'The text that will be used when a feature is turned Off (eg. BB Code in posts).', 'text', 'Off', 4, 21);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (73, 'showindexstats', 'Show Small Stats Section', 'Do you want to show the total number of threads, posts, members, and the last member on the forum home?', 'yesno', 'yes', 6, 16);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (74, 'regtype', 'Registration Method', 'Please select the method of registration to use when users register.', 'select\r\ninstant=Instant Activation\r\nverify=Send Email Verification\r\nrandompass=Send Random Password', 'verify', 1, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (75, 'userpppoptions', 'User Selectable Posts Per Page', 'If you would like to allow users to select how many posts are shown per page in a thread, enter the options they should be able to select separated with commas. If this is left blank they will not be able to choose how many posts are shown per page.', 'text', '5,10,20,25,30,40,50', 2, 8);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (76, 'usertppoptions', 'User Selectable Threads Per Page', 'If you would like to allow users to select how many threads per page are shown in a forum, enter the options they should be able to select separated with commas. If this is left blank they will not be able to choose how many threads are shown per page.', 'text', '10,20,25,30,40,50', 6, 7);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (77, 'wolcutoffmins', 'Cut-off Time (mins)', 'The number of minutes before a user is marked offline. Recommended: 15.', 'text', '15', 1, 23);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (78, 'postfloodcheck', 'Post Flood Checking', 'Set to on if you want to enable flood checking for posts. Specifiy the time between posts below.', 'onoff', 'on', 4, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (79, 'postfloodsecs', 'Post Flood Time', 'Set the time (in seconds) users have to wait between posting, to be in effect; the option above must be on.', 'text', '60', 5, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (80, 'gzipoutput', 'Use GZip Page Compression?', 'Do you want to compress pages in GZip format when they are sent to the browser? This means quicker downloads for your visitors, and less traffic usage for you. The level of the compression is set by the server\'s load.', 'yesno', 'yes', 1, 27);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (81, 'standardheaders', 'Send Standard Headers', 'With some web servers, this option can cause problems; with others, it is needed. ', 'yesno', 'no', 2, 27);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (82, 'nocacheheaders', 'Send No Cache Headers', 'With this option you can prevent caching of the page by the browser.', 'yesno', 'no', 3, 27);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (83, 'maxpostimages', 'Maximum Images per Post', 'Enter the maximum number of images (including smilies) a user can put in their post. Set to 0 to disable this.', 'text', '10', 8, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (84, 'maxsigimages', 'Maximum Number of Images per Signature', 'Enter the maximum number of images (including smilies) a user can put in their signature. Set to 0 to disable this.', 'text', '2', 2, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (85, 'browsingthisforum', 'Users Browsing this Forum', 'Here you can turn off the \'users browsing this forum\' feature.', 'onoff', 'on', 9, 7);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (86, 'usereferrals', 'Use Referrals System', 'Do you want to use the user referrals system on these forums?', 'yesno', 'yes', 3, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (87, 'subscribeexcerpt', 'Amount of Characters for Subscription Previews', 'How many characters of the post do you want to send with the email notification of a new reply.', 'text', '100', 9, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (93, 'cpstyle', 'Control Panel Style', 'The Default style that the control panel will use. Styles are inside the styles folder. A folder name inside that folder becomes the style title and style.css inside the style title folder is the css style file.', 'cpstyle', 'Axiom', 1, 28);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (121, 'cplanguage', 'Control Plane Language', 'The language of the control panel.', 'language', 'english', 1, 28);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (94, 'minnamelength', 'Minimum Username Length', 'The minimum number of characters a username can be when a user registers.', 'text', '3', 5, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (95, 'maxnamelength', 'Maximum Username Length', 'The maximum number of characters a username can be when a user registers.', 'text', '30', 6, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (96, 'redirects', 'Friendly Redirection Pages', 'This will enable friendly redirection pages instead of bumping the user directly to the page.', 'onoff', 'on', 4, 27);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (97, 'betweenregstime', 'Time Between Registrations', 'The amount of time (in hours) to disallow registrations for users who have already registered an account under the same ip address.', 'text', '24', 2, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (98, 'maxregsbetweentime', 'Maximum Registrations Per IP Address', 'This option allows you to set the maximum amount of times a certain user can register within the timeframe specified above.', 'text', '2', 4, 19);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (111, 'portal_showstats', 'Show forum statistics', 'Do you want to show the total number of posts, threads, members and the last registered member on the portal page?', 'yesno', 'yes', 5, 30);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (110, 'portal_showpms', 'Show the number of PMs to users', 'Do you want to show the number of private messages the current user has in their pm system.', 'yesno', 'yes', 4, 30);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (109, 'portal_showwelcome', 'Show the Welcome box', 'Do you want to show the welcome box to visitors / users.', 'yesno', 'yes', 3, 30);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (108, 'portal_numannouncements', 'Number of announcements to show', 'Please enter the number of announcements to show on the main page.', 'text', '10', 2, 30);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (103, 'portal_showstats', 'Show forum statistics', 'Do you want to show the total number of posts, threads, members and the last registered member on the portal page?', 'yesno', 'yes', 5, 29);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (104, 'portal_showwol', 'Show Whos Online', 'Do you want to show the \'whos online\' information to users when they visit the portal page?', 'yesno', 'yes', 6, 29);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (107, 'portal_announcementsfid', 'Forum ID to pull announcements from', 'Please enter the forum id (fid) of the forum you wish to pull the announcements from', 'text', '2', 1, 30);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (106, 'portal_showdiscussionsnum', 'Number of latest discussions to show', 'Please enter the number of current forum discussions to show on the portal page.', 'text', '10', 8, 29);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (112, 'portal_showwol', 'Show Who\'s Online', 'Do you want to show the \'Who\'s online\' information to users when they visit the portal page?', 'yesno', 'yes', 6, 30);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (113, 'portal_showsearch', 'Show Search Box', 'Do you want to show the search box, allowing users to quickly search the forums on the portal?', 'yesno', 'yes', 7, 30);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (114, 'portal_showdiscussions', 'Show Latest Discussions', 'Do you wish to show the current forum discussions on the portal page?', 'yesno', 'yes', 8, 30);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (115, 'portal_showdiscussionsnum', 'Number of latest discussions to show', 'Please enter the number of current forum discussions to show on the portal page.', 'text', '10', 9, 30);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (116, 'attachthumbh', 'Attached Thumbnail Maximum Height', 'Enter the width that attached thumbnails should be generated at.', 'text', '60', 12, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (117, 'attachthumbw', 'Attached Thumbnail Maximum Width', 'Enter the width that attached thumbnails should be generated at.', 'text', '60', 13, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (118, 'maxattachments', 'Maximum Attachments Per Post', 'THe maximum number of attachments a user is allowed to upload per post.', 'text', '5', 10, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (119, 'attachthumbnails', 'Show Attached Thumbnails in Posts', 'Do you want to show the generated thumbnails for attached images inside the posts?', 'yesno', 'yes', 11, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (120, 'polloptionlimit', 'Maximum Poll Option Length', 'The maximum length that each poll option can be. (Set to 0 to disable).', 'text', '250', 1, 13);"); + $db->write_query("INSERT INTO `settings` (`sid`, `name`, `title`, `description`, `optionscode`, `value`, `disporder`, `gid`) VALUES (122, 'timezoneoffset', 'Default Timezone Offset', 'Here you can set the default timezone offset for guests and members using the default offset.', 'text', '+10', 5, 3);"); + + $output->print_contents("$contents

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "); + $output->print_footer("1_done"); +} diff --git a/Upload/install/resources/upgrade10.php b/Upload/install/resources/upgrade10.php new file mode 100644 index 0000000..cc7cd1b --- /dev/null +++ b/Upload/install/resources/upgrade10.php @@ -0,0 +1,39 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +function upgrade10_dbchanges() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + + $db->write_query("UPDATE ".TABLE_PREFIX."templates SET version='0' WHERE version=''"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."templates CHANGE version version int unsigned NOT NULL default '0'"); + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("10_done"); +} + diff --git a/Upload/install/resources/upgrade11.php b/Upload/install/resources/upgrade11.php new file mode 100644 index 0000000..7a27aaf --- /dev/null +++ b/Upload/install/resources/upgrade11.php @@ -0,0 +1,73 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +function upgrade11_dbchanges() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + + $query = $db->simple_select("templates", "*", "title IN ('showthread_inlinemoderation','showthread_ratethread','editpost','newreply','usercp_drafts','newthread','usercp_options','forumdisplay_inlinemoderation','report','private_empty','usercp_profile','usercp_attachments','usercp_usergroups_joingroup','usercp_avatar','usercp_avatar_gallery','usercp_usergroups_memberof','managegroup','managegroup_adduser','managegroup_joinrequests','private_send','polls_editpoll','private_archive','calendar_addevent','moderation_inline_deleteposts','private_tracking','moderation_threadnotes','showthread_quickreply','member_emailuser','moderation_reports','member_login','index_loginform','moderation_deletethread','moderation_mergeposts','polls_newpoll','member_register_agreement','usercp_password','usercp_email','reputation_add','moderation_deletepoll','usercp_changeavatar','usercp_notepad','member_resetpassword','member_lostpw','usercp_changename','moderation_deleteposts','moderation_split','sendthread','usercp_editsig','private_read','error_nopermission','private_folders','moderation_move','moderation_merge','member_activate','usercp_editlists','calendar_editevent','member_resendactivation','moderation_inline_deletethreads','moderation_inline_movethreads','moderation_inline_mergeposts','moderation_inline_splitposts','member_register','showthread_moderationoptions','headerinclude','private','forumdisplay_threadlist_inlineedit_js')"); + while($template = $db->fetch_array($query)) + { + if($template['title'] == "private_read") + { + $template['template'] = str_replace("private.php?action=delete&pmid={\$pm['pmid']}", "private.php?action=delete&pmid={\$pm['pmid']}&my_post_key={\$mybb->post_code}", $template['template']); + } + elseif($template['title'] == "showthread_moderationoptions") + { + $template['template'] = str_replace('', ' +', $template['template']); + + $template['template'] = str_replace('moderation.php?action=\'+this.options[this.selectedIndex].value+\'&tid={$tid}&modtype=thread', 'moderation.php?action=\'+this.options[this.selectedIndex].value+\'&tid={$tid}&modtype=thread&my_post_key={$mybb->post_code}', $template['template']); + } + elseif($template['title'] == "headerinclude") + { + $template['template'] = str_replace('var cookieDomain = "{$mybb->settings[\'cookiedomain\']}";', 'var my_post_key = \'{$mybb->post_code}\'; +var cookieDomain = "{$mybb->settings[\'cookiedomain\']}";', $template['template']); + } + elseif($template['title'] == "forumdisplay_threadlist_inlineedit_js") + { + $template['template'] = str_replace('"xmlhttp.php?action=edit_subject"', '"xmlhttp.php?action=edit_subject&my_post_key="+my_post_key', $template['template']); + } + else + { + // Remove any duplicates + $template['template'] = str_replace("post_code}\" />", "", $template['template']); + + $template['template'] = preg_replace("##i", "\npost_code}\" />", $template['template']); + } + + // Update MyBB Javascript versions (to clear cache) + $template['template'] = str_replace("?ver=121", "?ver=1212", $template['template']); + + $db->update_query("templates", array('template' => $db->escape_string($template['template']), 'version' => '1212'), "tid='{$template['tid']}'", 1); + } + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("11_done"); +} + diff --git a/Upload/install/resources/upgrade12.php b/Upload/install/resources/upgrade12.php new file mode 100644 index 0000000..4afefad --- /dev/null +++ b/Upload/install/resources/upgrade12.php @@ -0,0 +1,1992 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0, + "requires_deactivated_plugins" => 1, +); + +@set_time_limit(0); + +// We need to globalize $db here because when this script is called +// during load_module $db is not globalized in the function +global $db; + +// FIRST STEP IS FOR INTEGER CONVERSION PROJECT + +function upgrade12_dbchanges() +{ + global $db, $output, $mybb; + + $output->print_header("Konwersja liczb całkowitych"); + + $perpage = 10000; + + $to_int = array( + "announcements" => array("aid", "allowhtml", "allowmycode", "allowsmilies"), + "forumpermissions" => array("pid", "canview","canviewthreads","candlattachments","canpostthreads","canpostreplys","canpostattachments","canratethreads","caneditposts","candeleteposts","candeletethreads","caneditattachments","canpostpolls","canvotepolls","cansearch"), + "forums" => array("fid", "active","open","allowhtml","allowmycode","allowsmilies","allowimgcode","allowpicons","allowtratings","usepostcounts","showinjump","modposts","modthreads","modattachments","overridestyle"), + "groupleaders" => array("lid", "canmanagemembers","canmanagerequests"), + "helpdocs" => array("hid", "usetranslation","enabled"), + "helpsections" => array("sid", "usetranslation","enabled"), + "moderators" => array("mid", "caneditposts","candeleteposts","canviewips","canopenclosethreads","canmanagethreads","canmovetononmodforum"), + "mycode" => array("cid", "active"), + "polls" => array("pid", "closed","multiple","public"), + "posts" => array("pid", "includesig","smilieoff"), + "privatemessages" => array("pmid", "includesig","smilieoff"), + "profilefields" => array("fid", "required","editable","hidden"), + "smilies" => array("sid", "showclickable"), + "usergroups" => array("gid","isbannedgroup","canview","canviewthreads","canviewprofiles","candlattachments","canpostthreads","canpostreplys","canpostattachments","canratethreads","caneditposts","candeleteposts","candeletethreads","caneditattachments","canpostpolls","canvotepolls","canusepms","cansendpms","cantrackpms","candenypmreceipts","cansendemail","canviewmemberlist","canviewcalendar","canviewonline","canviewwolinvis","canviewonlineips","cancp","issupermod","cansearch","canusercp","canuploadavatars","canratemembers","canchangename","showforumteam","usereputationsystem","cangivereputations","candisplaygroup","cancustomtitle"), + "users" => array("uid","allownotices","hideemail","invisible","receivepms","pmpopup","pmnotify","remember","showsigs","showavatars","showquickreply","showredirect","away"), + "threads" => array("tid", "closed") + ); + + if(!$db->field_exists('pmpopup', "users")) + { + $pmpopup_key = array_search('pmpopup', $to_int['users']); + if($pmpopup_key) + { + unset($to_int['users'][$pmpopup_key]); + } + } + + // Continuing? + if($mybb->input['last_table']) + { + $current_table = $mybb->input['last_table']; + } + else + { + $current_table = array_keys($to_int); + $current_table = $current_table[0]; + echo "

    MyBB 1.4 to wielki krok w rozwoju projektu MyBB.

    Z tego powodu, wiele danych w bazie danych musi zostać skonwertowanych do nowego formatu.

    "; + } + + echo "

    Trwa konwersja danych do nowego formatu, ten proces może zająć chwilę.

    "; + + $remaining = $perpage; + + $final_table = array_keys($to_int); + $final_table = $final_table[count($final_table)-1]; + + $next_act = "12_dbchanges"; + + $start = (int)$mybb->input['start']; + $count = $mybb->input['count']; + + foreach($to_int as $table => $columns) + { + if($table == $current_table) + { + $form_fields['last_table'] = $current_table; + if($remaining <= 0) + { + break; + } + $columns_sql = implode(",", $columns); + $primary_key = $columns[0]; + if(!$mybb->input['count']) + { + $query = $db->simple_select($table, "COUNT({$primary_key}) AS count"); + $count = $form_fields['count'] = $db->fetch_field($query, "count"); + } + if($start <= $count) + { + $end = $start+$perpage; + if($end > $count) $end = $count; + echo "

    {$table}: Konwersja {$start} do {$end} z {$count}

    "; + flush(); + $form_fields['start'] = $perpage+$start; + + $query = $db->simple_select($table, $columns_sql, "", array('order_by' => $primary_key, 'limit_start' => $start, 'limit' => $remaining)); + while($row = $db->fetch_array($query)) + { + $updated_row = array(); + foreach($columns as $column) + { + if($column == $primary_key || is_int($row[$column])) continue; + if($row[$column] == "yes" || $row[$column] == "on") + { + $updated_row[$column] = 1; + } + else if($row[$column] == "off" || $row[$column] == "no" || $row[$column] == 'new' || $row[$column] == "") + { + $updated_row[$column] = 0; + } + } + if(count($updated_row) > 0) + { + $db->update_query($table, $updated_row, "{$primary_key}={$row[$primary_key]}"); + } + --$remaining; + } + } + else + { + echo "

    {$table}: Konwersja typu kolumn

    "; + flush(); + $change_column = array(); + foreach($columns as $column) + { + // Closed does not get converted to an int + if($column == $primary_key || ($table == "threads" && $column == "closed")) + { + continue; + } + $change_column[] = "MODIFY {$column} int(1) NOT NULL default '0'"; + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."{$table} ".implode(", ", $change_column)); + + if($table == $final_table) + { + // Finished, after all this! + $next_act = "12_dbchanges1"; + } + else + { + $tbl_keys = array_keys($to_int); + $current = array_search($current_table, $tbl_keys); + $form_fields['last_table'] = $current_table = $tbl_keys[$current+1]; + $form_fields['start'] = $start = 0; + $form_fields['count'] = $count = $mybb->input['count'] = 0; + } + } + } + } + + // Still converting + if($next_act == "12_dbchanges") + { + echo "

    Zakończono

    "; + echo "

    Naciśnij przycisk Dalej, aby kontynuować proces konwersji liczb całkowitych.

    "; + foreach($form_fields as $key => $val) + { + echo ""; + } + global $footer_extra; + $footer_extra = ""; + $output->print_footer($next_act); + } + else + { + // Convert settings table + $query = $db->write_query("UPDATE ".TABLE_PREFIX."settings SET value=1 WHERE value='yes' OR value='on'"); + $query = $db->write_query("UPDATE ".TABLE_PREFIX."settings SET value=0 WHERE value='no' OR value='off'"); + echo "

    Zakończono

    "; + echo "

    Proces konwersji liczb całkowitych został zakończony.

    "; + echo "

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + global $footer_extra; + $footer_extra = ""; + + $output->print_footer($next_act); + } +} + +function upgrade12_dbchanges1() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + echo "

    Dodawanie indeksu do tabeli z prywatnymi wiadomościami... "; + flush(); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages ADD INDEX ( `uid` )"); + + echo "Zakończono.

    "; + + $contents = "

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "; + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer("12_dbchanges_post1"); +} + +function upgrade12_dbchanges_post1() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + echo "

    Dodawanie indeksu do tabeli z postami... "; + flush(); + + // This will take a LONG time on huge post databases, so we only run it isolted from most of the other queries + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts ADD INDEX ( `visible` )"); + + echo "Zakończono.

    "; + flush(); + + $contents = "

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "; + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer("12_dbchanges_post2"); +} + +function upgrade12_dbchanges_post2() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + + if($db->field_exists('longipaddress', "posts")) + { + echo "

    Usuwanie kolumny longipaddress z tabeli z postami... "; + flush(); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts DROP longipaddress;"); + + echo "Zakończono.

    "; + flush(); + } + + echo "

    Dodawanie kolumny longipaddress do tabeli z postami... "; + flush(); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts ADD longipaddress int(11) NOT NULL default '0' AFTER ipaddress"); + + echo "Zakończono.

    "; + flush(); + + $contents = "

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "; + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer("12_dbchanges_user"); +} + +function upgrade12_dbchanges_user() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + echo "

    Dodawanie indeksu do tabeli z użytkownikami... "; + flush(); + + // This will take a LONG time on huge user databases, so we only run it isolted from most of the other queries + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD INDEX ( `lastvisit` )"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD INDEX ( `regdate` )"); + + echo "Zakończono.

    "; + flush(); + + $contents = "

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "; + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer("12_dbchanges2"); +} + +function upgrade12_dbchanges2() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + if($db->field_exists('recipients', "privatemessages")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages DROP recipients;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages ADD recipients text NOT NULL AFTER fromid"); + + if($db->field_exists('deletetime', "privatemessages")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages DROP deletetime;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages ADD deletetime bigint(30) NOT NULL default '0' AFTER dateline"); + + if($db->field_exists('maxpmrecipients', "usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups DROP maxpmrecipients;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups ADD maxpmrecipients int(4) NOT NULL default '5' AFTER pmquota"); + + if($db->field_exists('canwarnusers', "usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups DROP canwarnusers;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups ADD canwarnusers int(1) NOT NULL default '0' AFTER cancustomtitle"); + + if($db->field_exists('lastip', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP lastip;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD lastip varchar(50) NOT NULL default '' AFTER regip"); + + + + if($db->field_exists('coppauser', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP coppauser;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD coppauser int(1) NOT NULL default '0'"); + + if($db->field_exists('classicpostbit', 'users')) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP classicpostbit;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD classicpostbit int(1) NOT NULL default '0'"); + + if($db->field_exists('canreceivewarnings', "usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups DROP canreceivewarnings;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups ADD canreceivewarnings int(1) NOT NULL default '0' AFTER canwarnusers"); + + if($db->field_exists('maxwarningsday', "usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups DROP maxwarningsday;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups ADD maxwarningsday int(3) NOT NULL default '3' AFTER canreceivewarnings"); + + $db->update_query("usergroups", array('canreceivewarnings' => 1), "cancp != 1"); + $db->update_query("usergroups", array('maxwarningsday' => 3, 'canwarnusers' => 1), "cancp=1 OR issupermod=1 OR gid=6"); // Admins, Super Mods and Mods + + if($db->field_exists('canmodcp', "usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups DROP canmodcp;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups ADD canmodcp int(1) NOT NULL default '0' AFTER maxwarningsday"); + $db->update_query("usergroups", array('canmodcp' => 1), "cancp=1 OR issupermod=1 OR gid='6'"); // Admins, Super Mods and Mods + + if($db->field_exists('newpms', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP newpms;"); + } + + if($db->field_exists('keywords', "searchlog")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."searchlog DROP keywords;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."searchlog ADD keywords text NOT NULL AFTER querycache"); + + if($db->field_exists('canaddpublicevents', "usergroups") && !$db->field_exists('canaddevents', "usergroups")) + { + $db->update_query("usergroups", array('canaddpublicevents' => 0), "canaddpublicevents='no'"); + $db->update_query("usergroups", array('canaddpublicevents' => 1), "canaddpublicevents='yes'"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups CHANGE canaddpublicevents canaddevents int(1) NOT NULL default '0';"); + } + + if($db->field_exists('canaddprivateevents', "usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups DROP canaddprivateevents;"); + } + + if($db->field_exists('canbypasseventmod', "usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups DROP canbypasseventmod;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups ADD canbypasseventmod int(1) NOT NULL default '0' AFTER canaddevents;"); + + if($db->field_exists('canmoderateevents', "usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups DROP canmoderateevents;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups ADD canmoderateevents int(1) NOT NULL default '0' AFTER canbypasseventmod;"); + $db->update_query("usergroups", array('canbypasseventmod' => 1, 'canmoderateevents' => 1), "cancp=1 OR issupermod=1"); + $db->update_query("usergroups", array('canbypasseventmod' => 0, 'canmoderateevents' => 0), "cancp=0 AND issupermod=0"); + $db->update_query("usergroups", array('canaddevents' => 0), "gid='1'"); + + $db->drop_table("maillogs"); + $db->drop_table("mailerrors"); + $db->drop_table("promotions"); + $db->drop_table("promotionlogs"); + $db->drop_table("massemails"); + + $collation = $db->build_create_table_collation(); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."massemails ( + mid int unsigned NOT NULL auto_increment, + uid int unsigned NOT NULL default '0', + subject varchar(200) NOT NULL default '', + message text NOT NULL, + htmlmessage text NOT NULL, + type tinyint(1) NOT NULL default '0', + format tinyint(1) NOT NULL default '0', + dateline bigint(30) NOT NULL default '0', + senddate bigint(30) NOT NULL default '0', + status tinyint(1) NOT NULL default '0', + sentcount int unsigned NOT NULL default '0', + totalcount int unsigned NOT NULL default '0', + conditions text NOT NULL, + perpage smallint(4) NOT NULL default '50', + PRIMARY KEY(mid) + ) ENGINE=MyISAM{$collation};"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."maillogs ( + mid int unsigned NOT NULL auto_increment, + subject varchar(200) not null default '', + message TEXT NOT NULL, + dateline bigint(30) NOT NULL default '0', + fromuid int unsigned NOT NULL default '0', + fromemail varchar(200) not null default '', + touid bigint(30) NOT NULL default '0', + toemail varchar(200) NOT NULL default '', + tid int unsigned NOT NULL default '0', + ipaddress varchar(20) NOT NULL default '', + PRIMARY KEY(mid) + ) ENGINE=MyISAM{$collation};"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."mailerrors( + eid int unsigned NOT NULL auto_increment, + subject varchar(200) NOT NULL default '', + message TEXT NOT NULL, + toaddress varchar(150) NOT NULL default '', + fromaddress varchar(150) NOT NULL default '', + dateline bigint(30) NOT NULL default '0', + error text NOT NULL, + smtperror varchar(200) NOT NULL default '', + smtpcode int(5) NOT NULL default '0', + PRIMARY KEY(eid) + ) ENGINE=MyISAM{$collation};"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."promotions ( + pid int unsigned NOT NULL auto_increment, + title varchar(120) NOT NULL default '', + description text NOT NULL, + enabled tinyint(1) NOT NULL default '1', + logging tinyint(1) NOT NULL default '0', + posts int NOT NULL default '0', + posttype char(2) NOT NULL default '', + registered int NOT NULL default '0', + registeredtype varchar(20) NOT NULL default '', + reputations int NOT NULL default '0', + reputationtype char(2) NOT NULL default '', + requirements varchar(200) NOT NULL default '', + originalusergroup varchar(120) NOT NULL default '0', + newusergroup smallint unsigned NOT NULL default '0', + usergrouptype varchar(120) NOT NULL default '0', + PRIMARY KEY (pid) + ) ENGINE=MyISAM{$collation};"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."promotionlogs( + plid int unsigned NOT NULL auto_increment, + pid int unsigned NOT NULL default '0', + uid int unsigned NOT NULL default '0', + oldusergroup varchar(200) NOT NULL default '0', + newusergroup smallint unsigned NOT NULL default '0', + dateline bigint(30) NOT NULL default '0', + type varchar(9) NOT NULL default 'primary', + PRIMARY KEY(plid) + ) ENGINE=MyISAM{$collation};"); + + if($db->field_exists('maxemails', "usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups DROP maxemails;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups ADD maxemails int(3) NOT NULL default '5' AFTER cansendemail"); + + if($db->field_exists('parseorder', "mycode")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."mycode DROP parseorder;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."mycode ADD parseorder smallint unsigned NOT NULL default '0' AFTER active"); + + if($db->field_exists('mod_edit_posts', "forums")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums DROP mod_edit_posts;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums ADD mod_edit_posts int(1) NOT NULL default '0' AFTER modthreads"); + + if($db->field_exists('pmpopup', "users") && !$db->field_exists('pmnotice', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users CHANGE pmpopup pmnotice int(1) NOT NULL default '0'"); + } + + $db->drop_table("tasks"); + $db->drop_table("tasklog"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."tasks ( + tid int unsigned NOT NULL auto_increment, + title varchar(120) NOT NULL default '', + description text NOT NULL, + file varchar(30) NOT NULL default '', + minute varchar(200) NOT NULL default '', + hour varchar(200) NOT NULL default '', + day varchar(100) NOT NULL default '', + month varchar(30) NOT NULL default '', + weekday varchar(15) NOT NULL default '', + nextrun bigint(30) NOT NULL default '0', + lastrun bigint(30) NOT NULL default '0', + enabled int(1) NOT NULL default '1', + logging int(1) NOT NULL default '0', + locked bigint(30) NOT NULL default '0', + PRIMARY KEY(tid) + ) ENGINE=MyISAM{$collation};"); + + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."tasklog ( + lid int unsigned NOT NULL auto_increment, + tid int unsigned NOT NULL default '0', + dateline bigint(30) NOT NULL default '0', + data text NOT NULL, + PRIMARY KEY(lid) + ) ENGINE=MyISAM{$collation};"); + + + include_once MYBB_ROOT."inc/functions_task.php"; + $tasks = file_get_contents(INSTALL_ROOT.'resources/tasks.xml'); + $parser = new XMLParser($tasks); + $parser->collapse_dups = 0; + $tree = $parser->get_tree(); + + // Insert scheduled tasks + foreach($tree['tasks'][0]['task'] as $task) + { + $new_task = array( + 'title' => $db->escape_string($task['title'][0]['value']), + 'description' => $db->escape_string($task['description'][0]['value']), + 'file' => $db->escape_string($task['file'][0]['value']), + 'minute' => $db->escape_string($task['minute'][0]['value']), + 'hour' => $db->escape_string($task['hour'][0]['value']), + 'day' => $db->escape_string($task['day'][0]['value']), + 'weekday' => $db->escape_string($task['weekday'][0]['value']), + 'month' => $db->escape_string($task['month'][0]['value']), + 'enabled' => $db->escape_string($task['enabled'][0]['value']), + 'logging' => $db->escape_string($task['logging'][0]['value']) + ); + + $new_task['nextrun'] = fetch_next_run($new_task); + + $db->insert_query("tasks", $new_task); + $taskcount++; + } + + if($db->table_exists("favorites") && !$db->table_exists("threadsubscriptions")) + { + $db->write_query("RENAME TABLE ".TABLE_PREFIX."favorites TO ".TABLE_PREFIX."threadsubscriptions"); + } + + if($db->field_exists('fid', "threadsubscriptions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threadsubscriptions CHANGE fid sid int unsigned NOT NULL auto_increment"); + } + + if($db->field_exists('type', "threadsubscriptions")) + { + $db->update_query("threadsubscriptions", array('type' => 0), "type='f'"); + $db->update_query("threadsubscriptions", array('type' => 1), "type='s'"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threadsubscriptions CHANGE type notification int(1) NOT NULL default '0'"); + } + + if($db->field_exists('dateline', "threadsubscriptions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threadsubscriptions DROP dateline;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threadsubscriptions ADD dateline bigint(30) NOT NULL default '0'"); + + if($db->field_exists('subscriptionkey', "threadsubscriptions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threadsubscriptions DROP subscriptionkey;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threadsubscriptions ADD subscriptionkey varchar(32) NOT NULL default ''"); + + if($db->field_exists('emailnotify', "users")) + { + $db->update_query("users", array('emailnotify' => 0), "emailnotify='no' OR emailnotify='0'"); + $db->update_query("users", array('emailnotify' => 2), "emailnotify='yes' OR emailnotify='1'"); + $db->update_query("users", array('emailnotify' => 0), "emailnotify != 1 AND emailnotify != 2"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users CHANGE emailnotify subscriptionmethod int(1) NOT NULL default '0'"); + } + + $db->drop_table("warninglevels"); + $db->drop_table("warningtypes"); + $db->drop_table("warnings"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."warninglevels ( + lid int unsigned NOT NULL auto_increment, + percentage int(3) NOT NULL default '0', + action text NOT NULL, + PRIMARY KEY(lid) + ) ENGINE=MyISAM{$collation};"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."warningtypes ( + tid int unsigned NOT NULL auto_increment, + title varchar(120) NOT NULL default '', + points int unsigned NOT NULL default '0', + expirationtime bigint(30) NOT NULL default '0', + PRIMARY KEY(tid) + ) ENGINE=MyISAM{$collation};"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."warnings ( + wid int unsigned NOT NULL auto_increment, + uid int unsigned NOT NULL default '0', + tid int unsigned NOT NULL default '0', + pid int unsigned NOT NULL default '0', + title varchar(120) NOT NULL default '', + points int unsigned NOT NULL default '0', + dateline bigint(30) NOT NULL default '0', + issuedby int unsigned NOT NULL default '0', + expires bigint(30) NOT NULL default '0', + expired int(1) NOT NULL default '0', + daterevoked bigint(30) NOT NULL default '0', + revokedby int unsigned NOT NULL default '0', + revokereason text NOT NULL, + notes text NOT NULL, + PRIMARY KEY(wid) + ) ENGINE=MyISAM{$collation};"); + + if($db->field_exists('warningpoints', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP warningpoints;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD warningpoints int(3) NOT NULL default '0' AFTER unreadpms"); + + if($db->field_exists('moderateposts', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP moderateposts;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD moderateposts int(1) NOT NULL default '0' AFTER warningpoints"); + + if($db->field_exists('moderationtime', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP moderationtime;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD moderationtime bigint(30) NOT NULL default '0' AFTER moderateposts"); + + if($db->field_exists('suspendposting', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP suspendposting;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD suspendposting int(1) NOT NULL default '0' AFTER moderationtime"); + + if($db->field_exists('suspensiontime', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP suspensiontime;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD suspensiontime bigint(30) NOT NULL default '0' AFTER suspendposting"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."banned CHANGE oldadditionalgroups oldadditionalgroups TEXT NOT NULL"); + + if($db->field_exists('birthdayprivacy', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP birthdayprivacy;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD birthdayprivacy varchar(4) NOT NULL default 'all' AFTER birthday"); + + if($db->field_exists('birthdayprivacy', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP birthdayprivacy;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD birthdayprivacy varchar(4) NOT NULL default 'all' AFTER birthday"); + + if($db->field_exists('longregip', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP longregip;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD longregip int(11) NOT NULL default '0' AFTER lastip"); + + if($db->field_exists('longlastip', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP longlastip;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD longlastip int(11) NOT NULL default '0' AFTER lastip"); + + // Unused column + if($db->field_exists('titles', "searchlog")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."searchlog DROP titles;"); + } + + $db->drop_table("adminlog"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."adminlog ( + uid int unsigned NOT NULL default '0', + ipaddress varchar(50) NOT NULL default '', + dateline bigint(30) NOT NULL default '0', + module varchar(50) NOT NULL default '', + action varchar(50) NOT NULL default '', + data text NOT NULL, + KEY module (module, action) + ) ENGINE=MyISAM{$collation};"); + + if($db->field_exists('data', "adminsessions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminsessions DROP data;"); + } + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminsessions ADD data TEXT NOT NULL AFTER lastactive;"); + + if($db->field_exists('isdefault', "settings")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."settings DROP isdefault;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."settings ADD isdefault int(1) NOT NULL default '0' AFTER gid;"); + + $setting_group_cache = array(); + $query = $db->simple_select("settinggroups", "gid, isdefault"); + while($settinggroup = $db->fetch_array($query)) + { + $setting_group_cache[$settinggroup['gid']] = $settinggroup['isdefault']; + } + + $query = $db->simple_select("settings", "gid, sid"); + while($setting = $db->fetch_array($query)) + { + if($setting_group_cache[$setting['gid']] == 1) + { + $db->update_query("settings", array('isdefault' => 1), "sid = '{$setting['sid']}'", 1); + } + } + + $db->update_query("settings", array('value' => 'classic'), "name='postlayout' AND value != 'horizontal'"); + + $db->update_query("settings", array('optionscode' => $db->escape_string('php +')), "name='searchtype'", 1); + + $contents = "Zakończono

    "; + $contents .= "

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "; + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer("12_dbchanges3"); +} + +function upgrade12_dbchanges3() +{ + global $db, $output, $mybb; + + $output->print_header("Konwertowanie banów"); + + echo "

    Trwa konwersja istniejących zbanowanych adresów IP, adresów email i loginów...

    "; + flush(); + + $db->drop_table("banfilters"); + + $collation = $db->build_create_table_collation(); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."banfilters ( + fid int unsigned NOT NULL auto_increment, + filter varchar(200) NOT NULL default '', + type int(1) NOT NULL default '0', + lastuse bigint(30) NOT NULL default '0', + dateline bigint(30) NOT NULL default '0', + PRIMARY KEY (fid) + ) ENGINE=MyISAM{$collation};"); + + // Now we convert all of the old bans in to the new system! + $ban_types = array('bannedips', 'bannedemails', 'bannedusernames'); + foreach($ban_types as $type) + { + // Some people put spaces or breaks (\r\n) instead, so we should take that into account. + $mybb->settings[$type] = str_replace(array("\n", "\r\n", "\r"), ",", $mybb->settings[$type]); + + // Usernames can have spaces so don't replace those with commas. + if($type != 'bannedusernames') + { + $mybb->settings[$type] = str_replace(" ", ",", $mybb->settings[$type]); + } + + $bans = explode(",", $mybb->settings[$type]); + $bans = array_unique($bans); + $bans = array_map("trim", $bans); + foreach($bans as $ban) + { + if(!$ban) + { + continue; + } + + if($type == "bannedips") + { + $ban_type = 1; + } + else if($type == "bannedusernames") + { + $ban_type = 2; + } + else if($type == "bannedemails") + { + $ban_type = 3; + } + $new_ban = array( + "filter" => $db->escape_string($ban), + "type" => $ban_type, + "dateline" => TIME_NOW + ); + $db->insert_query("banfilters", $new_ban); + } + } + + $contents = "Zakończono

    "; + $contents .= "

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "; + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer("12_dbchanges4"); +} + +function upgrade12_dbchanges4() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + $db->drop_table("spiders"); + $db->drop_table("stats"); + + $collation = $db->build_create_table_collation(); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."spiders ( + sid int unsigned NOT NULL auto_increment, + name varchar(100) NOT NULL default '', + theme int unsigned NOT NULL default '0', + language varchar(20) NOT NULL default '', + usergroup int unsigned NOT NULL default '0', + useragent varchar(200) NOT NULL default '', + lastvisit bigint(30) NOT NULL default '0', + PRIMARY KEY(sid) + ) ENGINE=MyISAM{$collation};"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."stats ( + dateline bigint(30) NOT NULL default '0', + numusers int unsigned NOT NULL default '0', + numthreads int unsigned NOT NULL default '0', + numposts int unsigned NOT NULL default '0', + PRIMARY KEY(dateline) + ) ENGINE=MyISAM{$collation};"); + + $db->insert_query("spiders", array('name' => 'GoogleBot', 'useragent' => 'google')); + $db->insert_query("spiders", array('name' => 'Lycos', 'useragent' => 'lycos')); + $db->insert_query("spiders", array('name' => 'Ask Jeeves', 'useragent' => 'ask jeeves')); + $db->insert_query("spiders", array('name' => 'Hot Bot', 'useragent' => 'slurp@inktomi')); + $db->insert_query("spiders", array('name' => 'What You Seek', 'useragent' => 'whatuseek')); + $db->insert_query("spiders", array('name' => 'Archive.org', 'useragent' => 'is_archiver')); + $db->insert_query("spiders", array('name' => 'Altavista', 'useragent' => 'scooter')); + $db->insert_query("spiders", array('name' => 'Alexa', 'useragent' => 'ia_archiver')); + $db->insert_query("spiders", array('name' => 'MSN Search', 'useragent' => 'msnbot')); + $db->insert_query("spiders", array('name' => 'Yahoo!', 'useragent' => 'yahoo! slurp')); + + // DST correction changes + $db->update_query("users", array('dst' => 1), "dst=1"); + $db->update_query("users", array('dst' => 0), "dst=0"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users CHANGE dst dst INT(1) NOT NULL default '0'"); + if($db->field_exists('dstcorrection', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP dstcorrection;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD dstcorrection INT(1) NOT NULL default '0' AFTER dst"); + + $db->update_query("users", array('dstcorrection' => 2)); + + $db->update_query("adminoptions", array('cpstyle' => '')); + + if($db->field_exists('permsset', "adminoptions") && !$db->field_exists('permissions', "adminoptions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminoptions CHANGE permsset permissions TEXT NOT NULL "); + } + + $adminoptions = file_get_contents(INSTALL_ROOT.'resources/adminoptions.xml'); + $parser = new XMLParser($adminoptions); + $parser->collapse_dups = 0; + $tree = $parser->get_tree(); + + // Fetch default permissions list + $default_permissions = array(); + foreach($tree['adminoptions'][0]['user'] as $users) + { + $uid = $users['attributes']['uid']; + if($uid == -4) + { + foreach($users['permissions'][0]['module'] as $module) + { + foreach($module['permission'] as $permission) + { + $default_permissions[$module['attributes']['name']][$permission['attributes']['name']] = $permission['value']; + } + } + break; + } + } + + $convert_permissions = array( + "caneditsettings" => array( + "module" => "config", + "permission" => "settings" + ), + "caneditann" => array( + "module" => "forum", + "permission" => "announcements", + ), + "caneditforums" => array( + "module" => "forum", + "permission" => "management", + ), + "canmodposts" => array( + "module" => "forum", + "permission" => "moderation_queue", + ), + "caneditsmilies" => array( + "module" => "config", + "permission" => "smilies", + ), + "caneditpicons" => array( + "module" => "config", + "permission" => "post_icons", + ), + "caneditthemes" => array( + "module" => "style", + "permission" => "themes", + ), + "canedittemps" => array( + "module" => "style", + "permission" => "templates", + ), + "caneditusers" => array( + "module" => "user", + "permission" => "view", + ), + "caneditpfields" => array( + "module" => "config", + "permission" => "profile_fields", + ), + "caneditmodactions" => array( + "module" => "config", + "permission" => "mod_tools", + ), + "caneditugroups" => array( + "module" => "user", + "permission" => "groups", + ), + "caneditaperms" => array( + "module" => "user", + "permission" => "admin_permissions", + ), + "caneditutitles" => array( + "module" => "user", + "permission" => "titles", + ), + "caneditattach" => array( + "module" => "forum", + "permission" => "attachments", + ), + "canedithelp" => array( + "module" => "config", + "permission" => "help_documents", + ), + "caneditlangs" => array( + "module" => "config", + "permission" => "languages", + ), + "canrunmaint" => array( + "module" => "tools", + "permission" => "recount_rebuild", + ), + "canrundbtools" => array( + "module" => "tools", + "permission" => "backupdb", + ), + ); + + $new_permissions = $default_permissions; + + $query = $db->simple_select("adminoptions"); + while($adminoption = $db->fetch_array($query)) + { + foreach($adminoption as $field => $value) + { + if(strtolower(substr($field, 0, 3)) != "can") + { + continue; + } + + if(array_key_exists($field, $convert_permissions)) + { + // Note: old adminoptions table is still yes/no - do not change me + if($value == "yes") + { + $value = 1; + } + else + { + $value = $default_permissions[$convert_permissions[$field]['module']][$convert_permissions[$field]['permission']]; + } + $new_permissions[$convert_permissions[$field]['module']][$convert_permissions[$field]['permission']] = $value; + } + } + + $db->update_query("adminoptions", array('permissions' => serialize($new_permissions)), "uid = '{$adminoption['uid']}'"); + + $new_permissions = $default_permissions; + } + + foreach($convert_permissions as $field => $value) + { + if($db->field_exists($field, "adminoptions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminoptions DROP {$field}"); + } + } + + // Set default views + if($db->field_exists('defaultviews', "adminoptions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminoptions DROP defaultviews"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminoptions ADD defaultviews TEXT NOT NULL"); + $db->update_query("adminoptions", array('defaultviews' => serialize(array('user' => 1)))); + + require_once MYBB_ROOT."inc/functions_rebuild.php"; + rebuild_stats(); + + $contents = "Zakończono

    "; + $contents .= "

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "; + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer("12_dbchanges5"); +} + +function upgrade12_dbchanges5() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + $db->drop_table("templategroups"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."templategroups ( + gid int unsigned NOT NULL auto_increment, + prefix varchar(50) NOT NULL default '', + title varchar(100) NOT NULL default '', + PRIMARY KEY (gid) + ) ENGINE=MyISAM{$collation};"); + + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('1','calendar','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('2','editpost','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('3','forumbit','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('4','forumjump','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('5','forumdisplay','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('6','index','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('7','error','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('8','memberlist','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('9','multipage','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('10','private','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('11','portal','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('12','postbit','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('13','redirect','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('14','showthread','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('15','usercp','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('16','online','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('17','moderation','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('18','nav','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('19','search','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('20','showteam','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('21','reputation','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('22','newthread','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('23','newreply','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('24','member','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('25','warnings','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('26','global','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('27','header','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('28','managegroup','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('29','misc','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('30','modcp','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('31','php','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('32','polls','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('33','post','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('34','printthread','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('35','report','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('36','smilieinsert','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('37','stats','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('38','xmlhttp','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('39','footer','');"); + + $query = $db->query("SHOW INDEX FROM ".TABLE_PREFIX."users"); + while($ukey = $db->fetch_array($query)) + { + if($ukey['Key_name'] == "username") + { + $index = $ukey; + break; + } + } + if($index) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP KEY username"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD UNIQUE KEY username (username)"); + + if($db->field_exists('statustime', "privatemessages")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages DROP statustime;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages ADD statustime bigint(30) NOT NULL default '0' AFTER status"); + + $collation = $db->build_create_table_collation(); + + $db->drop_table("calendars"); + $db->drop_table("calendarpermissions"); + $db->drop_table("forumsread"); + $db->drop_table("adminviews"); + $db->drop_table("threadviews"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."threadviews ( + tid int unsigned NOT NULL default '0' + ) ENGINE=MyISAM{$collation};"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."calendars ( + cid int unsigned NOT NULL auto_increment, + name varchar(100) NOT NULL default '', + disporder int unsigned NOT NULL default '0', + startofweek int(1) NOT NULL default '0', + showbirthdays int(1) NOT NULL default '0', + eventlimit int(3) NOT NULL default '0', + moderation int(1) NOT NULL default '0', + allowhtml int(1) NOT NULL default '0', + allowmycode int(1) NOT NULL default '0', + allowimgcode int(1) NOT NULL default '0', + allowsmilies int(1) NOT NULL default '0', + PRIMARY KEY(cid) + ) ENGINE=MyISAM{$collation};"); + + $calendar_array = array( + 'name' => 'Default Calendar', + 'disporder' => 1, + 'startofweek' => 0, + 'showbirthdays' => 1, + 'eventlimit' => 4, + 'moderation' => 0, + 'allowhtml' => 0, + 'allowmycode' => 1, + 'allowimgcode' => 1, + 'allowsmilies' => 1 + ); + $db->insert_query("calendars", $calendar_array); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."calendarpermissions ( + cid int unsigned NOT NULL default '0', + gid int unsigned NOT NULL default '0', + canviewcalendar int(1) NOT NULL default '0', + canaddevents int(1) NOT NULL default '0', + canbypasseventmod int(1) NOT NULL default '0', + canmoderateevents int(1) NOT NULL default '0' + ) ENGINE=MyISAM{$collation};"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."forumsread ( + fid int unsigned NOT NULL default '0', + uid int unsigned NOT NULL default '0', + dateline int(10) NOT NULL default '0', + KEY dateline (dateline), + UNIQUE KEY fid (fid,uid) + ) ENGINE=MyISAM{$collation};"); + + if($db->field_exists('dateuploaded', "attachments")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments DROP dateuploaded;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments ADD dateuploaded bigint(30) NOT NULL default '0' AFTER downloads"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."adminviews ( + vid int unsigned NOT NULL auto_increment, + uid int unsigned NOT NULL default '0', + title varchar(100) NOT NULL default '', + type varchar(6) NOT NULL default '', + visibility int(1) NOT NULL default '0', + `fields` text NOT NULL, + conditions text NOT NULL, + sortby varchar(20) NOT NULL default '', + sortorder varchar(4) NOT NULL default '', + perpage int(4) NOT NULL default '0', + view_type varchar(6) NOT NULL default '', + PRIMARY KEY(vid) + ) ENGINE=MyISAM{$collation};"); + + $views = file_get_contents(INSTALL_ROOT.'resources/adminviews.xml'); + $parser = new XMLParser($views); + $parser->collapse_dups = 0; + $tree = $parser->get_tree(); + + // Insert admin views + foreach($tree['adminviews'][0]['view'] as $view) + { + $fields = array(); + foreach($view['fields'][0]['field'] as $field) + { + $fields[] = $field['attributes']['name']; + } + $conditions = array(); + if($view['conditions'][0]['condition']) + { + foreach($view['conditions'][0]['condition'] as $condition) + { + if(!$condition['value']) continue; + if($condition['attributes']['is_serialized'] == 1) + { + $condition['value'] = my_unserialize($condition['value']); + } + $conditions[$condition['attributes']['name']] = $condition['value']; + } + } + $new_view = array( + "uid" => 0, + "type" => $db->escape_string($view['attributes']['type']), + "visibility" => (int)$view['attributes']['visibility'], + "title" => $db->escape_string($view['title'][0]['value']), + "fields" => $db->escape_string(serialize($fields)), + "conditions" => $db->escape_string(serialize($conditions)), + "sortby" => $db->escape_string($view['sortby'][0]['value']), + "sortorder" => $db->escape_string($view['sortorder'][0]['value']), + "perpage" => (int)$view['perpage'][0]['value'], + "view_type" => $db->escape_string($view['view_type'][0]['value']) + ); + $db->insert_query("adminviews", $new_view); + $view_count++; + } + + $avatardimensions = str_replace('x', '|', my_strtolower($mybb->settings['postmaxavatarsize'])); + + $db->simple_select("users", "uid", "avatar != '' AND avatardimensions = ''"); + while($user = $db->fetch_array($query)) + { + $db->update_query("users", array('avatardimensions' => $avatardimensions), "uid='{$user['uid']}'", 1); + } + + $contents = "Zakończono

    "; + $contents .= "

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "; + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer("12_redoconfig"); +} + +function upgrade12_redoconfig() +{ + global $db, $output, $orig_config, $mybb; + + $config = $orig_config; + + $output->print_header("Ponowne tworzenie pliku config.php"); + + if(!is_array($config['database'])) + { + // Backup our old Config file + @copy(MYBB_ROOT."inc/config.php", MYBB_ROOT."inc/config.backup.php"); + + $fh = @fopen(MYBB_ROOT."inc/config.php", "w"); + if(!$fh) + { + echo "

    Nie można otworzyć pliku inc/config.php
    Sprawdź uprawnienia dla tego pliku przed kontynuowaniem (CHMOD 766 lub 777).

    "; + $output->print_footer("12_redoconfig"); + exit; + } + + if(!$config['memcache_host']) + { + $config['memcache_host'] = "localhost"; + } + + if(!$config['memcache_port']) + { + $config['memcache_port'] = 11211; + } + + $comment = ""; + + if(!$db->db_encoding || !$config['db_encoding']) + { + $comment = " // "; + } + + if(!$config['db_encoding']) + { + $config['db_encoding'] = "utf8"; + } + + $configdata = " 365, // Administrator logs + 'mod_logs' => 0, // Moderator logs + 'task_logs' => 30, // Scheduled task logs + 'mail_logs' => 180, // Mail error logs + 'user_mail_logs' => 180, // User mail logs + 'promotion_logs' => 180 // Promotion logs +); + +?".">"; + fwrite($fh, $configdata); + fclose($fh); + } + echo "

    Plik konfiguracyjny został pomyślnie zapisany.

    "; + echo "

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "; + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer("12_dbchanges6"); +} + +function upgrade12_dbchanges6() +{ + global $db, $output; + + $output->print_header("Konwersja adresów IP postów"); + + if(!$_POST['ipspage']) + { + $ipp = 5000; + } + else + { + $ipp = $_POST['ipspage']; + } + + if($_POST['ipstart']) + { + $startat = $_POST['ipstart']; + $upper = $startat+$ipp; + $lower = $startat; + } + else + { + $startat = 0; + $upper = $ipp; + $lower = 1; + } + + $query = $db->simple_select("posts", "COUNT(pid) AS ipcount"); + $cnt = $db->fetch_array($query); + + if($upper > $cnt['ipcount']) + { + $upper = $cnt['ipcount']; + } + + echo "

    Konwersja adresu IP z {$lower} na {$upper} (ÅÄ…cznie: {$cnt['ipcount']})

    "; + flush(); + + $ipaddress = false; + + $query = $db->simple_select("posts", "ipaddress, longipaddress, pid", "", array('limit_start' => $lower, 'limit' => $ipp)); + while($post = $db->fetch_array($query)) + { + // Have we already converted this ip? + if(!$post['longipaddress']) + { + $db->update_query("posts", array('longipaddress' => my_ip2long($post['ipaddress'])), "pid = '{$post['pid']}'"); + } + $ipaddress = true; + } + + $remaining = $upper-$cnt['ipcount']; + if($remaining && $ipaddress) + { + $nextact = "12_dbchanges6"; + $startat = $startat+$ipp; + $contents = "

    Zakończono. Naciśnij przycisk Dalej, aby przejść do konwersji innego typu adresów IP.

    "; + } + else + { + $nextact = "12_dbchanges7"; + $contents = "

    Zakończono

    Wszystkie adresy IP postów zostały skonwertowane do nowego formatu. Naciśnij przycisk Dalej, aby kontynuować.

    "; + } + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer($nextact); +} + +function upgrade12_dbchanges7() +{ + global $db, $output; + + $output->print_header("Konwersja adresów IP użytkowników"); + + if(!$_POST['ipspage']) + { + $ipp = 5000; + } + else + { + $ipp = $_POST['ipspage']; + } + + if($_POST['ipstart']) + { + $startat = $_POST['ipstart']; + $upper = $startat+$ipp; + $lower = $startat; + } + else + { + $startat = 0; + $upper = $ipp; + $lower = 1; + } + + $query = $db->simple_select("users", "COUNT(uid) AS ipcount"); + $cnt = $db->fetch_array($query); + + if($upper > $cnt['ipcount']) + { + $upper = $cnt['ipcount']; + } + + $contents .= "

    Konwersja adresu IP z {$lower} na {$upper} (ÅÄ…cznie: {$cnt['ipcount']})

    "; + + $ipaddress = false; + $update_array = array(); + + $query = $db->simple_select("users", "regip, lastip, longlastip, longregip, uid", "", array('limit_start' => $lower, 'limit' => $ipp)); + while($user = $db->fetch_array($query)) + { + // Have we already converted this ip? + if(!$user['longregip']) + { + $update_array['longregip'] = (int)my_ip2long($user['regip']); + } + + if(!$user['longlastip']) + { + $update_array['longlastip'] = (int)my_ip2long($user['lastip']); + } + + if(!empty($update_array)) + { + $db->update_query("users", $update_array, "uid = '{$user['uid']}'"); + } + + $update_array = array(); + $ipaddress = true; + } + + $remaining = $upper-$cnt['ipcount']; + if($remaining && $ipaddress) + { + $nextact = "12_dbchanges7"; + $startat = $startat+$ipp; + $contents .= "

    Zakończono. Naciśnij przycisk Dalej, aby przejść do konwersji innego typu adresów IP.

    "; + } + else + { + $nextact = "12_dbchanges8"; + $contents .= "

    Zakończono

    Wszystkie adresy IP użytkowników zostały skonwertowane do nowego formatu. Naciśnij przycisk Dalej, aby kontynuować.

    "; + } + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer($nextact); +} + +function upgrade12_dbchanges8() +{ + global $db, $output; + + $output->print_header("Konwersja wydarzeń"); + + if(!$_POST['eventspage']) + { + $epp = 50; + } + else + { + $epp = $_POST['eventspage']; + } + + if($_POST['eventstart']) + { + $startat = $_POST['eventstart']; + $upper = $startat+$epp; + $lower = $startat; + } + else + { + $startat = 0; + $upper = $epp; + $lower = 1; + } + + $query = $db->simple_select("events", "COUNT(eid) AS eventcount"); + $cnt = $db->fetch_array($query); + + if($upper > $cnt['eventcount']) + { + $upper = $cnt['eventcount']; + } + + $contents .= "

    Konwersja wydarzeÅ„ z {$lower} do {$upper} (ÅÄ…cznie: {$cnt['eventcount']})

    "; + + // Just started - add fields + if(!$db->field_exists("donecon", "events")) + { + // Add temporary column + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events ADD donecon smallint(1) NOT NULL;"); + + if($db->field_exists('cid', "events")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events DROP cid;"); + } + + if($db->field_exists('visible', "events")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events DROP visible;"); + } + + if($db->field_exists('dateline', "events")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events DROP dateline;"); + } + + if($db->field_exists('starttime', "events")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events DROP starttime;"); + } + + if($db->field_exists('endtime', "events")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events DROP endtime;"); + } + + if($db->field_exists('timezone', "events")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events DROP timezone;"); + } + + if($db->field_exists('ignoretimezone', "events")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events DROP ignoretimezone;"); + } + + if($db->field_exists('usingtime', "events")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events DROP usingtime;"); + } + + if($db->field_exists('repeats', "events")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events DROP repeats;"); + } + + // Got structural changes? + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events ADD cid int unsigned NOT NULL default '0' AFTER eid"); + + if($db->field_exists('author', "events") && !$db->field_exists('uid', "events")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events CHANGE author uid int unsigned NOT NULL default '0'"); + } + + if($db->field_exists('subject', "events") && !$db->field_exists('name', "events")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events CHANGE subject name varchar(120) NOT NULL default ''"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events ADD visible int(1) NOT NULL default '0' AFTER description"); + $db->update_query("events", array('private' => 1), "private='yes' OR private='1'"); + $db->update_query("events", array('private' => 0), "private='no' OR private='0'"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events CHANGE private private int(1) NOT NULL default '0'"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events ADD dateline int(10) unsigned NOT NULL default '0' AFTER private"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events ADD starttime int(10) unsigned NOT NULL default '0' AFTER dateline"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events ADD endtime int(10) unsigned NOT NULL default '0' AFTER starttime"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events ADD timezone int(3) NOT NULL default '0' AFTER endtime"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events ADD ignoretimezone int(1) NOT NULL default '0' AFTER timezone"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events ADD usingtime int(1) NOT NULL default '0' AFTER ignoretimezone"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events ADD repeats text NOT NULL AFTER usingtime"); + } + + if($db->field_exists('date', "events")) + { + $query = $db->simple_select("events", "*", "donecon!=1", array("order_by" => "eid", "limit" => $epp)); + while($event = $db->fetch_array($query)) + { + $e_date = explode("-", $event['date']); + if(!$e_date[2]) $e_date[2] = 2005; + $starttime = gmmktime(0, 0, 0, $e_date[1], $e_date[0], $e_date[2]); + $updated_event = array( + "cid" => 1, + "visible" => 1, + "donecon" => 1, + "starttime" => $starttime, + "dateline" => $starttime + ); + $db->update_query("events", $updated_event, "eid='{$event['eid']}'", 1); + } + + $date = true; + } + else + { + $date = false; + } + + $query = $db->simple_select("events", "COUNT(eid) AS remaining", "donecon!=1"); + $remaining = $db->fetch_field($query, "remaining"); + if($remaining && $date) + { + $nextact = "12_dbchanges8"; + $startat = $startat+$epp; + $contents .= "

    Zakończono. Naciśnij przycisk Dalej, aby przejść do konwersji innego typu wydarzeń.

    "; + } + else + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events DROP donecon"); + if($db->field_exists('date', "events")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events DROP date"); + } + $nextact = "12_redothemes"; + $contents .= "

    Zakończono

    Wszystkie wydarzenia zostały skonwertowane. Naciśnij przycisk Dalej, aby kontynuować.

    "; + } + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer($nextact); +} + +function upgrade12_redothemes() +{ + global $db, $output, $config, $mybb; + + $output->print_header("Konwersja stylów"); + + if(!@is_dir(MYBB_ROOT.'cache/')) + { + @mkdir(MYBB_ROOT.'cache/', 077); + + // Add in empty index.html! + $fp = @fopen(MYBB_ROOT."cache/index.html", "w"); + @fwrite($fp, ""); + @fclose($fp); + } + $cachewritable = @fopen(MYBB_ROOT.'cache/test.write', 'w'); + if(!$cachewritable) + { + $not_writable = true; + @fclose($cachewritable); + } + else + { + @fclose($cachewritable); + @my_chmod(MYBB_ROOT.'cache', '0777'); + @my_chmod(MYBB_ROOT.'cache/test.write', '0777'); + @unlink(MYBB_ROOT.'cache/test.write'); + } + + if($not_writable) + { + echo "

    Nie można zapisać do katalogu /cache.
    Przed kontynuowaniem procesu aktualizacji, upewnij się, że katalog istnieje i ma nadane odpowiednie uprawnienia (CHMOD 777).

    "; + $output->print_footer("12_redothemes"); + exit; + } + + $not_writable = false; + if(!@is_dir(MYBB_ROOT.'cache/themes/')) + { + @mkdir(MYBB_ROOT.'cache/themes/', 077); + + // Add in empty index.html! + $fp = @fopen(MYBB_ROOT."cache/themes/index.html", "w"); + @fwrite($fp, ""); + @fclose($fp); + } + $themewritable = @fopen(MYBB_ROOT.'cache/themes/test.write', 'w'); + if(!$themewritable) + { + $not_writable = true; + @fclose($themewritable); + } + else + { + @fclose($themewritable); + @my_chmod(MYBB_ROOT.'cache/themes', '0777'); + @my_chmod(MYBB_ROOT.'cache/themes/test.write', '0777'); + @unlink(MYBB_ROOT.'cache/themes/test.write'); + } + + if($not_writable) + { + echo "

    Nie można zapisać do katalogu /cache/themes.
    Przed kontynuowaniem procesu aktualizacji upewnij się, że katalog istnieje i ma nadane odpowiednie uprawnienia (CHMOD 777)

    "; + $output->print_footer("12_redothemes"); + exit; + } + + if($db->field_exists('themebits', "themes") && !$db->field_exists('properties', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes CHANGE themebits properties text NOT NULL"); + } + + if($db->field_exists('cssbits', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP cssbits"); + } + + if($db->field_exists('csscached', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP csscached"); + } + + if($db->field_exists('stylesheets', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP stylesheets"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes ADD stylesheets text NOT NULL AFTER properties"); + + if($db->table_exists("themestylesheets")) + { + $db->drop_table("themestylesheets"); + } + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."themestylesheets( + sid int unsigned NOT NULL auto_increment, + name varchar(30) NOT NULL default '', + tid int unsigned NOT NULL default '0', + attachedto text NOT NULL, + stylesheet text NOT NULL, + cachefile varchar(100) NOT NULL default '', + lastmodified bigint(30) NOT NULL default '0', + PRIMARY KEY(sid) + ) ENGINE=MyISAM{$collation};"); + + // Define our default stylesheets - MyBB 1.4 contains additional stylesheets that our converted themes will also need + $contents = @file_get_contents(INSTALL_ROOT.'resources/mybb_theme.xml'); + if(file_exists(MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions_themes.php")) + { + require_once MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions_themes.php"; + } + else if(file_exists(MYBB_ROOT."admin/inc/functions_themes.php")) + { + require_once MYBB_ROOT."admin/inc/functions_themes.php"; + } + else + { + $output->print_error("Upewnij się, że katalog administracyjny (/admin) został poprawnie załadowany na serwer."); + } + + // Import master theme + if(import_theme_xml($contents, array("tid" => 1, "no_templates" => 1, "version_compat" => 1)) === -1) + { + $output->print_error("Upewnij się, że plik /install/resources/mybb_theme.xml został poprawnie załadowany na serwer."); + } + + // Fetch out default stylesheets from master + $query = $db->simple_select("themes", "*", "tid=1"); + $master_theme = $db->fetch_array($query); + + $master_stylesheets = my_unserialize($master_theme['stylesheets']); + + if(is_array($master_stylesheets)) + { + // Note: 1.4 only ships with one global|global stylesheet + foreach($master_stylesheets as $location => $sheets) + { + foreach($sheets as $action => $sheets) + { + foreach($sheets as $stylesheet) + { + if($location == "global" && $action == "global") + { + continue; // Skip global + } + + $default_stylesheets[$location][$action][] = $stylesheet; + $default_stylesheets['inherited']["{$location}_{$action}"][$stylesheet] = 1; // This stylesheet is inherited from the master + } + } + } + } + + $query = $db->simple_select("themes"); + while($theme = $db->fetch_array($query)) + { + if(!$theme['css']) + { + continue; + } + + $theme['css'] .= "\n\n".$theme['extracss']; + + $theme['css'] = upgrade_css_120_to_140($theme['css']); + + + // Create stylesheets + $cache_file = cache_stylesheet($theme['tid'], "global.css", $theme['css']); + + $new_stylesheet = array( + "tid" => $theme['tid'], + "name" => "global.css", + "attachedto" => "", + "stylesheet" => $db->escape_string($theme['css']), + "cachefile" => "global.css", + "lastmodified" => TIME_NOW + ); + $sid = $db->insert_query("themestylesheets", $new_stylesheet); + $css_url = "css.php?stylesheet={$sid}"; + if($cache_file) + { + $css_url = $cache_file; + } + + // Now we go and update the stylesheets column for this theme + $stylesheets = $default_stylesheets; + + // Add in our local for this theme + $stylesheets['global']['global'][] = $css_url; + + // Update the theme + $db->update_query("themes", array("stylesheets" => $db->escape_string(serialize($stylesheets))), "tid='{$theme['tid']}'"); + } + + if($db->field_exists('css', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP css"); + } + + if($db->field_exists('extracss', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP extracss"); + } + + // We need to replace this for our themes css to show up + // must be present in the old template (it usually is) + $query = $db->simple_select("templates", "tid,template", "title='headerinclude'"); + while($template = $db->fetch_array($query)) + { + $template['template'] = str_replace('', '{$stylesheets}', $template['template']); + + $db->update_query("templates", array('template' => $db->escape_string($template['template'])), "tid='{$template['tid']}'"); + } + + echo "

    Style zostały pomyślnie skonwertowane do nowego systemu.

    "; + echo "

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "; + + global $footer_extra; + //$footer_extra = ""; + + $output->print_footer("12_done"); +} diff --git a/Upload/install/resources/upgrade13.php b/Upload/install/resources/upgrade13.php new file mode 100644 index 0000000..6f11bbd --- /dev/null +++ b/Upload/install/resources/upgrade13.php @@ -0,0 +1,237 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +function upgrade13_dbchanges() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + if($db->type == "mysql" || $db->type == "mysqli") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminsessions ADD INDEX ( `uid` )"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminsessions ADD INDEX ( `dateline` )"); + } + + if($db->type != "sqlite") + { + if($db->index_exists("users", "username")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP KEY username"); + } + + $query = $db->simple_select("users", "username, uid", "1=1 GROUP BY username HAVING count(*) > 1"); + while($user = $db->fetch_array($query)) + { + $db->update_query("users", array('username' => $user['username']."_dup".$user['uid']), "uid='{$user['uid']}'", 1); + } + + if($db->type == "pgsql") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD UNIQUE(username)"); + } + else + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD UNIQUE KEY username (username)"); + } + } + + if($db->type == "pgsql") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users CHANGE longregip longregip int NOT NULL default '0'"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users CHANGE longlastip longlastip int NOT NULL default '0'"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts CHANGE longipaddress longipaddress int NOT NULL default '0'"); + } + else + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users CHANGE longregip longregip int(11) NOT NULL default '0'"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users CHANGE longlastip longlastip int(11) NOT NULL default '0'"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts CHANGE longipaddress longipaddress int(11) NOT NULL default '0'"); + } + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("13_dbchanges1"); +} + +function upgrade13_dbchanges1() +{ + global $db, $output; + + $output->print_header("Naprawa konwersji adresów IP postów"); + + if(!$_POST['ipspage']) + { + $ipp = 5000; + } + else + { + $ipp = $_POST['ipspage']; + } + + if($_POST['ipstart']) + { + $startat = $_POST['ipstart']; + $upper = $startat+$ipp; + $lower = $startat; + } + else + { + $startat = 0; + $upper = $ipp; + $lower = 1; + } + + $query = $db->simple_select("posts", "COUNT(pid) AS ipcount"); + $cnt = $db->fetch_array($query); + + if($upper > $cnt['ipcount']) + { + $upper = $cnt['ipcount']; + } + + echo "

    Naprawianie adresu IP z {$lower} do {$upper} (ÅÄ…cznie: {$cnt['ipcount']} )

    "; + flush(); + + $ipaddress = false; + + $query = $db->simple_select("posts", "ipaddress, longipaddress, pid", "", array('limit_start' => $lower, 'limit' => $ipp)); + while($post = $db->fetch_array($query)) + { + // Have we already converted this ip? + if(my_ip2long($post['ipaddress']) < 0) + { + $db->update_query("posts", array('longipaddress' => my_ip2long($post['ipaddress'])), "pid = '{$post['pid']}'"); + } + $ipaddress = true; + } + + $remaining = $upper-$cnt['ipcount']; + if($remaining && $ipaddress) + { + $nextact = "13_dbchanges1"; + $startat = $startat+$ipp; + $contents = "

    Zakończono. Naciśnij przycisk Dalej, aby przejść do następnej konwersji.

    "; + } + else + { + $nextact = "13_dbchanges2"; + $contents = "

    Zakończono

    Wszystkie adresy IP zostały przekonwertowane do nowego formatu. Naciśnij przycisk Dalej, aby kontynuować.

    "; + } + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer($nextact); +} + +function upgrade13_dbchanges2() +{ + global $db, $output; + + $output->print_header("Naprawa konwersji adresów IP użytkowników"); + + if(!$_POST['ipspage']) + { + $ipp = 5000; + } + else + { + $ipp = $_POST['ipspage']; + } + + if($_POST['ipstart']) + { + $startat = $_POST['ipstart']; + $upper = $startat+$ipp; + $lower = $startat; + } + else + { + $startat = 0; + $upper = $ipp; + $lower = 1; + } + + $query = $db->simple_select("users", "COUNT(uid) AS ipcount"); + $cnt = $db->fetch_array($query); + + if($upper > $cnt['ipcount']) + { + $upper = $cnt['ipcount']; + } + + $contents .= "

    Naprawienie adresu IP z {$lower} do {$upper} (ÅÄ…cznie: {$cnt['ipcount']})

    "; + + $ipaddress = false; + $update_array = array(); + + $query = $db->simple_select("users", "regip, lastip, longlastip, longregip, uid", "", array('limit_start' => $lower, 'limit' => $ipp)); + while($user = $db->fetch_array($query)) + { + // Have we already converted this ip? + if(my_ip2long($user['regip']) < 0) + { + $update_array['longregip'] = (int)my_ip2long($user['regip']); + } + + if(my_ip2long($user['lastip']) < 0) + { + $update_array['longlastip'] = (int)my_ip2long($user['lastip']); + } + + if(!empty($update_array)) + { + $db->update_query("users", $update_array, "uid = '{$user['uid']}'"); + } + + $update_array = array(); + $ipaddress = true; + } + + $remaining = $upper-$cnt['ipcount']; + if($remaining && $ipaddress) + { + $nextact = "13_dbchanges2"; + $startat = $startat+$ipp; + $contents .= "

    Zakończono. Naciśnij przycisk Dalej, aby przejść do następnej konwersji.

    "; + } + else + { + $nextact = "13_done"; + $contents .= "

    Zakończono.

    Wszystkie adresy IP użytkowników zostały skonwertowane do nowego formatu. Naciśnij przycisk Dalej, aby kontynuować.

    "; + } + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer($nextact); +} + diff --git a/Upload/install/resources/upgrade14.php b/Upload/install/resources/upgrade14.php new file mode 100644 index 0000000..9972201 --- /dev/null +++ b/Upload/install/resources/upgrade14.php @@ -0,0 +1,216 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +function upgrade14_dbchanges() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + // TODO: Need to check for PostgreSQL / SQLite support + + if($db->field_exists('codepress', "adminoptions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminoptions DROP codepress;"); + } + + if($db->type == "pgsql") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminoptions ADD codepress int NOT NULL default '1' AFTER cpstyle"); + } + else + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminoptions ADD codepress int(1) NOT NULL default '1' AFTER cpstyle"); + } + + if($db->type != "sqlite") + { + $longregip_index = $db->index_exists("users", "longregip"); + $longlastip_index = $db->index_exists("users", "longlastip"); + + if($longlastip_index == true) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP KEY longlastip"); + } + + if($longregip_index == true) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP KEY longregip"); + } + + $longipaddress_index = $db->index_exists("posts", "longipaddress"); + if($longipaddress_index == true) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts DROP KEY longipaddress"); + } + } + + if($db->field_exists('loginattempts', "sessions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."sessions DROP loginattempts;"); + } + + if($db->field_exists('loginattempts', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP loginattempts;"); + } + + if($db->type == "pgsql") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD loginattempts smallint NOT NULL default '1';"); + } + else + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD loginattempts tinyint(2) NOT NULL default '1';"); + } + + if($db->field_exists('failedlogin', "sessions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."sessions DROP failedlogin;"); + } + + if($db->field_exists('failedlogin', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP failedlogin;"); + } + + if($db->type == "pgsql") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD failedlogin bigint NOT NULL default '0';"); + } + else + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD failedlogin bigint(30) NOT NULL default '0';"); + } + + if($db->type == "mysql" || $db->type == "mysqli") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD INDEX longregip (longregip)"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD INDEX longlastip (longlastip)"); + } + + if($db->type == "sqlite") + { + // Because SQLite 2 nor 3 allows changing a column with a primary key constraint we have to completely rebuild the entire table + // *sigh* This is the 21st century, right? + $query = $db->simple_select("datacache"); + while($datacache = $db->fetch_array($query)) + { + $temp_datacache[$datacache['title']] = array('title' => $db->escape_string($datacache['title']), 'cache' => $db->escape_string($datacache['cache'])); + } + + $db->write_query("DROP TABLE ".TABLE_PREFIX."datacache"); + + $db->write_query("CREATE TABLE ".TABLE_PREFIX."datacache ( + title varchar(50) NOT NULL default '' PRIMARY KEY, + cache mediumTEXT NOT NULL +);"); + + reset($temp_datacache); + foreach($temp_datacache as $data) + { + $db->insert_query("datacache", $data); + } + } + else if($db->type == "pgsql") + { + if(!$db->index_exists("datacache", "title")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."datacache ADD PRIMARY KEY (title)"); + } + } + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("14_dbchanges1"); +} + +function upgrade14_dbchanges1() +{ + global $db, $output; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + if($db->type == "mysql" || $db->type == "mysqli") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts ADD INDEX longipaddress (longipaddress)"); + } + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("14_dbchanges2"); +} + +function upgrade14_dbchanges2() +{ + global $db, $output; + + $output->print_header("Czyszczenie starych ustawień i grup"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + $db->delete_query("settinggroups", "name='banning' AND isdefault='0'", 1); + + $db->delete_query("settings", "name='bannedusernames'", 1); + $db->delete_query("settings", "name='bannedips'", 1); + $db->delete_query("settings", "name='bannedemails'", 1); + $db->delete_query("settings", "name='publiceventcolor'", 1); + $db->delete_query("settings", "name='privateeventcolor'", 1); + $db->delete_query("settings", "name='cssmedium'", 1); + + $db->delete_query("templates", "title='usercp_options_timezoneselect' AND sid != '-1'"); + $db->delete_query("templates", "title='moderation_reports' AND sid != '-1'"); + $db->delete_query("templates", "title='moderation_reports_report' AND sid != '-1'"); + $db->delete_query("templates", "title='moderation_reports_multipage' AND sid != '-1'"); + $db->delete_query("templates", "title='moderation_allreports' AND sid != '-1'"); + $db->delete_query("templates", "title='showthread_ratingdisplay' AND sid != '-1'"); + $db->delete_query("templates", "title='moderation_getip_adminoptions' AND sid != '-1'"); + $db->delete_query("templates", "title='calendar_eventbit_public' AND sid != '-1'"); + $db->delete_query("templates", "title='calendar_daybit_today' AND sid != '-1'"); + $db->delete_query("templates", "title='calendar_daybit' AND sid != '-1'"); + $db->delete_query("templates", "title='online_iplookup' AND sid != '-1'"); + $db->delete_query("templates", "title='online_iplookup_adminoptions' AND sid != '-1'"); + $db->delete_query("templates", "title='online_row_ip' AND sid != '-1'"); + $db->delete_query("templates", "title='calendar_eventbit_dates' AND sid != '-1'"); + $db->delete_query("templates", "title='calendar_eventbit_dates_recurring' AND sid != '-1'"); + $db->delete_query("templates", "title='calendar_eventbit_times' AND sid != '-1'"); + $db->delete_query("templates", "title='calendar_editevent_normal' AND sid != '-1'"); + $db->delete_query("templates", "title='calendar_editevent_recurring' AND sid != '-1'"); + + $db->update_query("helpdocs", array('document' => $db->escape_string("MyBB makes use of cookies to store your login information if you are registered, and your last visit if you are not. +

    Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. +

    Cookies on this forum also track the specific topics you have read and when you last read them. +

    To clear all cookies set by this forum, you can click here.")), "hid='3'", 1); + + $contents .= "Click next to continue with the upgrade process.

    "; + $output->print_contents($contents); + $output->print_footer("14_done"); +} + diff --git a/Upload/install/resources/upgrade15.php b/Upload/install/resources/upgrade15.php new file mode 100644 index 0000000..b11ed97 --- /dev/null +++ b/Upload/install/resources/upgrade15.php @@ -0,0 +1,151 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +function upgrade15_dbchanges() +{ + global $db, $output, $mybb, $cache; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + if($db->type != "pgsql") + { + $db->update_query("settinggroups", array('isdefault' => '1'), "isdefault='yes'"); + $db->update_query("settinggroups", array('isdefault' => '0'), "isdefault='no'"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events CHANGE timezone timezone varchar(4) NOT NULL default '0'"); + } + + if($db->type == "pgsql") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."warnings ALTER COLUMN revokereason SET default ''"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."warnings ALTER COLUMN notes SET default ''"); + } + + $cache->update("internal_settings", array('encryption_key' => random_str(32))); + + if($db->type != "sqlite") + { + $ip_index = $db->index_exists("sessions", "ip"); + + if($ip_index == false) + { + if($db->type == "pgsql") + { + $db->write_query("CREATE INDEX ip ON ".TABLE_PREFIX."sessions (ip)"); + } + else + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."sessions ADD INDEX (`ip`)"); + } + } + } + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("15_usernameverify"); +} + +function upgrade15_usernameverify() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    OSTRZEŻENIE - PRZECZYTAJ PONIŻSZĄ INFORMACJĘ: Następny krok usunie wszystkie przecinki (,) z loginów na Twoim forum. Ta operacja musi zostać przeprowadzona, gdyż bez niej wysyłanie prywatnych wiadomości do użytkowników z loginami, które zawierają przecinki stanie się utrudnione lub niemożliwe.

    "; + flush(); + + $contents .= "Naciśnij dalej, jeżeli powyższa informacja została przeczytana i chcesz kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("15_usernameupdate"); +} + +function upgrade15_usernameupdate() +{ + global $db, $output, $mybb, $plugins; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + require_once MYBB_ROOT."inc/datahandler.php"; + require_once MYBB_ROOT."inc/datahandlers/user.php"; + // Load plugin system for datahandler + require_once MYBB_ROOT."inc/class_plugins.php"; + $plugins = new pluginSystem; + + $not_renameable = array(); + + // Because commas can cause some problems with private message sending in usernames we have to remove them + $query = $db->simple_select("users", "uid, username", "username LIKE '%,%'"); + while($user = $db->fetch_array($query)) + { + $prefix = ''; + $userhandler = new UserDataHandler('update'); + + do + { + $username = str_replace(',', '', $user['username']).'_'.$prefix; + + $updated_user = array( + "uid" => $user['uid'], + "username" => $username + ); + $userhandler->set_data($updated_user); + + ++$prefix; + } + while(!$userhandler->verify_username() || $userhandler->verify_username_exists()); + + if(!$userhandler->validate_user()) + { + $not_renameable[] = htmlspecialchars_uni($user['username']); + } + else + { + $db->update_query("users", array('username' => $db->escape_string($username)), "uid='{$user['uid']}'"); + $db->update_query("posts", array('username' => $db->escape_string($username)), "uid='{$user['uid']}'"); + $db->update_query("threads", array('username' => $db->escape_string($username)), "uid='{$user['uid']}'"); + $db->update_query("threads", array('lastposter' => $db->escape_string($username)), "lastposteruid='{$user['uid']}'"); + $db->update_query("forums", array('lastposter' => $db->escape_string($username)), "lastposteruid='{$user['uid']}'"); + + update_stats(array("numusers" => "+0")); + } + } + + if(!empty($not_renameable)) + { + echo "OSTRZEŻENIE: Poniższe loginy nie mogły zostać zmienione automatycznie. Zmień je ręcznie po zakończeniu procesu aktualizacji.
    +
      +
    • "; + echo implode('
    • \n
    • ', $not_renameable); + echo "
    • +
    "; + } + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("15_done"); +} \ No newline at end of file diff --git a/Upload/install/resources/upgrade16.php b/Upload/install/resources/upgrade16.php new file mode 100644 index 0000000..2632144 --- /dev/null +++ b/Upload/install/resources/upgrade16.php @@ -0,0 +1,25 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +/* Nothing to do from 1.4.5 to 1.4.13 */ + diff --git a/Upload/install/resources/upgrade17.php b/Upload/install/resources/upgrade17.php new file mode 100644 index 0000000..f8866a7 --- /dev/null +++ b/Upload/install/resources/upgrade17.php @@ -0,0 +1,961 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +function upgrade17_dbchanges() +{ + global $db, $output, $mybb, $cache; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + echo "

    Dodawanie indeksu do tabeli z prywatnymi wiadomościami... "; + flush(); + + if($db->type == "mysql" || $db->type == "mysqli") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages ADD INDEX ( `toid` )"); + } + + global $footer_extra; + $footer_extra = ""; + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("17_dbchanges2"); +} + +function upgrade17_dbchanges2() +{ + global $db, $output, $mybb, $cache; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + // Update our version history first + $version_history = array(); + $dh = opendir(INSTALL_ROOT."resources"); + while(($file = readdir($dh)) !== false) + { + if(preg_match("#upgrade([0-9]+).php$#i", $file, $match)) + { + $version_history[$match[1]] = $match[1]; + } + } + sort($version_history, SORT_NUMERIC); + + // This script isn't done yet! + unset($version_history['17']); + + $cache->update("version_history", $version_history); + + if($db->field_exists('prefix', 'threads')) + { + $db->drop_column("threads", "prefix"); + } + + if($db->field_exists('loginattempts', "adminoptions")) + { + $db->drop_column("adminoptions", "loginattempts"); + } + + if($db->field_exists('loginlockoutexpiry', "adminoptions")) + { + $db->drop_column("adminoptions", "loginlockoutexpiry"); + } + + if($db->field_exists('canonlyviewownthreads', "forumpermissions")) + { + $db->drop_column("forumpermissions", "canonlyviewownthreads"); + } + + if($db->field_exists('isgroup', 'moderators')) + { + $db->drop_column("moderators", "isgroup"); + } + + if($db->field_exists('referrals', 'promotions')) + { + $db->drop_column("promotions", "referrals"); + } + + if($db->field_exists('referralstype', 'promotions')) + { + $db->drop_column("promotions", "referralstype"); + } + + if($db->field_exists('pid', 'reputation')) + { + $db->drop_column("reputation", "pid"); + } + + if($db->field_exists('allowvideocode', 'calendars')) + { + $db->drop_column("calendars", "allowvideocode"); + } + + if($db->field_exists('allowvideocode', 'forums')) + { + $db->drop_column("forums", "allowvideocode"); + } + + switch($db->type) + { + case "pgsql": + $db->add_column("threads", "prefix", "smallint NOT NULL default '0' AFTER subject"); + $db->add_column("adminoptions", "loginattempts", "int NOT NULL default '0'"); + $db->add_column("adminoptions", "loginlockoutexpiry", "int NOT NULL default '0'"); + $db->add_column("forumpermissions", "canonlyviewownthreads", "int NOT NULL default '0' AFTER canviewthreads"); + $db->add_column("moderators", "isgroup", "int NOT NULL default '0'"); + $db->add_column("promotions", "referrals", "int NOT NULL default '0' AFTER reputationtype"); + $db->add_column("promotions", "referralstype", "char(2) NOT NULL default '' AFTER referrals"); + $db->add_column("reputation", "pid", "int NOT NULL default '0'"); + $db->add_column("calendars", "allowvideocode", "int NOT NULL default '0' AFTER allowimgcode"); + $db->add_column("forums", "allowvideocode", "int NOT NULL default '0' AFTER allowimgcode"); + break; + case "sqlite": + $db->add_column("threads", "prefix", "smallint NOT NULL default '0' AFTER subject"); + $db->add_column("adminoptions", "loginattempts", "int NOT NULL default '0'"); + $db->add_column("adminoptions", "loginlockoutexpiry", "int NOT NULL default '0'"); + $db->add_column("forumpermissions", "canonlyviewownthreads", "int NOT NULL default '0' AFTER canviewthreads"); + $db->add_column("moderators", "isgroup", "int NOT NULL default '0'"); + $db->add_column("promotions", "referrals", "int NOT NULL default '0' AFTER reputationtype"); + $db->add_column("promotions", "referralstype", "varchar(2) NOT NULL default '' AFTER referrals"); + $db->add_column("reputation", "pid", "int NOT NULL default '0'"); + $db->add_column("calendars", "allowvideocode", "int(1) NOT NULL default '0' AFTER allowimgcode"); + $db->add_column("forums", "allowvideocode", "int(1) NOT NULL default '0' AFTER allowimgcode"); + break; + default: + $db->add_column("threads", "prefix", "smallint unsigned NOT NULL default '0' AFTER subject"); + $db->add_column("adminoptions", "loginattempts", "int unsigned NOT NULL default '0'"); + $db->add_column("adminoptions", "loginlockoutexpiry", "int unsigned NOT NULL default '0'"); + $db->add_column("forumpermissions", "canonlyviewownthreads", "int(1) NOT NULL default '0' AFTER canviewthreads"); + $db->add_column("moderators", "isgroup", "int(1) unsigned NOT NULL default '0'"); + $db->add_column("promotions", "referrals", "int NOT NULL default '0' AFTER reputationtype"); + $db->add_column("promotions", "referralstype", "varchar(2) NOT NULL default '' AFTER referrals"); + $db->add_column("reputation", "pid", "int unsigned NOT NULL default '0'"); + $db->add_column("calendars", "allowvideocode", "int(1) NOT NULL default '0' AFTER allowimgcode"); + $db->add_column("forums", "allowvideocode", "int(1) NOT NULL default '0' AFTER allowimgcode"); + } + + $db->update_query("forums", array('allowvideocode' => '1')); + $db->update_query("calendars", array('allowvideocode' => '1')); + + global $footer_extra; + $footer_extra = ""; + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("17_dbchanges3"); +} + +function upgrade17_dbchanges3() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + if($db->field_exists('canundovotes', 'usergroups')) + { + $db->drop_column("usergroups", "canundovotes"); + } + + if($db->field_exists('maxreputationsperuser', 'usergroups')) + { + $db->drop_column("usergroups", "maxreputationsperuser"); + } + + if($db->field_exists('maxreputationsperthread', 'usergroups')) + { + $db->drop_column("usergroups", "maxreputationsperthread"); + } + + if($db->field_exists('receivefrombuddy', 'users')) + { + $db->drop_column("users", "receivefrombuddy"); + } + + if($db->field_exists('suspendsignature', 'users')) + { + $db->drop_column("users", "suspendsignature"); + } + + if($db->field_exists('suspendsigtime', 'users')) + { + $db->drop_column("users", "suspendsigtime"); + } + + if($db->field_exists('loginattempts', 'users')) + { + $db->drop_column("users", "loginattempts"); + } + + if($db->field_exists('failedlogin', 'users')) + { + $db->drop_column("users", "failedlogin"); + } + + if($db->field_exists('usernotes', "users")) + { + $db->drop_column("users", "usernotes"); + } + + if($db->field_exists('referrals', 'users')) + { + $db->drop_column("users", "referrals"); + } + + switch($db->type) + { + case "pgsql": + $db->add_column("usergroups", "canundovotes", "int NOT NULL default '0' AFTER canvotepolls"); + $db->add_column("usergroups", "maxreputationsperuser", "bigint NOT NULL default '0' AFTER maxreputationsday"); + $db->add_column("usergroups", "maxreputationsperthread", "bigint NOT NULL default '0' AFTER maxreputationsperuser"); + $db->add_column("users", "receivefrombuddy", "int NOT NULL default '0'"); + $db->add_column("users", "suspendsignature", "int NOT NULL default '0'"); + $db->add_column("users", "suspendsigtime", "bigint NOT NULL default '0'"); + $db->add_column("users", "loginattempts", "smallint NOT NULL default '1'"); + $db->add_column("users", "failedlogin", "bigint NOT NULL default '0'"); + $db->add_column("users", "usernotes", "text NOT NULL default ''"); + $db->add_column("users", "referrals", "int NOT NULL default '0' AFTER referrer"); + break; + case "sqlite": + $db->add_column("usergroups", "canundovotes", "int NOT NULL default '0' AFTER canvotepolls"); + $db->add_column("usergroups", "maxreputationsperuser", "bigint NOT NULL default '0' AFTER maxreputationsday"); + $db->add_column("usergroups", "maxreputationsperthread", "bigint NOT NULL default '0' AFTER maxreputationsperuser"); + $db->add_column("users", "receivefrombuddy", "int NOT NULL default '0'"); + $db->add_column("users", "suspendsignature", "int NOT NULL default '0'"); + $db->add_column("users", "suspendsigtime", "bigint NOT NULL default '0'"); + $db->add_column("users", "loginattempts", "tinyint NOT NULL default '1'"); + $db->add_column("users", "failedlogin", "bigint NOT NULL default '0'"); + $db->add_column("users", "usernotes", "text NOT NULL default ''"); + $db->add_column("users", "referrals", "int NOT NULL default '0' AFTER referrer"); + break; + default: + $db->add_column("usergroups", "canundovotes", "int(1) NOT NULL default '0' AFTER canvotepolls"); + $db->add_column("usergroups", "maxreputationsperuser", "bigint(30) NOT NULL default '0' AFTER maxreputationsday"); + $db->add_column("usergroups", "maxreputationsperthread", "bigint(30) NOT NULL default '0' AFTER maxreputationsperuser"); + $db->add_column("users", "receivefrombuddy", "int(1) NOT NULL default '0'"); + $db->add_column("users", "suspendsignature", "int(1) NOT NULL default '0'"); + $db->add_column("users", "suspendsigtime", "bigint(30) NOT NULL default '0'"); + $db->add_column("users", "loginattempts", "tinyint(2) NOT NULL default '1'"); + $db->add_column("users", "failedlogin", "bigint(30) NOT NULL default '0'"); + $db->add_column("users", "usernotes", "text NOT NULL"); + $db->add_column("users", "referrals", "int unsigned NOT NULL default '0' AFTER referrer"); + } + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer("17_dbchanges4"); +} + +function upgrade17_dbchanges4() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + if($db->field_exists('remember', 'users')) + { + $db->drop_column("users", "remember"); + } + + if($db->type != "pgsql") + { + // PgSQL doesn't support longtext + $db->modify_column("searchlog", "threads", "longtext NOT NULL"); + $db->modify_column("searchlog", "posts", "longtext NOT NULL"); + } + + if($db->field_exists("uid", "moderators") && !$db->field_exists("id", "moderators")) + { + switch($db->type) + { + case "pgsql": + $db->rename_column("moderators", "uid", "id", "int", true, "'0'"); + break; + default: + $db->rename_column("moderators", "uid", "id", "int unsigned NOT NULL default '0'"); + } + } + + if($db->table_exists("threadprefixes")) + { + $db->drop_table("threadprefixes"); + } + + if($db->table_exists("delayedmoderation")) + { + $db->drop_table("delayedmoderation"); + } + + switch($db->type) + { + case "sqlite": + $db->write_query("CREATE TABLE ".TABLE_PREFIX."threadprefixes ( + rid INTEGER PRIMARY KEY, + tid int NOT NULL default '0', + uid int NOT NULL default '0', + rating smallint NOT NULL default '0', + ipaddress varchar(30) NOT NULL default '' + );"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."delayedmoderation ( + did integer PRIMARY KEY, + type varchar(30) NOT NULL default '', + delaydateline bigint(30) NOT NULL default '0', + uid int(10) NOT NULL default '0', + fid smallint(5) NOT NULL default '0', + tids text NOT NULL, + dateline bigint(30) NOT NULL default '0', + inputs text NOT NULL + );"); + break; + case "pgsql": + $db->write_query("CREATE TABLE ".TABLE_PREFIX."threadprefixes ( + pid serial, + prefix varchar(120) NOT NULL default '', + displaystyle varchar(200) NOT NULL default '', + forums text NOT NULL, + groups text NOT NULL, + PRIMARY KEY(pid) + );"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."delayedmoderation ( + did serial, + type varchar(30) NOT NULL default '', + delaydateline bigint NOT NULL default '0', + uid int NOT NULL default '0', + fid smallint NOT NULL default '0', + tids text NOT NULL, + dateline bigint NOT NULL default '0', + inputs text NOT NULL default '', + PRIMARY KEY (did) + );"); + break; + default: + $db->write_query("CREATE TABLE ".TABLE_PREFIX."threadprefixes ( + pid int unsigned NOT NULL auto_increment, + prefix varchar(120) NOT NULL default '', + displaystyle varchar(200) NOT NULL default '', + forums text NOT NULL, + groups text NOT NULL, + PRIMARY KEY(pid) + ) ENGINE=MyISAM;"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."delayedmoderation ( + did int unsigned NOT NULL auto_increment, + type varchar(30) NOT NULL default '', + delaydateline bigint(30) unsigned NOT NULL default '0', + uid int(10) unsigned NOT NULL default '0', + fid smallint(5) unsigned NOT NULL default '0', + tids text NOT NULL, + dateline bigint(30) NOT NULL default '0', + inputs text NOT NULL, + PRIMARY KEY (did) + ) ENGINE=MyISAM;"); + } + + $added_tasks = sync_tasks(); + + echo "

    Dodano {$added_tasks} nowych zadań.

    "; + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer("17_dbchanges5"); +} + +function upgrade17_dbchanges5() +{ + global $db, $output, $mybb, $cache; + + if(file_exists(MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions.php")) + { + require_once MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions.php"; + } + else if(file_exists(MYBB_ROOT."admin/inc/functions.php")) + { + require_once MYBB_ROOT."admin/inc/functions.php"; + } + else + { + $output->print_error("Upewnij się, że katalog /admin został poprawnie załadowany na serwer."); + } + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + $db->update_query("spiders", array('name' => 'Bing'), "name='MSN Search'"); + $db->update_query("spiders", array('useragent' => 'Googlebot', 'name' => 'Google'), "useragent='google'"); + $db->update_query("spiders", array('useragent' => 'Teoma', 'name' => 'Ask.com'), "useragent='ask jeeves'"); + $db->delete_query("spiders", "name='Hot Bot'"); + $db->update_query("spiders", array('useragent' => 'archive_crawler', 'name' => 'Internet Archive'), "name='Archive.org'"); + $db->update_query("spiders", array('name' => 'Alexa Internet'), "useragent='ia_archiver'"); + $db->delete_query("spiders", "useragent='scooter'"); + $db->update_query("spiders", array('useragent' => 'Slurp'), "name='Yahoo!'"); + + $query = $db->simple_select("spiders", "COUNT(*) as numexists", "useragent='twiceler'"); + if($db->fetch_field($query, "numexists") == 0) + { + $db->insert_query("spiders", array('name' => "Cuil", 'useragent' => 'twiceler')); + } + + $query = $db->simple_select("spiders", "COUNT(*) as numexists", "useragent='Baiduspider'"); + if($db->fetch_field($query, "numexists") == 0) + { + $db->insert_query("spiders", array('name' => "Baidu", 'useragent' => 'Baiduspider')); + } + + $db->update_query("attachtypes", array('mimetype' => 'application/x-httpd-php'), "extension='php'"); + $db->update_query("attachtypes", array('mimetype' => 'text/html'), "extension='htm'"); + $db->update_query("attachtypes", array('mimetype' => 'text/html'), "extension='html'"); + $db->update_query("attachtypes", array('mimetype' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'), "extension='docx'"); + $db->update_query("attachtypes", array('mimetype' => 'application/vnd.ms-excel'), "extension='xls'"); + $db->update_query("attachtypes", array('mimetype' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'), "extension='xlsx'"); + $db->update_query("attachtypes", array('mimetype' => 'application/vnd.ms-powerpoint'), "extension='ppt'"); + $db->update_query("attachtypes", array('mimetype' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation'), "extension='pptx'"); + + $cache->update_moderators(); + + $db->update_query("themes", array('allowedgroups' => 'all'), "allowedgroups='' OR allowedgroups IS NULL"); + + // Add permissions for all of our new ACP pages + change_admin_permission('config', 'thread_prefixes'); + change_admin_permission('tools', 'file_verification'); + change_admin_permission('tools', 'statistics'); + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer("17_dbchanges6"); +} + +function upgrade17_dbchanges6() +{ + global $db, $output; + + $output->print_header("Naprawa adresów IP postów po konwersji"); + + if(!$_POST['ipspage']) + { + $ipp = 5000; + } + else + { + $ipp = $_POST['ipspage']; + } + + if($_POST['ipstart']) + { + $startat = $_POST['ipstart']; + $upper = $startat+$ipp; + $lower = $startat; + } + else + { + $startat = 0; + $upper = $ipp; + $lower = 1; + } + + $query = $db->simple_select("posts", "COUNT(pid) AS ipcount"); + $cnt = $db->fetch_array($query); + + if($upper > $cnt['ipcount']) + { + $upper = $cnt['ipcount']; + } + + echo "

    Naprawianie adresu z {$lower} na {$upper} (ÅÄ…cznie: {$cnt['ipcount']})

    "; + flush(); + + $ipaddress = false; + + $query = $db->simple_select("posts", "ipaddress, pid", "", array('limit_start' => $lower, 'limit' => $ipp)); + while($post = $db->fetch_array($query)) + { + $db->update_query("posts", array('longipaddress' => (int)my_ip2long($post['ipaddress'])), "pid = '{$post['pid']}'"); + $ipaddress = true; + } + + $remaining = $upper-$cnt['ipcount']; + if($remaining && $ipaddress) + { + $nextact = "17_dbchanges6"; + $startat = $startat+$ipp; + $contents = "

    Done. Click Next to move on to the next set of post ips.

    "; + } + else + { + $nextact = "17_dbchanges7"; + $contents = "

    Zakończono

    Wszystkie adresy IP zostały naprawione. Naciśnij przycisk Dalej, aby kontynuować.

    "; + } + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer($nextact); +} + +function upgrade17_dbchanges7() +{ + global $db, $output; + + $output->print_header("Naprawa adresów IP użytkowników po konwersji"); + + if(!$_POST['ipspage']) + { + $ipp = 5000; + } + else + { + $ipp = $_POST['ipspage']; + } + + if($_POST['ipstart']) + { + $startat = $_POST['ipstart']; + $upper = $startat+$ipp; + $lower = $startat; + } + else + { + $startat = 0; + $upper = $ipp; + $lower = 1; + } + + $query = $db->simple_select("users", "COUNT(uid) AS ipcount"); + $cnt = $db->fetch_array($query); + + if($upper > $cnt['ipcount']) + { + $upper = $cnt['ipcount']; + } + + $contents .= "

    Naprawianie adresu IP z {$lower} do {$upper} (ÅÄ…cznie: {$cnt['ipcount']})

    "; + + $ipaddress = false; + $update_array = array(); + + $query = $db->simple_select("users", "regip, lastip, uid", "", array('limit_start' => $lower, 'limit' => $ipp)); + while($user = $db->fetch_array($query)) + { + $update_array = array( + 'longregip' => (int)my_ip2long($user['regip']), + 'longlastip' => (int)my_ip2long($user['lastip']) + ); + + $db->update_query("users", $update_array, "uid = '{$user['uid']}'"); + + $update_array = array(); + $ipaddress = true; + } + + $remaining = $upper-$cnt['ipcount']; + if($remaining && $ipaddress) + { + $nextact = "17_dbchanges7"; + $startat = $startat+$ipp; + $contents .= "

    Zakończono. Naciśnij przycisk Dalej, aby kontynuować proces.

    "; + } + else + { + $nextact = "17_redoconfig"; + $contents .= "

    Zakończono.

    Wszystkie adresy IP użytkowników zostały naprawione. Naciśnij przycisk Dalej, aby kontynuować.

    "; + } + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer($nextact); +} + +function upgrade17_redoconfig() +{ + global $db, $output, $orig_config, $mybb; + + $config = $orig_config; + + $output->print_header("Ponowne tworzenie pliku config.php"); + + if(!is_array($config['memcache'])) + { + // Backup our old Config file + @copy(MYBB_ROOT."inc/config.php", MYBB_ROOT."inc/config.backup.php"); + + $fh = @fopen(MYBB_ROOT."inc/config.php", "w"); + if(!$fh) + { + echo "

    Unable to open inc/config.php
    Before the upgrade process can continue, you need to changes the permissions of inc/config.php so it is writable.

    "; + $output->print_footer("17_redoconfig"); + exit; + } + + if(!$config['memcache_host']) + { + $config['memcache_host'] = "localhost"; + } + + if(!$config['memcache_port']) + { + $config['memcache_port'] = 11211; + } + + $comment = ""; + + if(!$db->db_encoding || !$config['database']['encoding']) + { + $comment = " // "; + } + + if(!$config['database']['encoding']) + { + $config['database']['encoding'] = "utf8"; + } + + // Update SQLite selection. SQLite 2 is depreciated. + if($config['database']['type'] == 'sqlite2' || $config['database']['type'] == 'sqlite3') + { + $config['database']['type'] = 'sqlite'; + } + + // Do we have a read or a write database? + if($config['database']['read']) + { + $database_config = "\$config['database']['type'] = '{$config['database']['type']}';"; + foreach(array('read', 'write') as $type) + { + // Multiple read/write databases? + if($config['database'][$type][0]['database']) + { + $i = 0; + foreach($config['database'][$type] as $database_connection) + { + $database_config .= " +\$config['database']['{$type}'][{$i}]['database'] = '{$database_connection['database']}'; +\$config['database']['{$type}'][{$i}]['table_prefix'] = '{$database_connection['table_prefix']}'; +\$config['database']['{$type}'][{$i}]['hostname'] = '{$database_connection['hostname']}'; +\$config['database']['{$type}'][{$i}]['username'] = '{$database_connection['username']}'; +\$config['database']['{$type}'][{$i}]['password'] = '{$database_connection['password']}';"; + ++$i; + } + } + // Just a single database read/write connection + else + { + $database_config .= " +\$config['database']['{$type}']['database'] = '{$config['database'][$type]['database']}'; +\$config['database']['{$type}']['table_prefix'] = '{$config['database'][$type]['table_prefix']}'; + +\$config['database']['{$type}']['hostname'] = '{$config['database'][$type]['hostname']}'; +\$config['database']['{$type}']['username'] = '{$config['database'][$type]['username']}'; +\$config['database']['{$type}']['password'] = '{$config['database'][$type]['password']}';"; + } + } + } + // Standard database connection stuff + else + { + $database_config = "\$config['database']['type'] = '{$config['database']['type']}'; +\$config['database']['database'] = '{$config['database']['database']}'; +\$config['database']['table_prefix'] = '{$config['database']['table_prefix']}'; + +\$config['database']['hostname'] = '{$config['database']['hostname']}'; +\$config['database']['username'] = '{$config['database']['username']}'; +\$config['database']['password'] = '{$config['database']['password']}'; +"; + } + + + $configdata = " {$config['log_pruning']['admin_logs']}, // Administrator logs + 'mod_logs' => {$config['log_pruning']['mod_logs']}, // Moderator logs + 'task_logs' => {$config['log_pruning']['task_logs']}, // Scheduled task logs + 'mail_logs' => {$config['log_pruning']['mail_logs']}, // Mail error logs + 'user_mail_logs' => {$config['log_pruning']['user_mail_logs']}, // User mail logs + 'promotion_logs' => {$config['log_pruning']['promotion_logs']} // Promotion logs +); + +?".">"; + fwrite($fh, $configdata); + fclose($fh); + } + echo "

    Plik z konfiguracją został pomyślnie utworzony ponownie.

    "; + echo "

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer("17_updatecss"); +} +function upgrade17_updatecss() +{ + global $db, $output, $orig_config, $mybb; + + if(file_exists(MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions_themes.php")) + { + require_once MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions_themes.php"; + } + else if(file_exists(MYBB_ROOT."admin/inc/functions_themes.php")) + { + require_once MYBB_ROOT."admin/inc/functions_themes.php"; + } + else + { + $output->print_error("Upewnij się, że katalog /admin został poprawnie załadowany na serwer."); + } + + $output->print_header("Aktualizowanie arkuszy stylów CSS"); + + $query = $db->simple_select("themestylesheets", "*", "name='global.css' OR name='usercp.css'"); + while($theme = $db->fetch_array($query)) + { + resync_stylesheet($theme); + } + + $query = $db->simple_select("themestylesheets", "*", "name='global.css' OR name='usercp.css'"); + while($theme = $db->fetch_array($query)) + { + $theme['stylesheet'] = upgrade_css_140_to_160($theme['name'], $theme['stylesheet']); + + // Create stylesheets + cache_stylesheet($theme['tid'], $theme['cachefile'], $theme['stylesheet']); + + $update_stylesheet = array( + "stylesheet" => $db->escape_string($theme['stylesheet']), + "lastmodified" => TIME_NOW + ); + $db->update_query("themestylesheets", $update_stylesheet, "sid='{$theme['sid']}'"); + } + + echo "

    Arkusze stylów CSS zostały zaktualizowane.

    "; + echo "

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + + global $footer_extra; + //$footer_extra = ""; + + $output->print_footer("17_done"); +} + +function upgrade_css_140_to_160($name, $css) +{ + // Update our CSS to the new stuff in 1.6 + $parsed_css = css_to_array($css); + + if($name == "global.css") + { + if(is_array($parsed_css)) + { + foreach($parsed_css as $class_id => $array) + { + switch($array['class_name']) + { + case '.navigation .active': + $parsed_css[$class_id]['values'] = str_replace('font-size: small;', 'font-size: 13px;', $array['values']); + break; + case '.highlight': + $parsed_css[$class_id]['values'] = str_replace('padding: 3px;', "padding-top: 3px;\n\tpadding-bottom: 3px;", $array['values']); + break; + case '.pm_alert': + case '.red_alert': + $parsed_css[$class_id]['values'] .= "\n\tmargin-bottom: 15px;"; + break; + case '.pagination .pagination_current': + $parsed_css[$class_id]['values'] .= "\n\tcolor: #000;"; + break; + default: + } + } + } + + $to_add = array( + md5('#panel .remember_me input') => array("class_name" => '#panel .remember_me input', "values" => "vertical-align: middle;\n\tmargin-top: -1px;"), + md5('.hiddenrow') => array("class_name" => '.hiddenrow', "values" => 'display: none;'), + md5('.selectall') => array("class_name" => '.selectall', "values" => "background-color: #FFFBD9;\n\tfont-weight: bold;\n\ttext-align: center;"), + md5('.repbox') => array("class_name" => '.repbox', "values" => "font-size:16px;\n\tfont-weight: bold;\n\tpadding:5px 7px 5px 7px;"), + md5('._neutral') => array("class_name" => '._neutral', "values" => "background-color:#FAFAFA;\n\tcolor: #999999;\n\tborder:1px solid #CCCCCC;"), + md5('._minus') => array("class_name" => '._minus', "values" => "background-color: #FDD2D1;\n\tcolor: #CB0200;\n\tborder:1px solid #980201;"), + md5('._plus') => array("class_name" => '._plus', "values" => "background-color:#E8FCDC;\n\tcolor: #008800;\n\tborder:1px solid #008800;"), + md5('.pagination_breadcrumb') => array("class_name" => '.pagination_breadcrumb', "values" => "background-color: #f5f5f5;\n\tborder: 1px solid #fff;\n\toutline: 1px solid #ccc;\n\tpadding: 5px;\n\tmargin-top: 5px;\n\tfont-weight: normal;"), + md5('.pagination_breadcrumb_link') => array("class_name" => '.pagination_breadcrumb_link', "values" => "vertical-align: middle;\n\tcursor: pointer;"), + ); + } + else if($name == "usercp.css") + { + $to_add = array( + md5('.usercp_notepad') => array("class_name" => '.usercp_notepad', "values" => "width: 99%;"), + md5('.usercp_container') => array("class_name" => '.usercp_container', "values" => "margin: 5px;\n\tpadding: 8px;\n\tborder:1px solid #CCCCCC;"), + ); + } + + foreach($to_add as $class_id => $array) + { + if($already_parsed[$class_id]) + { + $already_parsed[$class_id]++; + $class_id .= "_".$already_parsed[$class_id]; + } + else + { + $already_parsed[$class_id] = 1; + } + + $array['name'] = ""; + $array['description'] = ""; + + $parsed_css[$class_id] = $array; + } + + $css = ""; + foreach($parsed_css as $class_id => $array) + { + if($array['name'] || $array['description']) + { + $theme['css'] .= "/* "; + if($array['name']) + { + $array['css'] .= "Name: {$array['name']}"; + + if($array['description']) + { + $array['css'] .= "\n"; + } + } + + if($array['description']) + { + $array['css'] .= "Description: {$array['description']}"; + } + + $array['css'] .= " */\n"; + } + + $css .= "{$array['class_name']} {\n\t{$array['values']}\n}\n"; + } + + return $css; +} diff --git a/Upload/install/resources/upgrade18.php b/Upload/install/resources/upgrade18.php new file mode 100644 index 0000000..e253c39 --- /dev/null +++ b/Upload/install/resources/upgrade18.php @@ -0,0 +1,58 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +function upgrade18_dbchanges() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + + // Update the usergroup sequence for pgSQL - #1094 + if($mybb->config['database']['type'] == "pgsql") + { + $query = $db->simple_select("usergroups", "COUNT(gid) AS group_count"); + $group_count = $db->fetch_field($query, "group_count"); + + ++$group_count; + $db->query("ALTER SEQUENCE ".$mybb->config['database']['table_prefix']."usergroups_gid_seq RESTART WITH ".$group_count.""); + } + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "); + $output->print_footer("18_updatecache"); +} + +function upgrade18_updatecache() +{ + global $cache, $output; + + $output->print_header("Aktualizacja pamięci podręcznej"); + + echo "

    Przebudowywanie pamięci podręcznej...

    "; + + // Update the Moderator cache - #1200 + $cache->update_moderators(); + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "); + $output->print_footer("18_done"); +} diff --git a/Upload/install/resources/upgrade19.php b/Upload/install/resources/upgrade19.php new file mode 100644 index 0000000..475e745 --- /dev/null +++ b/Upload/install/resources/upgrade19.php @@ -0,0 +1,24 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +/* Nothing to do for 1.6.1 and 1.6.2 */ + diff --git a/Upload/install/resources/upgrade2.php b/Upload/install/resources/upgrade2.php new file mode 100644 index 0000000..bcf7928 --- /dev/null +++ b/Upload/install/resources/upgrade2.php @@ -0,0 +1,290 @@ + 1, + "revert_all_themes" => 1, + "revert_all_settings" => 1, + "requires_deactivated_plugins" => 1, +); + +function upgrade2_dbchanges() +{ + global $db, $output; + + $output->print_header("Dokonywanie zmian w bazie danych"); + + $contents .= "

    Trwa dokonywanie wymaganych zmian w bazie danych..."; + + $db->drop_table("badwords"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."badwords ( + bid smallint(6) NOT NULL auto_increment, + badword varchar(100) NOT NULL, + replacement varchar(100) NOT NULL, + PRIMARY KEY(bid) + );"); + + if($db->field_exists("icon", TABLE_PREFIX."attachtypes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachtypes DROP icon;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachtypes ADD icon varchar(100) NOT NULL;"); + + $db->delete_query("attachtypes"); + + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (1, 'Archiwum ZIP', 'application/zip', 'zip', 1024, 'images/attachtypes/zip.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (2, 'Obraz JPEG', 'image/jpeg', 'jpg', 500, 'images/attachtypes/image.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (3, 'Dokument tekstowy', 'text/plain', 'txt', 200, 'images/attachtypes/txt.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (4, 'Obraz GIF', 'image/gif', 'gif', 500, 'images/attachtypes/image.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (6, 'Plik PHP', 'application/octet-stream', 'php', 500, 'images/attachtypes/php.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (7, 'Obraz PNG', 'image/png', 'png', 500, 'images/attachtypes/image.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (8, 'Dokument Microsoft Word', 'application/msword', 'doc', 1024, 'images/attachtypes/doc.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (9, '', 'application/octet-stream', 'htm', 100, 'images/attachtypes/html.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (10, '', 'application/octet-stream', 'html', 100, 'images/attachtypes/html.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (11, '', 'image/jpeg', 'jpeg', 500, 'images/attachtypes/image.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (12, '', 'application/x-gzip', 'gz', 1024, 'images/attachtypes/tgz.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (13, '', 'application/x-tar', 'tar', 1024, 'images/attachtypes/tar.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (14, '', 'text/css', 'css', 100, 'images/attachtypes/css.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (15, '', 'application/pdf', 'pdf', 2048, 'images/attachtypes/pdf.gif');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."attachtypes (atid, name, mimetype, extension, maxsize, icon) VALUES (16, '', 'image/bmp', 'bmp', 500, 'images/attachtypes/image.gif');"); + + if($db->field_exists("outerwidth", TABLE_PREFIX."themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP outerwidth;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes ADD outerwidth varchar(15) NOT NULL;"); + + if($db->field_exists("icon", TABLE_PREFIX."themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP icon;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes ADD outercolor varchar(15) NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes CHANGE body bodybgcolor varchar(15) NOT NULL;"); + + if($db->field_exists("bodybgimage", TABLE_PREFIX."themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP bodybgimage;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes ADD bodybgimage varchar(100) NOT NULL default '' AFTER bodybgcolor;"); + + if($db->field_exists("bodybgimageattributes", TABLE_PREFIX."themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP bodydbimageattributes;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes ADD bodybgimageattributes varchar(100) NOT NULL default '' AFTER bodybgimage;"); + + + $db->write_query("UPDATE ".TABLE_PREFIX."themes SET outerwidth='0', bodybgcolor='#e3e3e3', bodybgimage='images/Light/logo_bg.png', bodybgimageattributes='repeat-x'"); + + $db->drop_table("regimages"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."regimages ( + imagehash varchar(32) NOT NULL, + imagestring varchar(8) NOT NULL, + dateline bigint(30) NOT NULL + );"); + + $db->write_query("UPDATE ".TABLE_PREFIX."adminoptions SET cpstyle=''"); + + if($db->field_exists("language", TABLE_PREFIX."users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP language;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD language varchar(50) NOT NULL;"); + + if($db->field_exists("timeonline", TABLE_PREFIX."users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP timeonline;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD timeonline bigint(30) NOT NULL default '0';"); + + if($db->field_exists("showcodebuttons", TABLE_PREFIX."users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."user DROP showcodebuttons;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD showcodebuttons int(1) NOT NULL default '1';"); + + $db->write_query("UPDATE ".TABLE_PREFIX."users SET language='english', showcodebuttons=1"); + + if($db->field_exists("oldgroup", TABLE_PREFIX."awaitingactivation")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."awaitingactivation DROP oldgroup;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."awaitingactivation ADD oldgroup bigint(30) NOT NULL;"); + + if($db->field_exists("misc", TABLE_PREFIX."awaitingactivation")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."awaitingactivation DROP misc;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."awaitingactivation ADD misc varchar(255) NOT NULL;"); + + $db->write_query("DELETE FROM ".TABLE_PREFIX."awaitingactivation WHERE type='e'"); + + $db->drop_table("settings"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."settings ( + sid smallint(6) NOT NULL auto_increment, + name varchar(120) NOT NULL default '', + title varchar(120) NOT NULL default '', + description text NOT NULL, + optionscode text NOT NULL, + value text NOT NULL, + disporder smallint(6) NOT NULL default '0', + gid smallint(6) NOT NULL default '0', + PRIMARY KEY (sid) + );"); + + $db->drop_table("reportedposts"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."reportedposts ( + rid smallint(6) NOT NULL auto_increment, + pid smallint(6) NOT NULL, + tid smallint(6) NOT NULL, + fid smallint(6) NOT NULL, + uid smallint(6) NOT NULL, + reportstatus int(1) NOT NULL, + reason varchar(250) NOT NULL, + dateline bigint(30) NOT NULL, + PRIMARY KEY (rid) + );"); + + $db->drop_table("threadsread"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."threadsread ( + tid smallint(6) NOT NULL, + uid smallint(6) NOT NULL, + dateline int(10) NOT NULL, + UNIQUE KEY tiduid (tid, uid) + );"); + $contents .= "zakończono

    "; + + $output->print_contents("$contents

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "); + $output->print_footer("2_dbchanges2"); +} + +function upgrade2_dbchanges2() +{ + global $db, $output; + + $output->print_header("Dokonywanie zmian w bazie danych"); + $contents .= "

    Trwa ponowne wprowadzenie ustawień..."; + + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'boardclosed', 'Board Closed', 'If you need to close your forums to make some changes or perform an upgrade, this is the global switch. Viewers will not be able to view your forums, however, they will see a message with the reason you specify below.
    \r\n
    \r\nAdministrators will still be able to view the forums.', 'yesno', 'no', 1, 26);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'boardclosed_reason', 'Board Closed Reason', 'If your forum is closed, you can set a message here that your visitors will be able to see when they visit your forums.', 'textarea', 'These forums are currently closed for maintenance. Please check back later.', 2, 26);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'bbname', 'Board Name', 'The name of your message boards. We recommend that it is not over 75 characters.', 'text', 'MyBB Forums', 1, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'bburl', 'Board URL', 'The url to your forums.
    Include the http://. Do NOT include a trailing slash.', 'text', '', 2, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'homename', 'Homepage Name', 'The name of your homepage. This will appear in the footer with a link to it.', 'text', 'MyBB', 3, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'homeurl', 'Homepage URL', 'The full URL of your homepage. This will be linked to in the footer along with its name.', 'text', 'http://www.mybb.com', 4, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'dateformat', 'Date Format', 'The format of the dates used on the forum. This format uses the PHP date() function. We recommend not changing this unless you know what you\'re doing.', 'text', 'm-d-Y', 1, 3);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'adminemail', 'Admin Email', 'The administrator\'s email address. This will be used for outgoing emails sent via the forums.', 'text', '', 5, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'timeformat', 'Time Format', 'The format of the times used on the forum. This format uses PHP\'s date() function. We recommend not changing this unless you know what you\'re doing.', 'text', 'h:i A', 2, 3);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'threadsperpage', 'Threads Per Page', '', 'text', '20', 1, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'stickyprefix', 'Sticky Threads Prefix', 'The prefix of topics which have been made sticky by a moderator or administrator.', 'text', 'Sticky:', 2, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'hottopic', 'Replys For Hot Topic', 'The number of replies that is needed for a topic to be considered \'hot\'.', 'text', '20', 3, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'cookiedomain', 'Cookie Domain', 'The domain which cookies should be set to. This can remain blank. It should also start with a . so it covers all subdomains.', 'text', '', 8, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'cookiepath', 'Cookie Path', 'The path which cookies are set to, we recommend setting this to the full directory path to your forums with a trailing slash.', 'text', '', 9, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'pollprefix', 'Poll Prefix', 'The prefix on forum display which contain polls.', 'text', 'Poll:', 4, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'postsperpage', 'Posts Per Page:', 'The number of posts to display per page. We recommend its not higher than 20 for people with slower connections.', 'text', '10', 1, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'regdateformat', 'Registered Date Format', 'The format used on showthread where it shows when the user registered.', 'text', 'M Y', 3, 3);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'sigmycode', 'Allow MyCode in Signatures', 'Do you want to allow MyCode to be used in users\' signatures?', 'yesno', 'yes', 1, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'sigsmilies', 'Allow Smilies in Signatures', 'Do you want to allow smilies to be used in users\' signatures?', 'yesno', 'yes', 3, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'sightml', 'Allow HTML in Signatures', 'Do you want to allow HTML to be used in users\' signatures?', 'yesno', 'no', 4, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'sigimgcode', 'Allow [img] Code in Signatures', 'Do you want to allow [img] code to be used in users\' signatures?', 'yesno', 'yes', 5, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'quoteboxstyle', 'Fancy Quote Boxes', 'Selecting yes will cause quotes to be in a table and look more professional. Selecting no will show quotes in the traditional way.', 'yesno', 'yes', 1, 10);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'codeboxstyle', 'Fancy Code Boxes', 'Selecting yes will cause code to be in a table and look more professional. Selecting no will show code in the traditional way.', 'yesno', 'yes', 2, 10);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'threadusenetstyle', 'Usenet Style Thread View', 'Selecting yes will cause posts to look similar to how posts look in USENET. No will cause posts to look the modern way.', 'yesno', 'no', 4, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'pmsallowhtml', 'Allow HTML', 'Selecting yes will allow HTML to be used in private messages.', 'yesno', 'no', 1, 11);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'pmsallowmycode', 'Allow MyCode', 'Selecting yes will allow MyCode to be used in private messages.', 'yesno', 'yes', 2, 11);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'pmsallowsmilies', 'Allow Smilies', 'Selecting yes will allow Smilies to be used in private messages.', 'yesno', 'yes', 3, 11);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'pmsallowimgcode', 'Allow [img] Code', 'Selecting yes will allow [img] Code to be used in private messages.', 'yesno', 'yes', 4, 11);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'siglength', 'Length limit in Signatures', 'The maximum number of characters a user can place in a signature.', 'text', '255', 6, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'messagelength', 'Maximum Message Length', 'The maximum number of characters to allow in a message. A setting of 0 allows an unlimited length.', 'text', '0', 1, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'membersperpage', 'Members Per Page', 'The number of members to show per page on the member list.', 'text', '20', 1, 12);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'load', '*NIX Load Limiting', 'Limit the maximum server load before myBB rejects people. 0 for none. Recommended limit is 5.0.', 'text', '0', 5, 27);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'emailkeep', 'Users Keep Email', 'If a current user has an email already registered in your banned list, should he be allowed to keep it.', 'yesno', 'no', 4, 14);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'ipban', 'Ban by IP', 'Here, you may specify IP addresses or a range of IP addresses. You must separate each IP with a space.', 'textarea', '', 2, 14);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'emailban', 'Ban by Email', 'You may specify specific email addresses to ban, or you may specify a domain. You must separate email addresses and domains with a space.', 'textarea', '', 3, 14);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'avatarsize', 'Max Uploaded Avatar Size', 'Maximum file size (in kilobytes) of uploaded avatars.', 'text', '10', 8, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'avatardir', 'Avatar Directory', 'The directory where your avatars are stored. These are used in the avatar list in the User CP.', 'text', 'images/avatars', 7, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showeditedby', 'Show \'edited by\' Messages', 'Once a post is edited by a regular user, do you want to show the edited by message?', 'yesno', 'yes', 6, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxposts', 'Maximum Posts Per Day', 'This is the total number of posts allowed per user per day. 0 for unlimited.', 'text', '0', 2, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showeditedbyadmin', 'Show \'edited by\' Message for Forum Staff', 'Do you want to show edited by messages for forum staff when they edit their posts?', 'yesno', 'yes', 7, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'bannedusernames', 'Banned Usernames', 'Ban users from registering certain usernames. Seperate them with a space.', 'textarea', 'drcracker Oops! hmmm', 1, 14);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxpolloptions', 'Maximum Number of Poll Options', 'The maximum number of options for polls that users can post.', 'text', '10', 3, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'dotfolders', 'Use \'dot\' Icons', 'Do you want to show dots on the thread indicators of threads users have participated in.', 'yesno', 'yes', 8, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'contactlink', 'Contact Us Link', 'This will be used for the Contact Us link on the bottom of all the forum pages. Can either be an email address (using mailto:email@website.com) or a hyperlink.', 'text', 'mailto:contact@mybb.com', 6, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showdescriptions', 'Show Forum Descriptions?', 'This option will allow you to turn off showing the descriptions for forums.', 'yesno', 'yes', 1, 16);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showbirthdays', 'Show Today\'s Birthdays?', 'Do you want to show today\'s birthdays on the forum homepage?', 'yesno', 'yes', 2, 16);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showwol', 'Show Who\'s Online?', 'Display the currently active users on the forum home page.', 'yesno', 'yes', 4, 16);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'hideprivateforums', 'Hide Private Forums?', 'You can hide private forums by turning this option on. This option also hides forums on the forum jump and all subforums.', 'yesno', 'yes', 3, 16);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showsimilarthreads', 'Show \'Similar Threads\' Table', 'The Similar Threads table shows threads that are relevant to the thread being read. You can set the relevancy below.', 'yesno', 'no', 5, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'similarityrating', 'Similar Threads Relevancy Rating', 'This allows you to limit similar threads to ones more relevant (0 being not relevant). This number should not be over 10 and should not be set low (<5) for large forums.', 'text', '1', 7, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'similarlimit', 'Similar Threads Limit', 'Here you can change the total amount of similar threads to be shown in the similar threads table. It is recommended that it is not over 15 for 56k users.', 'text', '10', 8, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'privateeventcolor', 'Private Events Color', 'The color that private events will be shown in on the main calendar page.', 'text', 'red', 2, 17);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'publiceventcolor', 'Public Events Color', 'The color that public events will be shown in on the main calendar page.', 'text', 'green', 1, 17);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'movedprefix', 'Moved Threads Prefix', 'The prefix that threads that have been moved to another forum should have.', 'text', 'Moved:', 5, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'hottopicviews', 'Views For Hot Topic', 'The number of views a thread can have before it is considered \'hot\'.', 'text', '150', 7, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'logip', 'Log Posting IP Addresses', 'Do you wish to log ip addresses of users who post, and who you want to show ip addresses to.', 'radio\r\nno=Do not log IP\r\nhide=Show to Admins & Mods\r\nshow=Show to all Users', 'hide', 3, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'statslimit', 'Stats Limit', 'The number of threads to show on the stats page for most replies and most views.', 'text', '15', 10, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'modlist', 'Forums\' Moderator Listing', 'Here you can turn on or off the listing of moderators for each forum on index.php and forumdisplay.php', 'onoff', 'on', 5, 16);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'smilieinserter', 'Clickable Smilies Inserter', 'Clickable smilies will appear on the posting pages if this option is set to \'on\'.', 'onoff', 'on', 1, 20);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'smilieinsertertot', 'No. of Smilies to show', 'Enter the total number of smilies to show on the clickable smilie inserter.', 'text', '20', 2, 20);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'smilieinsertercols', 'No. of Smilie Cols to Show', 'Enter the number of columns you wish to show on the clickable smilie inserter.', 'text', '4', 3, 20);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showindexstats', 'Show Small Stats Section', 'Do you want to show the total number of threads, posts, members, and the last member on the forum home?', 'yesno', 'yes', 6, 16);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'regtype', 'Registration Method', 'Please select the method of registration to use when users register.', 'select\r\ninstant=Instant Activation\r\nverify=Send Email Verification\r\nrandompass=Send Random Password', 'verify', 1, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'userpppoptions', 'User Selectable Posts Per Page', 'If you would like to allow users to select how many posts are shown per page in a thread, enter the options they should be able to select separated with commas. If this is left blank they will not be able to choose how many posts are shown per page.', 'text', '5,10,20,25,30,40,50', 2, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'usertppoptions', 'User Selectable Threads Per Page', 'If you would like to allow users to select how many threads per page are shown in a forum, enter the options they should be able to select separated with commas. If this is left blank they will not be able to choose how many threads are shown per page.', 'text', '10,20,25,30,40,50', 6, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'wolcutoffmins', 'Cut-off Time (mins)', 'The number of minutes before a user is marked offline. Recommended: 15.', 'text', '15', 1, 23);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'postfloodcheck', 'Post Flood Checking', 'Set to on if you want to enable flood checking for posts. Specifiy the time between posts below.', 'onoff', 'on', 4, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'postfloodsecs', 'Post Flood Time', 'Set the time (in seconds) users have to wait between posting, to be in effect; the option above must be on.', 'text', '60', 5, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'gzipoutput', 'Use GZip Page Compression?', 'Do you want to compress pages in GZip format when they are sent to the browser? This means quicker downloads for your visitors, and less traffic usage for you. The level of the compression is set by the server\'s load.', 'yesno', 'yes', 1, 27);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'standardheaders', 'Send Standard Headers', 'With some web servers, this option can cause problems; with others, it is needed. ', 'yesno', 'no', 2, 27);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'nocacheheaders', 'Send No Cache Headers', 'With this option you can prevent caching of the page by the browser.', 'yesno', 'no', 3, 27);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxpostimages', 'Maximum Images per Post', 'Enter the maximum number of images (including smilies) a user can put in their post. Set to 0 to disable this.', 'text', '10', 8, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxsigimages', 'Maximum Number of Images per Signature', 'Enter the maximum number of images (including smilies) a user can put in their signature. Set to 0 to disable this.', 'text', '2', 2, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'browsingthisforum', 'Users Browsing this Forum', 'Here you can turn off the \'users browsing this forum\' feature.', 'onoff', 'on', 9, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'usereferrals', 'Use Referrals System', 'Do you want to use the user referrals system on these forums?', 'yesno', 'yes', 3, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'subscribeexcerpt', 'Amount of Characters for Subscription Previews', 'How many characters of the post do you want to send with the email notification of a new reply.', 'text', '100', 9, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'cpstyle', 'Control Panel Style', 'The Default style that the control panel will use. Styles are inside the styles folder. A folder name inside that folder becomes the style title and style.css inside the style title folder is the css style file.', 'cpstyle', 'Axiom', 2, 28);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'cplanguage', 'Control Panel Language', 'The language of the control panel.', 'adminlanguage', 'english', 1, 28);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'minnamelength', 'Minimum Username Length', 'The minimum number of characters a username can be when a user registers.', 'text', '3', 5, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxnamelength', 'Maximum Username Length', 'The maximum number of characters a username can be when a user registers.', 'text', '30', 6, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'redirects', 'Friendly Redirection Pages', 'This will enable friendly redirection pages instead of bumping the user directly to the page.', 'onoff', 'on', 4, 27);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'betweenregstime', 'Time Between Registrations', 'The amount of time (in hours) to disallow registrations for users who have already registered an account under the same ip address.', 'text', '24', 2, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxregsbetweentime', 'Maximum Registrations Per IP Address', 'This option allows you to set the maximum amount of times a certain user can register within the timeframe specified above.', 'text', '2', 4, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showstats', 'Show forum statistics', 'Do you want to show the total number of posts, threads, members and the last registered member on the portal page?', 'yesno', 'yes', 5, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showpms', 'Show the number of PMs to users', 'Do you want to show the number of private messages the current user has in their pm system.', 'yesno', 'yes', 4, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showwelcome', 'Show the Welcome box', 'Do you want to show the welcome box to visitors / users.', 'yesno', 'yes', 3, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_numannouncements', 'Number of announcements to show', 'Please enter the number of announcements to show on the main page.', 'text', '10', 2, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showstats', 'Show forum statistics', 'Do you want to show the total number of posts, threads, members and the last registered member on the portal page?', 'yesno', 'yes', 5, 29);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showwol', 'Show Whos Online', 'Do you want to show the \'whos online\' information to users when they visit the portal page?', 'yesno', 'yes', 6, 29);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_announcementsfid', 'Forum ID to pull announcements from', 'Please enter the forum id (fid) of the forum you wish to pull the announcements from', 'text', '1', 1, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showdiscussionsnum', 'Number of latest discussions to show', 'Please enter the number of current forum discussions to show on the portal page.', 'text', '10', 8, 29);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showwol', 'Show Who\'s Online', 'Do you want to show the \'Who\'s online\' information to users when they visit the portal page?', 'yesno', 'yes', 6, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showsearch', 'Show Search Box', 'Do you want to show the search box, allowing users to quickly search the forums on the portal?', 'yesno', 'yes', 7, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showdiscussions', 'Show Latest Discussions', 'Do you wish to show the current forum discussions on the portal page?', 'yesno', 'yes', 8, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showdiscussionsnum', 'Number of latest discussions to show', 'Please enter the number of current forum discussions to show on the portal page.', 'text', '10', 9, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'attachthumbh', 'Attached Thumbnail Maximum Height', 'Enter the width that attached thumbnails should be generated at.', 'text', '60', 12, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'attachthumbw', 'Attached Thumbnail Maximum Width', 'Enter the width that attached thumbnails should be generated at.', 'text', '60', 13, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxattachments', 'Maximum Attachments Per Post', 'THe maximum number of attachments a user is allowed to upload per post.', 'text', '5', 10, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'attachthumbnails', 'Show Attached Thumbnails in Posts', 'Do you want to show the generated thumbnails for attached images inside the posts?', 'yesno', 'yes', 11, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'polloptionlimit', 'Maximum Poll Option Length', 'The maximum length that each poll option can be. (Set to 0 to disable).', 'text', '250', 1, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'timezoneoffset', 'Default Timezone Offset', 'Here you can set the default timezone offset for guests and members using the default offset.', 'text', '+10', 4, 3);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'bblanguage', 'Default Language', 'The default language that MyBB should use for guests and for users without a selected language in their user control panel.', 'language', 'english', 7, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'regimage', 'Antispam Registration Image', 'If yes, and GD is installed, an image will be shown during registration where users are required to enter the text contained within the image to continue with registration.', 'onoff', 'on', 1, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'reportmethod', 'Reported Posts Medium', 'Please select from the list how you want reported posts to be dealt with. Storing them in the database is probably the better of the options listed.', 'radio\r\ndb=Stored in the Database\r\npms=Sent as Private Messages\r\nemail=Sent via Email', 'db', 1, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'threadreadcut', 'Read Threads in Database (Days)', 'The number of days that you wish to keep thread read information in the database. For large boards, we do not recommend a high number as the board will become slower. Set to 0 to disable.', 'text', '7', 3, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'announcementlimit', 'Announcements Limit', 'The number of forum announcements to show in the thread listing on the forum display pages. Set to 0 to show all active announcements.', 'text', '2', 10, 7);"); + + $output->print_contents("$contents

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "); + $output->print_footer("2_done"); +} +} diff --git a/Upload/install/resources/upgrade20.php b/Upload/install/resources/upgrade20.php new file mode 100644 index 0000000..b19b3bc --- /dev/null +++ b/Upload/install/resources/upgrade20.php @@ -0,0 +1,51 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +function upgrade20_dbchanges() +{ + global $db, $output, $mybb; + + $output->print_header("Naprawianie sekwencji w bazie danych"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + + // Update the sequences for pgSQL - #1094, #1248 + if($mybb->config['database']['type'] == "pgsql") + { + $db->query("SELECT setval('{$mybb->config['database']['table_prefix']}attachtypes_atid_seq', (SELECT max(atid) FROM {$mybb->config['database']['table_prefix']}attachtypes));"); + $db->query("SELECT setval('{$mybb->config['database']['table_prefix']}forums_fid_seq', (SELECT max(fid) FROM {$mybb->config['database']['table_prefix']}forums));"); + $db->query("SELECT setval('{$mybb->config['database']['table_prefix']}helpdocs_hid_seq', (SELECT max(hid) FROM {$mybb->config['database']['table_prefix']}helpdocs));"); + $db->query("SELECT setval('{$mybb->config['database']['table_prefix']}helpsections_sid_seq', (SELECT max(sid) FROM {$mybb->config['database']['table_prefix']}helpsections));"); + $db->query("SELECT setval('{$mybb->config['database']['table_prefix']}icons_iid_seq', (SELECT max(iid) FROM {$mybb->config['database']['table_prefix']}icons));"); + $db->query("SELECT setval('{$mybb->config['database']['table_prefix']}profilefields_fid_seq', (SELECT max(fid) FROM {$mybb->config['database']['table_prefix']}profilefields));"); + $db->query("SELECT setval('{$mybb->config['database']['table_prefix']}smilies_sid_seq', (SELECT max(sid) FROM {$mybb->config['database']['table_prefix']}smilies));"); + $db->query("SELECT setval('{$mybb->config['database']['table_prefix']}spiders_sid_seq', (SELECT max(sid) FROM {$mybb->config['database']['table_prefix']}spiders));"); + $db->query("SELECT setval('{$mybb->config['database']['table_prefix']}templategroups_gid_seq', (SELECT max(gid) FROM {$mybb->config['database']['table_prefix']}templategroups));"); + $db->query("SELECT setval('{$mybb->config['database']['table_prefix']}usergroups_gid_seq', (SELECT max(gid) FROM {$mybb->config['database']['table_prefix']}usergroups));"); + } + + $db->add_column("adminviews", "custom_profile_fields", "text NOT NULL AFTER conditions"); + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "); + $output->print_footer("20_done"); +} + diff --git a/Upload/install/resources/upgrade21.php b/Upload/install/resources/upgrade21.php new file mode 100644 index 0000000..a8af7c9 --- /dev/null +++ b/Upload/install/resources/upgrade21.php @@ -0,0 +1,104 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +function upgrade21_dbchanges() +{ + global $cache, $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + + $db->delete_query("settings", "name = 'standardheaders'"); + + if($db->field_exists('showinbirthdaylist', 'usergroups')) + { + $db->drop_column("usergroups", "showinbirthdaylist"); + } + + if($db->field_exists('canoverridepm', 'usergroups')) + { + $db->drop_column("usergroups", "canoverridepm"); + } + + if($db->field_exists('canusesig', 'usergroups')) + { + $db->drop_column("usergroups", "canusesig"); + } + + if($db->field_exists('canusesigxposts', 'usergroups')) + { + $db->drop_column("usergroups", "canusesigxposts"); + } + + if($db->field_exists('signofollow', 'usergroups')) + { + $db->drop_column("usergroups", "signofollow"); + } + + if($db->field_exists('postnum', 'profilefields')) + { + $db->drop_column("profilefields", "postnum"); + } + + switch($db->type) + { + case "pgsql": + case "sqlite": + $db->add_column("profilefields", "postnum", "bigint NOT NULL default '0'"); + $db->add_column("usergroups", "showinbirthdaylist", "int NOT NULL default '0'"); + $db->add_column("usergroups", "canoverridepm", "int NOT NULL default '0'"); + $db->add_column("usergroups", "canusesig", "int NOT NULL default '0'"); + $db->add_column("usergroups", "canusesigxposts", "bigint NOT NULL default '0'"); + $db->add_column("usergroups", "signofollow", "int NOT NULL default '0'"); + break; + default: + $db->add_column("profilefields", "postnum", "bigint(30) NOT NULL default '0'"); + $db->add_column("usergroups", "showinbirthdaylist", "int(1) NOT NULL default '0'"); + $db->add_column("usergroups", "canoverridepm", "int(1) NOT NULL default '0'"); + $db->add_column("usergroups", "canusesig", "int(1) NOT NULL default '0'"); + $db->add_column("usergroups", "canusesigxposts", "bigint(30) NOT NULL default '0'"); + $db->add_column("usergroups", "signofollow", "int(1) NOT NULL default '0'"); + break; + } + + // Update all usergroups to show in the birthday list + $db->update_query("usergroups", array("showinbirthdaylist" => 1)); + + // Update our nice usergroups to use a signature + $groups = $cache->read("usergroups"); + + foreach($groups as $group) + { + $disallowed_array = array(1, 5, 7); + if(in_array($group['gid'], $disallowed_array) || $group['isbannedgroup'] == 1) + { + continue; + } + + $db->update_query("usergroups", array("canusesig" => 1), "gid = '{$group['gid']}'"); + } + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "); + $output->print_footer("21_done"); +} + diff --git a/Upload/install/resources/upgrade22.php b/Upload/install/resources/upgrade22.php new file mode 100644 index 0000000..7ab55a5 --- /dev/null +++ b/Upload/install/resources/upgrade22.php @@ -0,0 +1,25 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +/* Nothing to do for 1.6.5 */ + diff --git a/Upload/install/resources/upgrade23.php b/Upload/install/resources/upgrade23.php new file mode 100644 index 0000000..8b9e0d3 --- /dev/null +++ b/Upload/install/resources/upgrade23.php @@ -0,0 +1,58 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +function upgrade23_dbchanges() +{ + global $db, $output; + + $output->print_header("Dokonywanie zmian w bazie danych"); + echo "

    Trwa dokonywanie wymaganych zmian w bazie danych.

    "; + + if($db->field_exists('canusecustomtools', 'moderators')) + { + $db->drop_column('moderators', 'canusecustomtools'); + } + + if($db->field_exists('cansendemailoverride', 'usergroups')) + { + $db->drop_column('usergroups', 'cansendemailoverride'); + } + + switch($db->type) + { + case "pgsql": + case "sqlite": + $db->add_column('moderators', 'canusecustomtools', "int NOT NULL default '0'"); + $db->add_column('usergroups', 'cansendemailoverride', "int NOT NULL default '0'"); + break; + default: + $db->add_column('moderators', 'canusecustomtools', "int(1) NOT NULL default '0'"); + $db->add_column('usergroups', 'cansendemailoverride', "int(1) NOT NULL default '0'"); + break; + } + + $db->update_query('moderators', array('canusecustomtools' => 1), "canmanagethreads = '1'"); + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "); + $output->print_footer("23_done"); +} diff --git a/Upload/install/resources/upgrade24.php b/Upload/install/resources/upgrade24.php new file mode 100644 index 0000000..f7b431c --- /dev/null +++ b/Upload/install/resources/upgrade24.php @@ -0,0 +1,23 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +/* Nothing to do for 1.6.7 */ diff --git a/Upload/install/resources/upgrade25.php b/Upload/install/resources/upgrade25.php new file mode 100644 index 0000000..e460bf5 --- /dev/null +++ b/Upload/install/resources/upgrade25.php @@ -0,0 +1,23 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +/* Nothing to do for 1.6.8 */ diff --git a/Upload/install/resources/upgrade26.php b/Upload/install/resources/upgrade26.php new file mode 100644 index 0000000..f9d598a --- /dev/null +++ b/Upload/install/resources/upgrade26.php @@ -0,0 +1,48 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +function upgrade26_dbchanges() +{ + global $db, $output; + + $output->print_header("Dokonywanie zmian w bazie danych"); + echo "

    Trwa dokonywanie wymaganych zmian w bazie danych.

    "; + + $db->update_query("helpdocs", array('usetranslation' => 1)); + $db->update_query("helpsections", array('usetranslation' => 1)); + + $db->modify_column("polls", "numvotes", "text NOT NULL"); + + if($db->field_exists('failedlogin', 'users')) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP failedlogin;"); + } + + // We don't need the posthash after the post is inserted into the database + $db->update_query('attachments', "posthash=''", 'pid!=0'); + + // Column will be dropped in MyBB 1.8 + $db->update_query('posts', "posthash=''"); + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "); + $output->print_footer("26_done"); +} diff --git a/Upload/install/resources/upgrade27.php b/Upload/install/resources/upgrade27.php new file mode 100644 index 0000000..60fc489 --- /dev/null +++ b/Upload/install/resources/upgrade27.php @@ -0,0 +1,24 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + + +/* Nothing to do for 1.6.10 */ diff --git a/Upload/install/resources/upgrade28.php b/Upload/install/resources/upgrade28.php new file mode 100644 index 0000000..ec98744 --- /dev/null +++ b/Upload/install/resources/upgrade28.php @@ -0,0 +1,23 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +/* Nothing to do for 1.6.11 or 1.6.12 */ diff --git a/Upload/install/resources/upgrade29.php b/Upload/install/resources/upgrade29.php new file mode 100644 index 0000000..179786c --- /dev/null +++ b/Upload/install/resources/upgrade29.php @@ -0,0 +1,24 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +/* Nothing to do for 1.6.13 */ + diff --git a/Upload/install/resources/upgrade3.php b/Upload/install/resources/upgrade3.php new file mode 100644 index 0000000..1221573 --- /dev/null +++ b/Upload/install/resources/upgrade3.php @@ -0,0 +1,826 @@ + 1, + "revert_all_themes" => 1, + "revert_all_settings" => 1, + "requires_deactivated_plugins" => 1, +); + +@set_time_limit(0); + +function upgrade3_dbchanges() +{ + global $db, $output; + + $output->print_header("Konwersja załączników na pliki"); + + $contents = "

    Pierwszym krokiem w aktualizacji z wersji RC4 jest przeniesienie załączników i awatarów do systemu plików.

    "; + + if(!@is_dir("../uploads/")) + { + $errors = "

    Katalog /uploads nie istnieje w katalogu, w którym znajduje się forum. Utwórz ten katalog przed kontynuowaniem."; + } + else + { + if(!@is_writable("../uploads/")) + { + @my_chmod("../uploads", '0777'); + if(!@is_writable("../uploads/")) + { + $errors = "

    Nie można zapisywać do katalogu /uploads. Sprawdź uprawnienia dla tego katalogu i spróbuj ponownie (CHMOD 766 lub 777)."; + } + } + } + if(!@is_dir("../uploads/avatars/")) + { + $errors .= "

    Katalog /uploads/avatars/ nie istnieje. Utwórz ten katalog przed kontynuowaniem."; + } + else + { + if(!@is_writable("../uploads/avatars/")) + { + @my_chmod("../uploads/avatars/", '0777'); + if(!is_writable("../uploads/avatars/")) + { + $errors = "

    Nie można zapisywać do katalogu /uploads/avatars. Sprawdź uprawnienia dla tego katalogu i spróbuj ponownie (CHMOD 766 lub 777)."; + } + } + } + + if($errors) + { + $output->print_contents($contents."

    Aby wykonać ten krok musisz naprawić poniższe błędy:

    $errors"); + $output->print_footer("3_dbchanges"); + exit; + } + + $contents .= "

    Wymagania co do folderów zostały spełnione.

    Jeżeli chcesz zmienić liczbę załączników do przetworzenia na stronę, możesz to zrobić poniżej.

    "; + $contents .= "

    Ilość wpisów na stronę:

    "; + $contents .= "

    Aby rozpocząć konwersję naciśnij dalej.

    "; + + $output->print_contents($contents); + $output->print_footer("3_convertattachments"); +} + +function upgrade3_convertattachments() +{ + global $db, $output; + + $output->print_header("Konwersja załączników na pliki"); + + if(!$_POST['attachmentspage']) + { + $app = 50; + } + else + { + $app = $_POST['attachmentspage']; + } + + if($_POST['attachmentstart']) + { + $startat = $_POST['attachmentstart']; + $upper = $startat+$app; + $lower = $startat; + } + else + { + $startat = 0; + $upper = $app; + $lower = 1; + } + + require_once MYBB_ROOT."inc/settings.php"; + + $query = $db->simple_select("attachments", "COUNT(aid) AS attachcount"); + $cnt = $db->fetch_array($query); + + $contents .= "

    Konwersja zaÅ‚Ä…czników z $lower do $upper (ÅÄ…cznie: ".$cnt['attachcount'].")

    "; + echo "

    Konwersja zaÅ‚Ä…czników z $lower do $upper (ÅÄ…cznie: ".$cnt['attachcount'].")

    "; + + if($db->field_exists("uid", TABLE_PREFIX."attachments")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments DROP uid;"); + } + // Add uid column + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments ADD uid smallint(6) NOT NULL AFTER posthash;"); + + + if($db->field_exists("thumbnail", TABLE_PREFIX."attachments")) + { + // Drop thumbnail column + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments DROP thumbnail"); + } + + if($db->field_exists("thumbnail", TABLE_PREFIX."attachments")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments DROP thumbnail;"); + } + // Add thumbnail column + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments ADD thumbnail varchar(120) NOT NULL;"); + + if($db->field_exists("attachname", TABLE_PREFIX."attachments")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments DROP attachname;"); + } + // Add attachname column + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments ADD attachname varchar(120) NOT NULL AFTER filesize;"); + + if(!$db->field_exists("donecon", TABLE_PREFIX."attachments")) + { + // Add temporary column + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments ADD donecon smallint(1) NOT NULL;"); + } + + $query = $db->query(" + SELECT a.*, p.uid AS puid, p.dateline + FROM ".TABLE_PREFIX."attachments a + LEFT JOIN ".TABLE_PREFIX."posts p ON (p.pid=a.pid) + WHERE a.donecon != '1' + ORDER BY a.aid ASC LIMIT {$app} + "); + while($attachment = $db->fetch_array($query)) + { + $filename = "post_".$attachment['puid']."_".$attachment['dateline'].$attachment['aid'].".attach"; + $ext = my_strtolower(my_substr(strrchr($attachment['filename'], "."), 1)); + $fp = fopen("../uploads/".$filename, "wb"); + if(!$fp) + { + die("Nie można utworzyć pliku. Sprawdź uprawnienia i odśwież stronę."); + } + fwrite($fp, $attachment['filedata']); + fclose($fp); + unset($attachment['filedata']); + if($ext == "gif" || $ext == "png" || $ext == "jpg" || $ext == "jpeg" || $ext == "jpe") + { + require_once MYBB_ROOT."inc/functions_image.php"; + $thumbname = str_replace(".attach", "_thumb.$ext", $filename); + $thumbnail = generate_thumbnail("../uploads/".$filename, "../uploads", $thumbname, $settings['attachthumbh'], $settings['attachthumbw']); + if($thumbnail['code'] == 4) + { + // Image was too small - fake a filename + $thumbnail['filename'] = "SMALL"; + } + } + $db->write_query("UPDATE ".TABLE_PREFIX."attachments SET attachname='".$filename."', donecon='1', uid='".$attachment['puid']."', thumbnail='".$thumbnail['filename']."' WHERE aid='".$attachment['aid']."'"); + unset($thumbnail); + } + + echo "

    Zakończono.

    "; + $query = $db->simple_select("attachments", "COUNT(aid) AS attachrem", "donecon != '1'"); + $cnt = $db->fetch_array($query); + + if($cnt['attachrem'] != 0) + { + $nextact = "3_convertattachments"; + $startat = $startat+$app; + $contents .= "

    Done. Click Next to move on to the next set of attachments.

    "; + } + else + { + if($db->field_exists("donecon", TABLE_PREFIX."attachments")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments DROP donecon"); + } + + if($db->field_exists("filedata", TABLE_PREFIX."attachments")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments DROP filedata"); + } + + if($db->field_exists("thumbnailsm", TABLE_PREFIX."attachments")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments DROP thumbnailsm"); + } + $nextact = "3_convertavatars"; + $contents .= "

    Zakończono

    Wszystkie załączniki zostały zamienione na pliki. W następnym kroku tej operacji zostaną poddane awatary.

    "; + $contents .= "

    Jeżeli chcesz zmienić liczbę awatarów do przetworzenia na stronę, możesz to zrobić poniżej.

    "; + $contents .= "

    Ilość wpisów na stronę:

    "; + $contents .= "

    Aby rozpocząć proces konwersji, naciśnij dalej.

    "; + } + $output->print_contents($contents); + $output->print_footer($nextact); +} + +function upgrade3_convertavatars() +{ + global $db, $output; + + $output->print_header("Konwersja awatarów na pliki"); + + if(!$_POST['userspage']) + { + $app = 50; + } + else + { + $app = $_POST['userspage']; + } + + if($_POST['avatarstart']) + { + $startat = $_POST['avatarstart']; + $upper = $startat+$app; + $lower = $startat; + } + else + { + $startat = 0; + $upper = $app; + $lower = 1; + } + + require_once MYBB_ROOT."inc/settings.php"; + + $query = $db->simple_select("avatars", "COUNT(uid) AS avatarcount"); + $cnt = $db->fetch_array($query); + + $contents .= "

    Konwersja awatarów z $lower do $upper (ÅÄ…cznie ".$cnt['avatarcount'].")

    "; + + // Add temporary column + if(!$db->field_exists("donecon", TABLE_PREFIX."avatars")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."avatars ADD donecon smallint(1) NOT NULL;"); + } + + if($db->field_exists("avatartype", TABLE_PREFIX."attachments")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments DROP avatartype;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD avatartype varchar(10) NOT NULL AFTER avatar;"); + + $query = $db->simple_select("avatars", "*", "donecon != '1'", array('order_by' => 'uid', 'order_dir' => 'asc', 'limit' => $app)); + while($avatar = $db->fetch_array($query)) + { + $ext = ""; + switch($avatar['type']) + { + case "image/jpeg": + case "image/jpg": + case "image/pjpeg": + $ext = "jpg"; + break; + case "image/x-png": + case "image/png": + $ext = "png"; + break; + case "image/gif": + $ext = "gif"; + break; + } + + if($ext) + { + $filename = "avatar_".$avatar['uid'].".".$ext; + $fp = @fopen("../uploads/avatars/".$filename, "wb"); + if(!$fp) + { + die("Nie można utowrzyć pliku. Sprawdź uprawnienia i odśwież stronę."); + } + fwrite($fp, $avatar['avatar']); + fclose($fp); + $db->write_query("UPDATE ".TABLE_PREFIX."avatars SET donecon='1' WHERE uid='".$avatar['uid']."'"); + $db->write_query("UPDATE ".TABLE_PREFIX."users SET avatar='uploads/avatars/$filename', avatartype='upload' WHERE uid='".$avatar['uid']."'"); + } + } + + echo "

    Zakończono.

    "; + $query = $db->simple_select("avatars", "COUNT(uid) AS avatarsrem", "donecon!='1'"); + $cnt = $db->fetch_array($query); + + if($cnt['avatarsrem'] != 0) + { + $nextact = "3_convertavatars"; + $startat = $startat+$app; + $contents .= "

    Done. Click Next to move on to the next set of avatars.

    "; + } + else + { + $db->drop_table("avatars"); + $nextact = "3_dbchanges2"; + $contents .= "

    Zakończono

    Wszystkie awatary zostały skonwertowane na pliki. W następnym kroku zostaną wykonane wymagane zapytania do bazy danych.

    "; + } + $output->print_contents($contents); + $output->print_footer($nextact); +} + +function upgrade3_dbchanges2() +{ + global $db, $output; + + $output->print_header("Dokonywanie zmian w bazie danych"); + + $contents = "

    Trwa dokonywanie wymaganych zmian w bazie danych.

    "; + + if($db->field_exists("additionalgroups", TABLE_PREFIX."users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP additionalgroups;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD additionalgroups varchar(200) NOT NULL default '' AFTER usergroup;"); + + if($db->field_exists("displaygroup", TABLE_PREFIX."users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP displaygroup;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD displaygroup smallint(6) NOT NULL default '0' AFTER additionalgroups;"); + + if($db->field_exists("candisplaygroup", TABLE_PREFIX."usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP candisplaygroup;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups ADD candisplaygroup varchar(3) NOT NULL;"); + + if(!$db->field_exists("reason", TABLE_PREFIX."banned")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."banned DROP reason;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."banned ADD reason varchar(200) NOT NULL"); + + if($db->field_exists("rulestype", TABLE_PREFIX."forums")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums DROP rulestype;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums ADD rulestype smallint(1) NOT NULL;"); + + if($db->field_exists("rulestitle", TABLE_PREFIX."forums")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums DROP rulestitle;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums ADD rulestitle varchar(200) NOT NULL;"); + + if($db->field_exists("rules", TABLE_PREFIX."forums")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums DROP rules;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums ADD rules text NOT NULL;"); + + if($db->field_exists("usetranslation", TABLE_PREFIX."helpdocs")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums DROP helpdocs;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."helpdocs ADD usetranslation CHAR( 3 ) NOT NULL AFTER document;"); + + if($db->field_exists("enabled", TABLE_PREFIX."helpdocs")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."helpdocs DROP enabled;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."helpdocs ADD enabled CHAR( 3 ) NOT NULL AFTER usetranslation;"); + + /* + + This will break the upgrade for users who have customised help documents + + $db->write_query("UPDATE ".TABLE_PREFIX."helpdocs SET hid='6' WHERE hid='7'"); + $db->write_query("UPDATE ".TABLE_PREFIX."helpdocs SET hid='7' WHERE hid='8'");*/ + + if($db->field_exists("usetranslation", TABLE_PREFIX."helpsections")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."helpsections DROP usetranslation;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."helpsections ADD usetranslation CHAR( 3 ) NOT NULL AFTER description;"); + + if($db->field_exists("enabled", TABLE_PREFIX."helpsections")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."helpsections DROP enabled;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."helpsections ADD enabled CHAR( 3 ) NOT NULL AFTER usetranslation;"); + + if($db->field_exists("firstpost", TABLE_PREFIX."threads")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads DROP firstpost;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads ADD firstpost int unsigned NOT NULL default '0' AFTER dateline;"); + + if($db->field_exists("attachquota", TABLE_PREFIX."usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups DROP attachquota;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups ADD attachquota bigint(30) NOT NULL default '0';"); + + if($db->field_exists("cancustomtitle", TABLE_PREFIX."usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups DROP cancustomtitle;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups ADD cancustomtitle varchar(3) NOT NULL;"); + + + $db->drop_table("groupleaders"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."groupleaders ( + lid smallint(6) NOT NULL auto_increment, + gid smallint(6) NOT NULL, + uid smallint(6) NOT NULL, + PRIMARY KEY(lid) + );"); + + $db->drop_table("joinrequests"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."joinrequests ( + rid smallint(6) NOT NULL auto_increment, + uid smallint(6) NOT NULL, + gid smallint(6) NOT NULL, + reason varchar(250) NOT NULL, + dateline bigint(30) NOT NULL, + PRIMARY KEY(rid) + );"); + + $db->drop_table("online"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."sessions ( + sid varchar(32) NOT NULL default '', + uid int unsigned NOT NULL default '0', + ip varchar(40) NOT NULL default '', + time bigint(30) NOT NULL default '0', + location varchar(150) NOT NULL default '', + useragent varchar(100) NOT NULL default '', + anonymous int(1) NOT NULL default '0', + nopermission int(1) NOT NULL default '0', + location1 int(10) NOT NULL default '0', + location2 int(10) NOT NULL default '0', + PRIMARY KEY(sid), + KEY location1 (location1), + KEY location2 (location2) + );"); + + if($db->field_exists("salt", TABLE_PREFIX."users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP salt;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD salt varchar(10) NOT NULL AFTER password;"); + + + if($db->field_exists("loginkey", TABLE_PREFIX."users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP loginkey;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD loginkey varchar(50) NOT NULL AFTER salt;"); + + + if($db->field_exists("pmnotify", TABLE_PREFIX."users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP pmnotify;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD pmnotify varchar(3) NOT NULL AFTER pmpopup;"); + + $collation = $db->build_create_table_collation(); + + $db->drop_table("settinggroups"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."settinggroups ( + gid smallint(6) NOT NULL auto_increment, + name varchar(220) NOT NULL default '', + description text NOT NULL, + disporder smallint(6) NOT NULL default '0', + isdefault char(3) NOT NULL default '', + PRIMARY KEY (gid) + ) ENGINE=MyISAM{$collation};"); + + $db->drop_table("settings"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."settings ( + sid smallint(6) NOT NULL auto_increment, + name varchar(120) NOT NULL default '', + title varchar(120) NOT NULL default '', + description text NOT NULL, + optionscode text NOT NULL, + value text NOT NULL, + disporder smallint(6) NOT NULL default '0', + gid smallint(6) NOT NULL default '0', + PRIMARY KEY (sid) + ) ENGINE=MyISAM{$collation};"); + + $db->drop_table("datacache"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."datacache ( + title varchar(30) NOT NULL default '', + cache mediumtext NOT NULL, + PRIMARY KEY(title) + ) ENGINE=MyISAM{$collation};"); + + $contents .= "

    Zakończono

    "; + $contents .= "

    Ponowne tworzenie ustawień..."; + + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (1, 'General Configuration', 'This section contains various settings such as your board name and url, as well as your website name and url.', 2, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (3, 'Date and Time Formats', 'Here you can specify the different date and time formats used to display dates and times on the forums.', 4, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (7, 'Forum Display Options', 'This section allows you to manage the various settings used on the forum fisplay (forumdisplay.php) of your boards such as enabling and disabling different features.', 6, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (8, 'Show Thread Options', 'This section allows you to manage the various settings used on the thread display page (showthread.php) of your boards such as enabling and disabling different features.', 7, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (11, 'Private Messaging', 'Various options with relation to the MyBB Private Messaging system (private.php) can be managed and set here.', 11, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (12, 'Member List', 'This section allows you to control various aspects of the board member listing (memberlist.php), such as how many members to show per page, and which features to enable or disable.', 10, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (13, 'Posting', 'These options control the various elements in relation to posting messages on the forums.', 9, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (14, 'Banning Options', '', 15, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (16, 'Forum Home Options', 'This section allows you to manage the various settings used on the forum home (index.php) of your boards such as enabling and disabling different features.', 5, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (17, 'Calendar', 'The board calendar allows the public and private listing of events and members'' birthdays. This section allows you to control and manage the settings for the Calendar.', 12, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (27, 'Server and Optimization Options', 'These options allow you to set various server and optimization preferences allowing you to reduce the load on your server, and gain better performance on your board.', 3, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (19, 'User Registration and Profile Options', 'Here you can control various settings with relation to user account registration and account management.', 8, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (20, 'Clickable Smilies and BB Code', '', 17, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (23, 'Who''s Online', '', 13, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (26, 'Board Online / Offline', 'These settings allow you to globally turn your forums online or offline, and allow you to specify a reason for turning them off.', 1, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (28, 'Control Panel Preferences (Global)', '', 19, 'yes');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settinggroups (gid, name, description, disporder, isdefault) VALUES (30, 'Portal Settings', '', 14, 'yes');"); + + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'boardclosed', 'Board Closed', 'If you need to close your forums to make some changes or perform an upgrade, this is the global switch. Viewers will not be able to view your forums, however, they will see a message with the reason you specify below.
    \r\n
    \r\nAdministrators will still be able to view the forums.', 'yesno', 'no', 1, 26);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'boardclosed_reason', 'Board Closed Reason', 'If your forum is closed, you can set a message here that your visitors will be able to see when they visit your forums.', 'textarea', 'These forums are currently closed for maintenance. Please check back later.', 2, 26);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'bbname', 'Board Name', 'The name of your message boards. We recommend that it is not over 75 characters.', 'text', 'Your Forums', 1, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'bburl', 'Board URL', 'The url to your forums.
    Include the http://. Do NOT include a trailing slash.', 'text', 'http://', 2, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'homename', 'Homepage Name', 'The name of your homepage. This will appear in the footer with a link to it.', 'text', 'Your Website', 3, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'homeurl', 'Homepage URL', 'The full URL of your homepage. This will be linked to in the footer along with its name.', 'text', 'http://', 4, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'dateformat', 'Date Format', 'The format of the dates used on the forum. This format uses the PHP date() function. We recommend not changing this unless you know what you''re doing.', 'text', 'm-d-Y', 1, 3);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'adminemail', 'Admin Email', 'The administrator''s email address. This will be used for outgoing emails sent via the forums.', 'text', 'root@localhost', 5, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'timeformat', 'Time Format', 'The format of the times used on the forum. This format uses PHP''s date() function. We recommend not changing this unless you know what you''re doing.', 'text', 'h:i A', 2, 3);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'threadsperpage', 'Threads Per Page', '', 'text', '20', 1, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'hottopic', 'Replys For Hot Topic', 'The number of replies that is needed for a topic to be considered ''hot''.', 'text', '20', 3, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'cookiedomain', 'Cookie Domain', 'The domain which cookies should be set to. This can remain blank. It should also start with a . so it covers all subdomains.', 'text', '', 8, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'cookiepath', 'Cookie Path', 'The path which cookies are set to, we recommend setting this to the full directory path to your forums with a trailing slash.', 'text', '', 9, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'postsperpage', 'Posts Per Page:', 'The number of posts to display per page. We recommend its not higher than 20 for people with slower connections.', 'text', '10', 1, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'regdateformat', 'Registered Date Format', 'The format used on showthread where it shows when the user registered.', 'text', 'M Y', 3, 3);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'sigmycode', 'Allow MyCode in Signatures', 'Do you want to allow MyCode to be used in users'' signatures?', 'yesno', 'yes', 1, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'sigsmilies', 'Allow Smilies in Signatures', 'Do you want to allow smilies to be used in users'' signatures?', 'yesno', 'yes', 3, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'sightml', 'Allow HTML in Signatures', 'Do you want to allow HTML to be used in users'' signatures?', 'yesno', 'no', 4, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'sigimgcode', 'Allow [img] Code in Signatures', 'Do you want to allow [img] code to be used in users'' signatures?', 'yesno', 'yes', 5, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'threadusenetstyle', 'Usenet Style Thread View', 'Selecting yes will cause posts to look similar to how posts look in USENET. No will cause posts to look the modern way.', 'yesno', 'no', 4, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'pmsallowhtml', 'Allow HTML', 'Selecting yes will allow HTML to be used in private messages.', 'yesno', 'no', 1, 11);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'pmsallowmycode', 'Allow MyCode', 'Selecting yes will allow MyCode to be used in private messages.', 'yesno', 'yes', 2, 11);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'pmsallowsmilies', 'Allow Smilies', 'Selecting yes will allow Smilies to be used in private messages.', 'yesno', 'yes', 3, 11);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'pmsallowimgcode', 'Allow [img] Code', 'Selecting yes will allow [img] Code to be used in private messages.', 'yesno', 'yes', 4, 11);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'siglength', 'Length limit in Signatures', 'The maximum number of characters a user can place in a signature.', 'text', '255', 6, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'messagelength', 'Maximum Message Length', 'The maximum number of characters to allow in a message. A setting of 0 allows an unlimited length.', 'text', '0', 1, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'membersperpage', 'Members Per Page', 'The number of members to show per page on the member list.', 'text', '20', 1, 12);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'load', '*NIX Load Limiting', 'Limit the maximum server load before myBB rejects people. 0 for none. Recommended limit is 5.0.', 'text', '0', 5, 27);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'emailkeep', 'Users Keep Email', 'If a current user has an email already registered in your banned list, should he be allowed to keep it.', 'yesno', 'no', 4, 14);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'ipban', 'Ban by IP', 'Here, you may specify IP addresses or a range of IP addresses. You must separate each IP with a space.', 'textarea', '', 2, 14);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'emailban', 'Ban by Email', 'You may specify specific email addresses to ban, or you may specify a domain. You must separate email addresses and domains with a space.', 'textarea', '', 3, 14);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'avatarsize', 'Max Uploaded Avatar Size', 'Maximum file size (in kilobytes) of uploaded avatars.', 'text', '10', 8, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'avatardir', 'Avatar Directory', 'The directory where your avatars are stored. These are used in the avatar list in the User CP.', 'text', 'images/avatars', 7, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showeditedby', 'Show ''edited by'' Messages', 'Once a post is edited by a regular user, do you want to show the edited by message?', 'yesno', 'yes', 6, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxposts', 'Maximum Posts Per Day', 'This is the total number of posts allowed per user per day. 0 for unlimited.', 'text', '0', 2, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showeditedbyadmin', 'Show ''edited by'' Message for Forum Staff', 'Do you want to show edited by messages for forum staff when they edit their posts?', 'yesno', 'yes', 7, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'bannedusernames', 'Banned Usernames', 'Ban users from registering certain usernames. Seperate them with a space.', 'textarea', '', 1, 14);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxpolloptions', 'Maximum Number of Poll Options', 'The maximum number of options for polls that users can post.', 'text', '10', 3, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'dotfolders', 'Use ''dot'' Icons', 'Do you want to show dots on the thread indicators of threads users have participated in.', 'yesno', 'yes', 8, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'contactlink', 'Contact Us Link', 'This will be used for the Contact Us link on the bottom of all the forum pages. Can either be an email address (using mailto:email@website.com) or a hyperlink.', 'text', '#', 6, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showdescriptions', 'Show Forum Descriptions?', 'This option will allow you to turn off showing the descriptions for forums.', 'yesno', 'yes', 1, 16);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showbirthdays', 'Show Today''s Birthdays?', 'Do you want to show today''s birthdays on the forum homepage?', 'yesno', 'yes', 2, 16);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showwol', 'Show Who''s Online?', 'Display the currently active users on the forum home page.', 'yesno', 'yes', 4, 16);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'hideprivateforums', 'Hide Private Forums?', 'You can hide private forums by turning this option on. This option also hides forums on the forum jump and all subforums.', 'yesno', 'yes', 3, 16);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showsimilarthreads', 'Show ''Similar Threads'' Table', 'The Similar Threads table shows threads that are relevant to the thread being read. You can set the relevancy below.', 'yesno', 'no', 5, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'similarityrating', 'Similar Threads Relevancy Rating', 'This allows you to limit similar threads to ones more relevant (0 being not relevant). This number should not be over 10 and should not be set low (<5) for large forums.', 'text', '1', 7, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'similarlimit', 'Similar Threads Limit', 'Here you can change the total amount of similar threads to be shown in the similar threads table. It is recommended that it is not over 15 for 56k users.', 'text', '10', 8, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'privateeventcolor', 'Private Events Color', 'The color that private events will be shown in on the main calendar page.', 'text', 'red', 2, 17);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'publiceventcolor', 'Public Events Color', 'The color that public events will be shown in on the main calendar page.', 'text', 'green', 1, 17);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'hottopicviews', 'Views For Hot Topic', 'The number of views a thread can have before it is considered ''hot''.', 'text', '150', 7, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'logip', 'Log Posting IP Addresses', 'Do you wish to log ip addresses of users who post, and who you want to show ip addresses to.', 'radio\r\nno=Do not log IP\r\nhide=Show to Admins & Mods\r\nshow=Show to all Users', 'hide', 3, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'statslimit', 'Stats Limit', 'The number of threads to show on the stats page for most replies and most views.', 'text', '15', 10, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'modlist', 'Forums'' Moderator Listing', 'Here you can turn on or off the listing of moderators for each forum on index.php and forumdisplay.php', 'onoff', 'on', 5, 16);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'smilieinserter', 'Clickable Smilies Inserter', 'Clickable smilies will appear on the posting pages if this option is set to ''on''.', 'onoff', 'on', 1, 20);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'smilieinsertertot', 'No. of Smilies to show', 'Enter the total number of smilies to show on the clickable smilie inserter.', 'text', '20', 2, 20);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'smilieinsertercols', 'No. of Smilie Cols to Show', 'Enter the number of columns you wish to show on the clickable smilie inserter.', 'text', '4', 3, 20);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showindexstats', 'Show Small Stats Section', 'Do you want to show the total number of threads, posts, members, and the last member on the forum home?', 'yesno', 'yes', 6, 16);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'regtype', 'Registration Method', 'Please select the method of registration to use when users register.', 'select\r\ninstant=Instant Activation\r\nverify=Send Email Verification\r\nrandompass=Send Random Password\r\nadmin=Administrator Activation', 'verify', 1, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'userpppoptions', 'User Selectable Posts Per Page', 'If you would like to allow users to select how many posts are shown per page in a thread, enter the options they should be able to select separated with commas. If this is left blank they will not be able to choose how many posts are shown per page.', 'text', '5,10,20,25,30,40,50', 2, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'usertppoptions', 'User Selectable Threads Per Page', 'If you would like to allow users to select how many threads per page are shown in a forum, enter the options they should be able to select separated with commas. If this is left blank they will not be able to choose how many threads are shown per page.', 'text', '10,20,25,30,40,50', 6, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'wolcutoffmins', 'Cut-off Time (mins)', 'The number of minutes before a user is marked offline. Recommended: 15.', 'text', '15', 1, 23);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'postfloodcheck', 'Post Flood Checking', 'Set to on if you want to enable flood checking for posts. Specifiy the time between posts below.', 'onoff', 'on', 4, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'postfloodsecs', 'Post Flood Time', 'Set the time (in seconds) users have to wait between posting, to be in effect; the option above must be on.', 'text', '60', 5, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'gzipoutput', 'Use GZip Page Compression?', 'Do you want to compress pages in GZip format when they are sent to the browser? This means quicker downloads for your visitors, and less traffic usage for you. The level of the compression is set by the server''s load.', 'yesno', 'yes', 1, 27);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'standardheaders', 'Send Standard Headers', 'With some web servers, this option can cause problems; with others, it is needed. ', 'yesno', 'no', 2, 27);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'nocacheheaders', 'Send No Cache Headers', 'With this option you can prevent caching of the page by the browser.', 'yesno', 'no', 3, 27);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxpostimages', 'Maximum Images per Post', 'Enter the maximum number of images (including smilies) a user can put in their post. Set to 0 to disable this.', 'text', '10', 8, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxsigimages', 'Maximum Number of Images per Signature', 'Enter the maximum number of images (including smilies) a user can put in their signature. Set to 0 to disable this.', 'text', '2', 2, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'browsingthisforum', 'Users Browsing this Forum', 'Here you can turn off the ''users browsing this forum'' feature.', 'onoff', 'on', 9, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'usereferrals', 'Use Referrals System', 'Do you want to use the user referrals system on these forums?', 'yesno', 'yes', 3, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'subscribeexcerpt', 'Amount of Characters for Subscription Previews', 'How many characters of the post do you want to send with the email notification of a new reply.', 'text', '100', 9, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'cpstyle', 'Control Panel Style', 'The Default style that the control panel will use. Styles are inside the styles folder. A folder name inside that folder becomes the style title and style.css inside the style title folder is the css style file.', 'cpstyle', 'Axiom', 2, 28);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'cplanguage', 'Control Panel Language', 'The language of the control panel.', 'adminlanguage', 'english', 1, 28);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'minnamelength', 'Minimum Username Length', 'The minimum number of characters a username can be when a user registers.', 'text', '3', 5, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxnamelength', 'Maximum Username Length', 'The maximum number of characters a username can be when a user registers.', 'text', '30', 6, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'redirects', 'Friendly Redirection Pages', 'This will enable friendly redirection pages instead of bumping the user directly to the page.', 'onoff', 'on', 4, 27);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'betweenregstime', 'Time Between Registrations', 'The amount of time (in hours) to disallow registrations for users who have already registered an account under the same ip address.', 'text', '24', 2, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxregsbetweentime', 'Maximum Registrations Per IP Address', 'This option allows you to set the maximum amount of times a certain user can register within the timeframe specified above.', 'text', '2', 4, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showstats', 'Show forum statistics', 'Do you want to show the total number of posts, threads, members and the last registered member on the portal page?', 'yesno', 'yes', 5, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showpms', 'Show the number of PMs to users', 'Do you want to show the number of private messages the current user has in their pm system.', 'yesno', 'yes', 4, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showwelcome', 'Show the Welcome box', 'Do you want to show the welcome box to visitors / users.', 'yesno', 'yes', 3, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_numannouncements', 'Number of announcements to show', 'Please enter the number of announcements to show on the main page.', 'text', '10', 2, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showstats', 'Show forum statistics', 'Do you want to show the total number of posts, threads, members and the last registered member on the portal page?', 'yesno', 'yes', 5, 29);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showwol', 'Show Whos Online', 'Do you want to show the ''whos online'' information to users when they visit the portal page?', 'yesno', 'yes', 6, 29);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_announcementsfid', 'Forum ID to pull announcements from', 'Please enter the forum id (fid) of the forum you wish to pull the announcements from', 'text', '1', 1, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showdiscussionsnum', 'Number of latest discussions to show', 'Please enter the number of current forum discussions to show on the portal page.', 'text', '10', 8, 29);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showwol', 'Show Who''s Online', 'Do you want to show the ''Who''s online'' information to users when they visit the portal page?', 'yesno', 'yes', 6, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showsearch', 'Show Search Box', 'Do you want to show the search box, allowing users to quickly search the forums on the portal?', 'yesno', 'yes', 7, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showdiscussions', 'Show Latest Discussions', 'Do you wish to show the current forum discussions on the portal page?', 'yesno', 'yes', 8, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'portal_showdiscussionsnum', 'Number of latest discussions to show', 'Please enter the number of current forum discussions to show on the portal page.', 'text', '10', 9, 30);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'attachthumbh', 'Attached Thumbnail Maximum Height', 'Enter the height that attached thumbnails should be generated at.', 'text', '60', 12, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'attachthumbw', 'Attached Thumbnail Maximum Width', 'Enter the width that attached thumbnails should be generated at.', 'text', '60', 13, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxattachments', 'Maximum Attachments Per Post', 'THe maximum number of attachments a user is allowed to upload per post.', 'text', '5', 10, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'attachthumbnails', 'Show Attached Thumbnails in Posts', 'Do you want to show the generated thumbnails for attached images inside the posts?', 'yesno', 'yes', 11, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'polloptionlimit', 'Maximum Option Length', 'The maximum length that each poll option can be. (Set to 0 to disable).', 'text', '250', 1, 13);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'timezoneoffset', 'Default Timezone Offset', 'Here you can set the default timezone offset for guests and members using the default offset.', 'text', '+10', 4, 3);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'bblanguage', 'Default Language', 'The default language that MyBB should use for guests and for users without a selected language in their user control panel.', 'language', 'english', 7, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'regimage', 'Antispam Registration Image', 'If yes, and GD is installed, an image will be shown during registration where users are required to enter the text contained within the image to continue with registration.', 'onoff', 'on', 1, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'reportmethod', 'Reported Posts Medium', 'Please select from the list how you want reported posts to be dealt with. Storing them in the database is probably the better of the options listed.', 'radio\r\ndb=Stored in the Database\r\npms=Sent as Private Messages\r\nemail=Sent via Email', 'db', 1, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'threadreadcut', 'Read Threads in Database (Days)', 'The number of days that you wish to keep thread read information in the database. For large boards, we do not recommend a high number as the board will become slower. Set to 0 to disable.', 'text', '7', 3, 8);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'announcementlimit', 'Announcements Limit', 'The number of forum announcements to show in the thread listing on the forum display pages. Set to 0 to show all active announcements.', 'text', '2', 10, 7);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'uploadspath', 'Uploads Path', 'The path used for all board uploads. It must be chmod 777 (on Unix servers).', 'text', './uploads', 1, 27);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'maxavatardims', 'Maximum Avatar Dimensions', 'The maximum dimensions that an avatar can be, in the format of widthxheight. If this is left blank then there will be no dimension restriction.', 'text', '10x10', 1, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'avataruploadpath', 'Avatar Upload Path', 'This is the path where custom avatars will be uploaded to. This directory must be chmod 777 (writable) for uploads to work.', 'text', './uploads/avatars', 1, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'subforumsindex', 'Subforums to show on Index listing', 'The number of subforums that you wish to show inside forums on the index and forumdisplay pages. Set to 0 to disable this', 'text', '2', 1, 16);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'disableregs', 'Disable Registrations', 'Allows you to turn off the capability for users to register with one click.', 'yesno', 'no', 9, 19);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'decpoint', 'Decimal Point', 'The decimal point you use in your region.', 'text', '.', 1, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'thousandssep', 'Thousands Numeric Separator', 'The punctuation you want to use . (for example, the setting \',\' with the number 1200 will give you a number such as 1,200)', 'text', ',', 1, 1);"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."settings (sid, name, title, description, optionscode, value, disporder, gid) VALUES (NULL, 'showvernum', 'Show Version Numbers', 'Allows you to turn off the public display of version numbers in MyBB.', 'onoff', 'off', 1, 1);"); + + echo "Zakończono

    "; + $output->print_contents($contents); + $output->print_footer("3_dbchanges3"); +} + +function upgrade3_dbchanges3() +{ + global $db, $output; + + $output->print_header("Zmiana rozmiaru pól w bazie danych"); + + $contents = "

    Trwa zmiana rozmiaru pól w bazie danych.

    "; + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminlog CHANGE uid uid int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminoptions CHANGE uid uid int(10) NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."announcements CHANGE aid aid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."announcements CHANGE fid fid int(10) NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."announcements CHANGE uid uid int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments CHANGE aid aid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments CHANGE uid uid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments CHANGE visible visible int(1) NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachments CHANGE downloads downloads int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachtypes CHANGE atid atid int unsigned NOT NULL auto_increment;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."awaitingactivation CHANGE aid aid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."awaitingactivation CHANGE uid uid int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."badwords CHANGE bid bid int unsigned NOT NULL auto_increment;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."banned CHANGE uid uid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."banned CHANGE gid gid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."banned CHANGE oldgroup oldgroup int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."banned CHANGE admin admin int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events CHANGE eid eid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."events CHANGE author author int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."favorites CHANGE fid fid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."favorites CHANGE uid uid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."favorites CHANGE tid tid int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forumpermissions CHANGE pid pid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forumpermissions CHANGE fid fid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forumpermissions CHANGE gid gid int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums CHANGE fid fid smallint unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums CHANGE pid pid smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums CHANGE disporder disporder smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums CHANGE threads threads int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums CHANGE posts posts int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums CHANGE style style smallint unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forumsubscriptions CHANGE fsid fsid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forumsubscriptions CHANGE fid fid smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forumsubscriptions CHANGE uid uid int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."groupleaders CHANGE lid lid smallint unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."groupleaders CHANGE gid gid smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."groupleaders CHANGE uid uid int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."helpdocs CHANGE hid hid smallint unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."helpdocs CHANGE sid sid smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."helpdocs CHANGE disporder disporder smallint unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."helpsections CHANGE sid sid smallint unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."helpsections CHANGE disporder disporder smallint unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."icons CHANGE iid iid smallint unsigned NOT NULL auto_increment;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."joinrequests CHANGE rid rid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."joinrequests CHANGE uid uid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."joinrequests CHANGE gid gid smallint unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."moderatorlog CHANGE uid uid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."moderatorlog CHANGE fid fid smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."moderatorlog CHANGE tid tid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."moderatorlog CHANGE pid pid int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."moderators CHANGE mid mid smallint unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."moderators CHANGE fid fid smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."moderators CHANGE uid uid int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."polls CHANGE pid pid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."polls CHANGE tid tid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."polls CHANGE numoptions numoptions smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."polls CHANGE numvotes numvotes smallint unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."pollvotes CHANGE vid vid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."pollvotes CHANGE pid pid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."pollvotes CHANGE uid uid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."pollvotes CHANGE voteoption voteoption smallint unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts CHANGE pid pid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts CHANGE tid tid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts CHANGE replyto replyto int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts CHANGE fid fid smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts CHANGE icon icon smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts CHANGE uid uid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts CHANGE edituid edituid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts CHANGE visible visible int(1) NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages CHANGE pmid pmid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages CHANGE uid uid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages CHANGE toid toid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages CHANGE fromid fromid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages CHANGE folder folder smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."privatemessages CHANGE icon icon smallint unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."profilefields CHANGE fid fid smallint unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."profilefields CHANGE disporder disporder smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."profilefields CHANGE length length smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."profilefields CHANGE maxlength maxlength smallint unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."reportedposts CHANGE rid rid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."reportedposts CHANGE pid pid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."reportedposts CHANGE tid tid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."reportedposts CHANGE fid fid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."reportedposts CHANGE uid uid int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."reputation CHANGE uid uid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."reputation CHANGE pid pid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."reputation CHANGE adduid adduid int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."searchlog CHANGE sid sid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."searchlog CHANGE uid uid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."searchlog CHANGE limitto limitto smallint(4) NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."settinggroups CHANGE gid gid smallint unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."settinggroups CHANGE disporder disporder smallint unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."settings CHANGE sid sid smallint unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."settings CHANGE disporder disporder smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."settings CHANGE gid gid smallint unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."smilies CHANGE sid sid smallint unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."smilies CHANGE disporder disporder smallint unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."templates CHANGE tid tid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."templates CHANGE sid sid int(10) NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."templatesets CHANGE sid sid smallint unsigned NOT NULL auto_increment;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes CHANGE tid tid smallint unsigned NOT NULL auto_increment;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threadratings CHANGE rid rid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threadratings CHANGE tid tid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threadratings CHANGE uid uid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threadratings CHANGE rating rating smallint unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads CHANGE tid tid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads CHANGE fid fid smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads CHANGE icon icon smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads CHANGE poll poll int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads CHANGE uid uid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads CHANGE replies replies int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads CHANGE views views int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads CHANGE sticky sticky int(1) NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads CHANGE numratings numratings smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads CHANGE totalratings totalratings smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads CHANGE visible visible int(1) NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threadsread CHANGE tid tid int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threadsread CHANGE uid uid int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."userfields CHANGE ufid ufid int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups CHANGE gid gid smallint unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups CHANGE stars stars smallint(4) NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users CHANGE uid uid int unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users CHANGE usergroup usergroup smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users CHANGE displaygroup displaygroup smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users CHANGE style style smallint unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users CHANGE referrer referrer int unsigned NOT NULL;"); + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usertitles CHANGE utid utid smallint unsigned NOT NULL auto_increment;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usertitles CHANGE posts posts int unsigned NOT NULL;"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usertitles CHANGE stars stars smallint(4) NOT NULL;"); + + echo "Zakończono

    "; + + $contents .= "OSTRZEŻENIE: W następnym kroku zostaną usunięte wszystkie style i szablony zainstalowane na Twoim forum! Przed rozpoczęciem wykonaj ich kopię zapasową.

    "; + $output->print_contents($contents); + $output->print_footer("3_done"); +} diff --git a/Upload/install/resources/upgrade30.php b/Upload/install/resources/upgrade30.php new file mode 100644 index 0000000..003ff91 --- /dev/null +++ b/Upload/install/resources/upgrade30.php @@ -0,0 +1,2508 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +function upgrade30_dbchanges() +{ + global $cache, $output, $mybb, $db; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + $db->update_query('settings', array('value' => -1), 'name IN (\'postmergefignore\', \'postmergeuignore\') AND value=\'\''); + $db->update_query('settings', array('optionscode' => 'forumselect'), 'name IN (\'postmergefignore\', \'portal_announcementsfid\') AND optionscode=\'text\''); + $db->update_query('settings', array('optionscode' => 'groupselect'), 'name=\'postmergeuignore\' AND optionscode=\'text\''); + + if($db->type == "mysql" || $db->type == "mysqli") + { + if($db->index_exists('posts', 'tiddate')) + { + $db->drop_index('posts', 'tiddate'); + } + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts ADD INDEX (`tid`, `dateline`)"); + } + + if($db->field_exists('modposts', 'usergroups')) + { + $db->drop_column("usergroups", "modposts"); + } + + if($db->field_exists('modthreads', 'usergroups')) + { + $db->drop_column("usergroups", "modthreads"); + } + + if($db->field_exists('mod_edit_posts', 'usergroups')) + { + $db->drop_column("usergroups", "mod_edit_posts"); + } + + if($db->field_exists('modattachments', 'usergroups')) + { + $db->drop_column("usergroups", "modattachments"); + } + + if($db->field_exists('regex', 'profilefields')) + { + $db->drop_column("profilefields", "regex"); + } + + if($db->field_exists('allowhtml', 'profilefields')) + { + $db->drop_column("profilefields", "allowhtml"); + } + + if($db->field_exists('allowmycode', 'profilefields')) + { + $db->drop_column("profilefields", "allowmycode"); + } + + if($db->field_exists('allowsmilies', 'profilefields')) + { + $db->drop_column("profilefields", "allowsmilies"); + } + + if($db->field_exists('allowimgcode', 'profilefields')) + { + $db->drop_column("profilefields", "allowimgcode"); + } + + if($db->field_exists('allowvideocode', 'profilefields')) + { + $db->drop_column("profilefields", "allowvideocode"); + } + + if($db->field_exists('viewableby', 'profilefields')) + { + $db->drop_column("profilefields", "viewableby"); + } + + if($db->field_exists('editable`', 'profilefields')) + { + $db->drop_column("profilefields", "editable"); + } + + if($db->field_exists('editableby', 'profilefields')) + { + $db->drop_column("profilefields", "editableby"); + } + + if($db->field_exists('oldgroup', 'awaitingactivation')) + { + $db->drop_column("awaitingactivation", "oldgroup"); + } + + if($db->field_exists('status', 'forums')) + { + $db->drop_column("forums", "status"); + } + + if($db->field_exists('posthash', 'posts')) + { + $db->drop_column("posts", "posthash"); + } + + if($db->field_exists('isdefault', 'templategroups')) + { + $db->drop_column("templategroups", "isdefault"); + } + + if($db->table_exists('reportedposts')) + { + if($db->field_exists('type', 'reportedposts')) + { + $db->drop_column("reportedposts", "type"); + } + + if($db->field_exists('reports', 'reportedposts')) + { + $db->drop_column("reportedposts", "reports"); + } + + if($db->field_exists('reporters', 'reportedposts')) + { + $db->drop_column("reportedposts", "reporters"); + } + + if($db->field_exists('lastreport', 'reportedposts')) + { + $db->drop_column("reportedposts", "lastreport"); + } + } + + if($db->field_exists('warnings', 'promotions')) + { + $db->drop_column("promotions", "warnings"); + } + + if($db->field_exists('warningstype', 'promotions')) + { + $db->drop_column("promotions", "warningstype"); + } + + if($db->field_exists('useragent', 'adminsessions')) + { + $db->drop_column("adminsessions", "useragent"); + } + + if($db->field_exists('deletedthreads', 'forums')) + { + $db->drop_column("forums", "deletedthreads"); + } + + if($db->field_exists('deletedposts', 'forums')) + { + $db->drop_column("forums", "deletedposts"); + } + + if($db->field_exists('threads', 'promotions')) + { + $db->drop_column('promotions', 'threads'); + } + + if($db->field_exists('threadtype', 'promotions')) + { + $db->drop_column('promotions', 'threadtype'); + } + + if($db->field_exists('online', 'promotions')) + { + $db->drop_column('promotions', 'online'); + } + + if($db->field_exists('onlinetype', 'promotions')) + { + $db->drop_column('promotions', 'onlinetype'); + } + + if($db->field_exists('modposts', 'forums')) + { + $db->drop_column("forums", "modposts"); + } + + if($db->field_exists('modthreads', 'forums')) + { + $db->drop_column("forums", "modthreads"); + } + + if($db->field_exists('mod_edit_posts', 'forums')) + { + $db->drop_column("forums", "mod_edit_posts"); + } + + if($db->field_exists('modattachments', 'forums')) + { + $db->drop_column("forums", "modattachments"); + } + + // Avoid complex convert coding... + if($db->field_exists('hidden', 'profilefields')) + { + $db->update_query('profilefields', array('hidden' => 2), 'hidden=1'); + $db->update_query('profilefields', array('hidden' => 1), 'hidden=0'); + $db->update_query('profilefields', array('hidden' => 0), 'hidden=2'); + + switch($db->type) + { + case "pgsql": + $db->rename_column("profilefields", "hidden", "profile", "smallint", "set", "'0'"); + break; + default: + $db->rename_column("profilefields", "hidden", "profile", "tinyint(1) NOT NULL default '0'"); + break; + } + } + + switch($db->type) + { + case "pgsql": + $db->add_column("usergroups", "modposts", "smallint NOT NULL default '0' AFTER canratethreads"); + $db->add_column("usergroups", "modthreads", "smallint NOT NULL default '0' AFTER modposts"); + $db->add_column("usergroups", "mod_edit_posts", "smallint NOT NULL default '0' AFTER modthreads"); + $db->add_column("usergroups", "modattachments", "smallint NOT NULL default '0' AFTER mod_edit_posts"); + $db->add_column("profilefields", "regex", "text NOT NULL default ''"); + $db->add_column("profilefields", "allowhtml", "smallint NOT NULL default '0'"); + $db->add_column("profilefields", "allowmycode", "smallint NOT NULL default '0'"); + $db->add_column("profilefields", "allowsmilies", "smallint NOT NULL default '0'"); + $db->add_column("profilefields", "allowimgcode", "smallint NOT NULL default '0'"); + $db->add_column("profilefields", "allowvideocode", "smallint NOT NULL default '0'"); + $db->add_column("profilefields", "viewableby", "text NOT NULL default ''"); + $db->add_column("profilefields", "editableby", "text NOT NULL default ''"); + $db->add_column("templategroups", "isdefault", "smallint NOT NULL default '0'"); + if($db->table_exists('reportedposts')) + { + $db->add_column("reportedposts", "type", "varchar(50) NOT NULL default ''"); + $db->add_column("reportedposts", "reports", "int NOT NULL default '0'"); + $db->add_column("reportedposts", "reporters", "text NOT NULL default ''"); + $db->add_column("reportedposts", "lastreport", "bigint NOT NULL default '0'"); + } + $db->add_column("promotions", "threads", "int NOT NULL default '0' AFTER posttype"); + $db->add_column("promotions", "threadtype", "varchar(2) NOT NULL default '' AFTER threads"); + $db->add_column("promotions", "warnings", "int NOT NULL default '0' AFTER referralstype"); + $db->add_column("promotions", "warningstype", "varchar(2) NOT NULL default '' AFTER warnings"); + $db->add_column("promotions", "online", "int NOT NULL default '0' AFTER warningstype"); + $db->add_column("promotions", "onlinetype", "varchar(20) NOT NULL default '' AFTER online"); + $db->add_column("adminsessions", "useragent", "varchar(100) NOT NULL default ''"); + $db->add_column("forums", "deletedthreads", "int NOT NULL default '0' AFTER unapprovedposts"); + $db->add_column("forums", "deletedposts", "int NOT NULL default '0' AFTER deletedthreads"); + break; + case "sqlite": + $db->add_column("usergroups", "modposts", "tinyint(1) NOT NULL default '0' AFTER canratethreads"); + $db->add_column("usergroups", "modthreads", "tinyint(1) NOT NULL default '0' AFTER modposts"); + $db->add_column("usergroups", "mod_edit_posts", "tinyint(1) NOT NULL default '0' AFTER modthreads"); + $db->add_column("usergroups", "modattachments", "tinyint(1) NOT NULL default '0' AFTER mod_edit_posts"); + $db->add_column("profilefields", "regex", "text NOT NULL default ''"); + $db->add_column("profilefields", "allowhtml", "tinyint(1) NOT NULL default '0'"); + $db->add_column("profilefields", "allowmycode", "tinyint(1) NOT NULL default '0'"); + $db->add_column("profilefields", "allowsmilies", "tinyint(1) NOT NULL default '0'"); + $db->add_column("profilefields", "allowimgcode", "tinyint(1) NOT NULL default '0'"); + $db->add_column("profilefields", "allowvideocode", "tinyint(1) NOT NULL default '0'"); + $db->add_column("profilefields", "viewableby", "text NOT NULL default ''"); + $db->add_column("profilefields", "editableby", "text NOT NULL default ''"); + $db->add_column("templategroups", "isdefault", "tinyint(1) NOT NULL default '0'"); + if($db->table_exists('reportedposts')) + { + $db->add_column("reportedposts", "type", "varchar(50) NOT NULL default ''"); + $db->add_column("reportedposts", "reports", "int NOT NULL default '0'"); + $db->add_column("reportedposts", "reporters", "text NOT NULL default ''"); + $db->add_column("reportedposts", "lastreport", "bigint NOT NULL default '0'"); + } + $db->add_column("promotions", "warnings", "int NOT NULL default '0' AFTER referralstype"); + $db->add_column("promotions", "warningstype", "varchar(2) NOT NULL default '' AFTER warnings"); + $db->add_column("adminsessions", "useragent", "varchar(100) NOT NULL default ''"); + $db->add_column("forums", "deletedthreads", "int NOT NULL default '0' AFTER unapprovedposts"); + $db->add_column("forums", "deletedposts", "int NOT NULL default '0' AFTER deletedthreads"); + break; + default: + $db->add_column("usergroups", "modposts", "tinyint(1) NOT NULL default '0' AFTER canratethreads"); + $db->add_column("usergroups", "modthreads", "tinyint(1) NOT NULL default '0' AFTER modposts"); + $db->add_column("usergroups", "mod_edit_posts", "tinyint(1) NOT NULL default '0' AFTER modthreads"); + $db->add_column("usergroups", "modattachments", "tinyint(1) NOT NULL default '0' AFTER mod_edit_posts"); + $db->add_column("profilefields", "regex", "text NOT NULL"); + $db->add_column("profilefields", "allowhtml", "tinyint(1) NOT NULL default '0'"); + $db->add_column("profilefields", "allowmycode", "tinyint(1) NOT NULL default '0'"); + $db->add_column("profilefields", "allowsmilies", "tinyint(1) NOT NULL default '0'"); + $db->add_column("profilefields", "allowimgcode", "tinyint(1) NOT NULL default '0'"); + $db->add_column("profilefields", "allowvideocode", "tinyint(1) NOT NULL default '0'"); + $db->add_column("profilefields", "viewableby", "text NOT NULL"); + $db->add_column("profilefields", "editableby", "text NOT NULL"); + $db->add_column("templategroups", "isdefault", "tinyint(1) NOT NULL default '0'"); + if($db->table_exists('reportedposts')) + { + $db->add_column("reportedposts", "type", "varchar(50) NOT NULL default ''"); + $db->add_column("reportedposts", "reports", "int unsigned NOT NULL default '0'"); + $db->add_column("reportedposts", "reporters", "text NOT NULL"); + $db->add_column("reportedposts", "lastreport", "bigint(30) NOT NULL default '0'"); + } + $db->add_column("promotions", "threads", "int NOT NULL default '0' AFTER posttype"); + $db->add_column("promotions", "threadtype", "char(2) NOT NULL default '' AFTER threads"); + $db->add_column("promotions", "warnings", "int NOT NULL default '0' AFTER referralstype"); + $db->add_column("promotions", "warningstype", "char(2) NOT NULL default '' AFTER warnings"); + $db->add_column("promotions", "online", "int NOT NULL default '0' AFTER warningstype"); + $db->add_column("promotions", "onlinetype", "varchar(20) NOT NULL default '' AFTER online"); + $db->add_column("adminsessions", "useragent", "varchar(100) NOT NULL default ''"); + $db->add_column("forums", "deletedthreads", "int(10) NOT NULL default '0' AFTER unapprovedposts"); + $db->add_column("forums", "deletedposts", "int(10) NOT NULL default '0' AFTER deletedthreads"); + break; + } + + $db->update_query('profilefields', array('viewableby' => '-1', 'editableby' => '-1')); + + global $footer_extra; + $footer_extra = ""; + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "); + $output->print_footer("30_dbchanges2"); +} + +function upgrade30_dbchanges2() +{ + global $cache, $output, $mybb, $db; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + if($db->field_exists('ipaddress', 'privatemessages')) + { + $db->drop_column('privatemessages', 'ipaddress'); + } + + if($db->field_exists('canonlyreplyownthreads', 'forumpermissions')) + { + $db->drop_column("forumpermissions", "canonlyreplyownthreads"); + } + + if($db->field_exists('modposts', 'forumpermissions')) + { + $db->drop_column("forumpermissions", "modposts"); + } + + if($db->field_exists('modthreads', 'forumpermissions')) + { + $db->drop_column("forumpermissions", "modthreads"); + } + + if($db->field_exists('mod_edit_posts', 'forumpermissions')) + { + $db->drop_column("forumpermissions", "mod_edit_posts"); + } + + if($db->field_exists('modattachments', 'forumpermissions')) + { + $db->drop_column("forumpermissions", "modattachments"); + } + + if($db->field_exists('canbereported', 'usergroups')) + { + $db->drop_column('usergroups', 'canbereported'); + } + + if($db->field_exists('edittimelimit', 'usergroups')) + { + $db->drop_column("usergroups", "edittimelimit"); + } + + if($db->field_exists('maxposts', 'usergroups')) + { + $db->drop_column("usergroups", "maxposts"); + } + + if($db->field_exists('showmemberlist', 'usergroups')) + { + $db->drop_column("usergroups", "showmemberlist"); + } + + if($db->field_exists('canviewboardclosed', 'usergroups')) + { + $db->drop_column("usergroups", "canviewboardclosed"); + } + + if($db->field_exists('deletedposts', 'threads')) + { + $db->drop_column("threads", "deletedposts"); + } + + if($db->field_exists('used', 'captcha')) + { + $db->drop_column("captcha", "used"); + } + + if($db->field_exists('editreason', 'posts')) + { + $db->drop_column("posts", "editreason"); + } + + if($db->field_exists('usethreadcounts', 'forums')) + { + $db->drop_column("forums", "usethreadcounts"); + } + + if($db->field_exists('requireprefix', 'forums')) + { + $db->drop_column("forums", "requireprefix"); + } + + if($db->field_exists('threadnum', 'users')) + { + $db->drop_column("users", "threadnum"); + } + + if($db->field_exists('canchangewebsite', 'usergroups')) + { + $db->drop_column("usergroups", "canchangewebsite"); + } + + switch($db->type) + { + case "pgsql": + $db->add_column("forumpermissions", "canonlyreplyownthreads", "smallint NOT NULL default '0' AFTER canpostreplys"); + $db->add_column("forumpermissions", "modposts", "smallint NOT NULL default '0' AFTER caneditattachments"); + $db->add_column("forumpermissions", "modthreads", "smallint NOT NULL default '0' AFTER modposts"); + $db->add_column("forumpermissions", "mod_edit_posts", "smallint NOT NULL default '0' AFTER modthreads"); + $db->add_column("forumpermissions", "modattachments", "smallint NOT NULL default '0' AFTER mod_edit_posts"); + $db->add_column("usergroups", "canbereported", "smallint NOT NULL default '0' AFTER canchangename"); + $db->add_column("usergroups", "canchangewebsite", "smallint NOT NULL default '1' AFTER canbereported"); + $db->add_column("usergroups", "edittimelimit", "int NOT NULL default '0'"); + $db->add_column("usergroups", "maxposts", "int NOT NULL default '0'"); + $db->add_column("usergroups", "showmemberlist", "smallint NOT NULL default '1'"); + $db->add_column("usergroups", "canviewboardclosed", "smallint NOT NULL default '0' AFTER candlattachments"); + $db->add_column("threads", "deletedposts", "int NOT NULL default '0' AFTER unapprovedposts"); + $db->add_column("captcha", "used", "smallint NOT NULL default '0'"); + $db->add_column("posts", "editreason", "varchar(150) NOT NULL default '' AFTER edittime"); + $db->add_column("forums", "usethreadcounts", "smallint NOT NULL default '0' AFTER usepostcounts"); + $db->add_column("forums", "requireprefix", "smallint NOT NULL default '0' AFTER usethreadcounts"); + $db->add_column("users", "threadnum", "int NOT NULL default '0' AFTER postnum"); + break; + default: + $db->add_column("forumpermissions", "canonlyreplyownthreads", "tinyint(1) NOT NULL default '0' AFTER canpostreplys"); + $db->add_column("forumpermissions", "modposts", "tinyint(1) NOT NULL default '0' AFTER caneditattachments"); + $db->add_column("forumpermissions", "modthreads", "tinyint(1) NOT NULL default '0' AFTER modposts"); + $db->add_column("forumpermissions", "mod_edit_posts", "tinyint(1) NOT NULL default '0' AFTER modthreads"); + $db->add_column("forumpermissions", "modattachments", "tinyint(1) NOT NULL default '0' AFTER mod_edit_posts"); + $db->add_column("usergroups", "canbereported", "tinyint(1) NOT NULL default '0' AFTER canchangename"); + $db->add_column("usergroups", "canchangewebsite", "tinyint(1) NOT NULL default '1' AFTER canbereported"); + $db->add_column("usergroups", "edittimelimit", "int(4) NOT NULL default '0'"); + $db->add_column("usergroups", "maxposts", "int(4) NOT NULL default '0'"); + $db->add_column("usergroups", "showmemberlist", "tinyint(1) NOT NULL default '1'"); + $db->add_column("usergroups", "canviewboardclosed", "tinyint(1) NOT NULL default '0' AFTER candlattachments"); + $db->add_column("threads", "deletedposts", "int(10) NOT NULL default '0' AFTER unapprovedposts"); + $db->add_column("captcha", "used", "tinyint(1) NOT NULL default '0'"); + $db->add_column("posts", "editreason", "varchar(150) NOT NULL default '' AFTER edittime"); + $db->add_column("forums", "usethreadcounts", "tinyint(1) NOT NULL default '0' AFTER usepostcounts"); + $db->add_column("forums", "requireprefix", "tinyint(1) NOT NULL default '0' AFTER usethreadcounts"); + $db->add_column("users", "threadnum", "int(10) NOT NULL default '0' AFTER postnum"); + break; + } + + $db->update_query('forums', array('usethreadcounts' => 1), 'usepostcounts = 1'); + + global $footer_extra; + $footer_extra = ""; + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + $output->print_footer("30_dbchanges3"); +} + +function upgrade30_dbchanges3() +{ + global $cache, $output, $mybb, $db; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + if($db->field_exists('cansoftdeleteposts', 'moderators')) + { + $db->drop_column('moderators', 'cansoftdeleteposts'); + } + + if($db->field_exists('canrestoreposts', 'moderators')) + { + $db->drop_column("moderators", "canrestoreposts"); + } + + if($db->field_exists('cansoftdeletethreads', 'moderators')) + { + $db->drop_column('moderators', 'cansoftdeletethreads'); + } + + if($db->field_exists('canrestorethreads', 'moderators')) + { + $db->drop_column("moderators", "canrestorethreads"); + } + + if($db->field_exists('candeletethreads', 'moderators')) + { + $db->drop_column("moderators", "candeletethreads"); + } + + if($db->field_exists('canviewunapprove', 'moderators')) + { + $db->drop_column("moderators", "canviewunapprove"); + } + + if($db->field_exists('canviewdeleted', 'moderators')) + { + $db->drop_column("moderators", "canviewdeleted"); + } + + if($db->field_exists('canstickunstickthreads', 'moderators')) + { + $db->drop_column("moderators", "canstickunstickthreads"); + } + + if($db->field_exists('canapproveunapprovethreads', 'moderators')) + { + $db->drop_column("moderators", "canapproveunapprovethreads"); + } + + if($db->field_exists('canapproveunapproveposts', 'moderators')) + { + $db->drop_column("moderators", "canapproveunapproveposts"); + } + + if($db->field_exists('canapproveunapproveattachs', 'moderators')) + { + $db->drop_column("moderators", "canapproveunapproveattachs"); + } + + if($db->field_exists('canmanagepolls', 'moderators')) + { + $db->drop_column("moderators", "canmanagepolls"); + } + + if($db->field_exists('canpostclosedthreads', 'moderators')) + { + $db->drop_column("moderators", "canpostclosedthreads"); + } + + if($db->field_exists('canmanageannouncements', 'moderators')) + { + $db->drop_column("moderators", "canmanageannouncements"); + } + + if($db->field_exists('canmanagereportedposts', 'moderators')) + { + $db->drop_column("moderators", "canmanagereportedposts"); + } + + if($db->field_exists('canviewmodlog', 'moderators')) + { + $db->drop_column("moderators", "canviewmodlog"); + } + + switch($db->type) + { + case "pgsql": + $db->add_column("moderators", "cansoftdeleteposts", "smallint NOT NULL default '0' AFTER caneditposts"); + $db->add_column("moderators", "canrestoreposts", "smallint NOT NULL default '0' AFTER cansoftdeleteposts"); + $db->add_column("moderators", "cansoftdeletethreads", "smallint NOT NULL default '0' AFTER candeleteposts"); + $db->add_column("moderators", "canrestorethreads", "smallint NOT NULL default '0' AFTER cansoftdeletethreads"); + $db->add_column("moderators", "candeletethreads", "smallint NOT NULL default '0' AFTER canrestorethreads"); + $db->add_column("moderators", "canviewunapprove", "smallint NOT NULL default '0' AFTER canviewips"); + $db->add_column("moderators", "canviewdeleted", "smallint NOT NULL default '0' AFTER canviewunapprove"); + $db->add_column("moderators", "canstickunstickthreads", "smallint NOT NULL default '0' AFTER canopenclosethreads"); + $db->add_column("moderators", "canapproveunapprovethreads", "smallint NOT NULL default '0' AFTER canstickunstickthreads"); + $db->add_column("moderators", "canapproveunapproveposts", "smallint NOT NULL default '0' AFTER canapproveunapprovethreads"); + $db->add_column("moderators", "canapproveunapproveattachs", "smallint NOT NULL default '0' AFTER canapproveunapproveposts"); + $db->add_column("moderators", "canmanagepolls", "smallint NOT NULL default '0' AFTER canmanagethreads"); + $db->add_column("moderators", "canpostclosedthreads", "smallint NOT NULL default '0' AFTER canmanagepolls"); + $db->add_column("moderators", "canmanageannouncements", "smallint NOT NULL default '0' AFTER canusecustomtools"); + $db->add_column("moderators", "canmanagereportedposts", "smallint NOT NULL default '0' AFTER canmanageannouncements"); + $db->add_column("moderators", "canviewmodlog", "smallint NOT NULL default '0' AFTER canmanagereportedposts"); + break; + default: + $db->add_column("moderators", "cansoftdeleteposts", "tinyint(1) NOT NULL default '0' AFTER caneditposts"); + $db->add_column("moderators", "canrestoreposts", "tinyint(1) NOT NULL default '0' AFTER cansoftdeleteposts"); + $db->add_column("moderators", "cansoftdeletethreads", "tinyint(1) NOT NULL default '0' AFTER candeleteposts"); + $db->add_column("moderators", "canrestorethreads", "tinyint(1) NOT NULL default '0' AFTER cansoftdeletethreads"); + $db->add_column("moderators", "candeletethreads", "tinyint(1) NOT NULL default '0' AFTER canrestorethreads"); + $db->add_column("moderators", "canviewunapprove", "tinyint(1) NOT NULL default '0' AFTER canviewips"); + $db->add_column("moderators", "canviewdeleted", "tinyint(1) NOT NULL default '0' AFTER canviewunapprove"); + $db->add_column("moderators", "canstickunstickthreads", "tinyint(1) NOT NULL default '0' AFTER canopenclosethreads"); + $db->add_column("moderators", "canapproveunapprovethreads", "tinyint(1) NOT NULL default '0' AFTER canstickunstickthreads"); + $db->add_column("moderators", "canapproveunapproveposts", "tinyint(1) NOT NULL default '0' AFTER canapproveunapprovethreads"); + $db->add_column("moderators", "canapproveunapproveattachs", "tinyint(1) NOT NULL default '0' AFTER canapproveunapproveposts"); + $db->add_column("moderators", "canmanagepolls", "tinyint(1) NOT NULL default '0' AFTER canmanagethreads"); + $db->add_column("moderators", "canpostclosedthreads", "tinyint(1) NOT NULL default '0' AFTER canmanagepolls"); + $db->add_column("moderators", "canmanageannouncements", "tinyint(1) NOT NULL default '0' AFTER canusecustomtools"); + $db->add_column("moderators", "canmanagereportedposts", "tinyint(1) NOT NULL default '0' AFTER canmanageannouncements"); + $db->add_column("moderators", "canviewmodlog", "tinyint(1) NOT NULL default '0' AFTER canmanagereportedposts"); + break; + } + + global $footer_extra; + $footer_extra = ""; + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + $output->print_footer("30_dbchanges4"); +} + +function upgrade30_dbchanges4() +{ + global $cache, $output, $mybb, $db; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + if($db->field_exists('emailfloodtime', 'usergroups')) + { + $db->drop_column("usergroups", "emailfloodtime"); + } + + if($db->field_exists('canmanageannounce', 'usergroups')) + { + $db->drop_column("usergroups", "canmanageannounce"); + } + + if($db->field_exists('canmanagemodqueue', 'usergroups')) + { + $db->drop_column("usergroups", "canmanagemodqueue"); + } + + if($db->field_exists('canmanagereportedcontent', 'usergroups')) + { + $db->drop_column("usergroups", "canmanagereportedcontent"); + } + + if($db->field_exists('canviewmodlogs', 'usergroups')) + { + $db->drop_column("usergroups", "canviewmodlogs"); + } + + if($db->field_exists('caneditprofiles', 'usergroups')) + { + $db->drop_column("usergroups", "caneditprofiles"); + } + + if($db->field_exists('canbanusers', 'usergroups')) + { + $db->drop_column("usergroups", "canbanusers"); + } + + if($db->field_exists('canviewwarnlogs', 'usergroups')) + { + $db->drop_column("usergroups", "canviewwarnlogs"); + } + + if($db->field_exists('canuseipsearch', 'usergroups')) + { + $db->drop_column("usergroups", "canuseipsearch"); + } + + if($db->field_exists('type', 'maillogs')) + { + $db->drop_column("maillogs", "type"); + } + + if($db->field_exists('groups', 'modtools')) + { + $db->drop_column("modtools", "groups"); + } + + switch($db->type) + { + case "pgsql": + $db->add_column("usergroups", "emailfloodtime", "int NOT NULL default '5' AFTER maxemails"); + $db->add_column("usergroups", "canmanageannounce", "smallint NOT NULL default '0' AFTER showmemberlist"); + $db->add_column("usergroups", "canmanagemodqueue", "smallint NOT NULL default '0' AFTER canmanageannounce"); + $db->add_column("usergroups", "canmanagereportedcontent", "smallint NOT NULL default '0' AFTER canmanagemodqueue"); + $db->add_column("usergroups", "canviewmodlogs", "smallint NOT NULL default '0' AFTER canmanagereportedcontent"); + $db->add_column("usergroups", "caneditprofiles", "smallint NOT NULL default '0' AFTER canviewmodlogs"); + $db->add_column("usergroups", "canbanusers", "smallint NOT NULL default '0' AFTER caneditprofiles"); + $db->add_column("usergroups", "canviewwarnlogs", "smallint NOT NULL default '0' AFTER canbanusers"); + $db->add_column("usergroups", "canuseipsearch", "smallint NOT NULL default '0' AFTER canviewwarnlogs"); + $db->add_column("maillogs", "type", "smallint NOT NULL default '0'"); + break; + default: + $db->add_column("usergroups", "emailfloodtime", "int(3) NOT NULL default '5' AFTER maxemails"); + $db->add_column("usergroups", "canmanageannounce", "tinyint(1) NOT NULL default '0' AFTER showmemberlist"); + $db->add_column("usergroups", "canmanagemodqueue", "tinyint(1) NOT NULL default '0' AFTER canmanageannounce"); + $db->add_column("usergroups", "canmanagereportedcontent", "tinyint(1) NOT NULL default '0' AFTER canmanagemodqueue"); + $db->add_column("usergroups", "canviewmodlogs", "tinyint(1) NOT NULL default '0' AFTER canmanagereportedcontent"); + $db->add_column("usergroups", "caneditprofiles", "tinyint(1) NOT NULL default '0' AFTER canviewmodlogs"); + $db->add_column("usergroups", "canbanusers", "tinyint(1) NOT NULL default '0' AFTER caneditprofiles"); + $db->add_column("usergroups", "canviewwarnlogs", "tinyint(1) NOT NULL default '0' AFTER canbanusers"); + $db->add_column("usergroups", "canuseipsearch", "tinyint(1) NOT NULL default '0' AFTER canviewwarnlogs"); + $db->add_column("maillogs", "type", "tinyint(1) NOT NULL default '0'"); + break; + } + + switch($db->type) + { + case "sqlite": + $db->add_column("modtools", "groups", "text NOT NULL default ''"); + break; + default: + $db->add_column("modtools", "groups", "text NOT NULL"); + break; + } + + $update_array = array( + "canmanageannounce" => 1, + "canmanagemodqueue" => 1, + "canmanagereportedcontent" => 1, + "canviewmodlogs" => 1, + "caneditprofiles" => 1, + "canbanusers" => 1, + "canviewwarnlogs" => 1, + "canuseipsearch" => 1 + ); + $db->update_query("usergroups", $update_array, "canmodcp= '1'"); + + $update_array = array( + "type" => 1 + ); + $db->update_query("maillogs", $update_array, "tid= '0'"); + + $update_array = array( + "type" => 2 + ); + $db->update_query("maillogs", $update_array, "tid > '0'"); + + global $footer_extra; + $footer_extra = ""; + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + $output->print_footer("30_dbchanges5"); +} + +function upgrade30_dbchanges5() +{ + global $cache, $output, $mybb, $db; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + if($db->table_exists("questions")) + { + $db->drop_table("questions"); + } + + if($db->table_exists("questionsessions")) + { + $db->drop_table("questionsessions"); + } + + if($db->table_exists("spamlog")) + { + $db->drop_table("spamlog"); + } + + $collation = $db->build_create_table_collation(); + + switch($db->type) + { + case "sqlite": + $db->write_query("CREATE TABLE ".TABLE_PREFIX."questions ( + qid INTEGER PRIMARY KEY, + question varchar(200) NOT NULL default '', + answer varchar(150) NOT NULL default '', + shown int unsigned NOT NULL default 0, + correct int unsigned NOT NULL default 0, + incorrect int unsigned NOT NULL default 0, + active tinyint(1) NOT NULL default '0' + );"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."questionsessions ( + sid varchar(32) NOT NULL default '', + qid int unsigned NOT NULL default '0', + dateline int unsigned NOT NULL default '0' + );"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."spamlog ( + sid INTEGER PRIMARY KEY, + username varchar(120) NOT NULL DEFAULT '', + email varchar(220) NOT NULL DEFAULT '', + ipaddress blob(16) NOT NULL default '', + dateline int unsigned NOT NULL default '0', + data TEXT NOT NULL + );"); + break; + case "pgsql": + $db->write_query("CREATE TABLE ".TABLE_PREFIX."questions ( + qid serial, + question varchar(200) NOT NULL default '', + answer varchar(150) NOT NULL default '', + shown int NOT NULL default 0, + correct int NOT NULL default 0, + incorrect int NOT NULL default 0, + active smallint NOT NULL default '0', + PRIMARY KEY (qid) + );"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."questionsessions ( + sid varchar(32) NOT NULL default '', + qid int NOT NULL default '0', + dateline int NOT NULL default '0', + UNIQUE (sid) + );"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."spamlog ( + sid serial, + username varchar(120) NOT NULL DEFAULT '', + email varchar(220) NOT NULL DEFAULT '', + ipaddress bytea NOT NULL default '', + dateline numeric(30,0) NOT NULL default '0', + data text NOT NULL default '', + PRIMARY KEY (sid) + );"); + break; + default: + $db->write_query("CREATE TABLE ".TABLE_PREFIX."questions ( + qid int unsigned NOT NULL auto_increment, + question varchar(200) NOT NULL default '', + answer varchar(150) NOT NULL default '', + shown int unsigned NOT NULL default 0, + correct int unsigned NOT NULL default 0, + incorrect int unsigned NOT NULL default 0, + active tinyint(1) NOT NULL default '0', + PRIMARY KEY (qid) + ) ENGINE=MyISAM{$collation}"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."questionsessions ( + sid varchar(32) NOT NULL default '', + qid int unsigned NOT NULL default '0', + dateline int unsigned NOT NULL default '0', + PRIMARY KEY (sid) + ) ENGINE=MyISAM{$collation}"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."spamlog ( + sid int unsigned NOT NULL auto_increment, + username varchar(120) NOT NULL DEFAULT '', + email varchar(220) NOT NULL DEFAULT '', + ipaddress varbinary(16) NOT NULL default '', + dateline int unsigned NOT NULL default '0', + data text NOT NULL, + PRIMARY KEY (sid) + ) ENGINE=MyISAM{$collation}"); + } + + global $footer_extra; + $footer_extra = ""; + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + $output->print_footer("30_dbchanges6"); +} + +function upgrade30_dbchanges6() +{ + global $cache, $output, $mybb, $db; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + flush(); + + if($db->table_exists("buddyrequests")) + { + $db->drop_table("buddyrequests"); + } + + $collation = $db->build_create_table_collation(); + + switch($db->type) + { + case "pgsql": + $db->write_query("CREATE TABLE ".TABLE_PREFIX."buddyrequests ( + id serial, + uid int NOT NULL, + touid int NOT NULL, + date int NOT NULL, + PRIMARY KEY (id) + );"); + break; + case "sqlite": + $db->write_query("CREATE TABLE ".TABLE_PREFIX."buddyrequests ( + id INTEGER PRIMARY KEY, + uid bigint unsigned NOT NULL, + touid bigint unsigned NOT NULL, + date int unsigned NOT NULL + );"); + break; + default: + $db->write_query("CREATE TABLE ".TABLE_PREFIX."buddyrequests ( + id int(10) UNSIGNED NOT NULL auto_increment, + uid bigint(30) UNSIGNED NOT NULL, + touid bigint(30) UNSIGNED NOT NULL, + date int(11) UNSIGNED NOT NULL, + KEY (uid), + KEY (touid), + PRIMARY KEY (id) + ) ENGINE=MyISAM{$collation};"); + break; + } + + if($db->field_exists('msn', 'users')) + { + $db->drop_column("users", "msn"); + } + + if($db->field_exists('postbit', 'profilefields')) + { + $db->drop_column("profilefields", "postbit"); + } + + if($db->field_exists('skype', 'users')) + { + $db->drop_column("users", "skype"); + } + + if($db->field_exists('google', 'users')) + { + $db->drop_column("users", "google"); + } + + if($db->field_exists('cplanguage', 'adminoptions')) + { + $db->drop_column("adminoptions", "cplanguage"); + } + + if($db->field_exists('showimages', 'users')) + { + $db->drop_column("users", "showimages"); + } + + if($db->field_exists('showvideos', 'users')) + { + $db->drop_column("users", "showvideos"); + } + + if($db->field_exists('caninvitemembers', 'groupleaders')) + { + $db->drop_column("groupleaders", "caninvitemembers"); + } + + if($db->field_exists('invite', 'joinrequests')) + { + $db->drop_column("joinrequests", "invite"); + } + + if($db->field_exists('registration', 'profilefields')) + { + $db->drop_column("profilefields", "registration"); + } + + if($db->field_exists('validated', 'awaitingactivation')) + { + $db->drop_column("awaitingactivation", "validated"); + } + + if($db->field_exists('sourceeditor', 'users')) + { + $db->drop_column("users", "sourceeditor"); + } + + if($db->field_exists('buddyrequestspm', 'users')) + { + $db->drop_column("users", "buddyrequestspm"); + } + + if($db->field_exists('buddyrequestsauto', 'users')) + { + $db->drop_column("users", "buddyrequestsauto"); + } + + if($db->field_exists('ipaddress', 'privatemessages')) + { + $db->drop_column("privatemessages", "ipaddress"); + } + + if($db->field_exists('maxoptions', 'polls')) + { + $db->drop_column("polls", "maxoptions"); + } + + switch($db->type) + { + case "pgsql": + $db->add_column("profilefields", "postbit", "smallint NOT NULL default '0' AFTER profile"); + $db->add_column("users", "skype", "varchar(75) NOT NULL default '' AFTER yahoo"); + $db->add_column("users", "google", "varchar(75) NOT NULL default '' AFTER skype"); + $db->add_column("adminoptions", "cplanguage", "varchar(50) NOT NULL default '' AFTER cpstyle"); + $db->add_column("users", "showimages", "smallint NOT NULL default '1' AFTER threadmode"); + $db->add_column("users", "showvideos", "smallint NOT NULL default '1' AFTER showimages"); + $db->add_column("users", "buddyrequestspm", "smallint NOT NULL default '1' AFTER pmnotify"); + $db->add_column("users", "buddyrequestsauto", "smallint NOT NULL default '0' AFTER buddyrequestspm"); + $db->add_column("groupleaders", "caninvitemembers", "smallint NOT NULL default '0'"); + $db->add_column("joinrequests", "invite", "smallint NOT NULL default '0'"); + $db->add_column("profilefields", "registration", "smallint NOT NULL default '0' AFTER required"); + $db->add_column("awaitingactivation", "validated", "smallint NOT NULL default '0' AFTER type"); + $db->add_column("users", "sourceeditor", "smallint NOT NULL default '0'"); + break; + default: + $db->add_column("profilefields", "postbit", "tinyint(1) NOT NULL default '0' AFTER profile"); + $db->add_column("users", "skype", "varchar(75) NOT NULL default '' AFTER yahoo"); + $db->add_column("users", "google", "varchar(75) NOT NULL default '' AFTER skype"); + $db->add_column("adminoptions", "cplanguage", "varchar(50) NOT NULL default '' AFTER cpstyle"); + $db->add_column("users", "showimages", "tinyint(1) NOT NULL default '1' AFTER threadmode"); + $db->add_column("users", "showvideos", "tinyint(1) NOT NULL default '1' AFTER showimages"); + $db->add_column("users", "buddyrequestspm", "tinyint(1) NOT NULL default '1' AFTER pmnotify"); + $db->add_column("users", "buddyrequestsauto", "tinyint(1) NOT NULL default '0' AFTER buddyrequestspm"); + $db->add_column("groupleaders", "caninvitemembers", "tinyint(1) NOT NULL default '0'"); + $db->add_column("joinrequests", "invite", "tinyint(1) NOT NULL default '0'"); + $db->add_column("profilefields", "registration", "tinyint(1) NOT NULL default '0' AFTER required"); + $db->add_column("awaitingactivation", "validated", "tinyint(1) NOT NULL default '0' AFTER type"); + $db->add_column("users", "sourceeditor", "tinyint(1) NOT NULL default '0'"); + break; + } + + switch($db->type) + { + case "pgsql": + $db->add_column("privatemessages", "ipaddress", "bytea NOT NULL default ''"); + $db->add_column("polls", "maxoptions", "smallint NOT NULL default '0'"); + break; + case "sqlite": + $db->add_column("privatemessages", "ipaddress", "blob(16) NOT NULL default ''"); + $db->add_column("polls", "maxoptions", "smallint NOT NULL default '0'"); + break; + default: + $db->add_column("privatemessages", "ipaddress", "varbinary(16) NOT NULL default ''"); + $db->add_column("polls", "maxoptions", "smallint unsigned NOT NULL default '0'"); + break; + } + + $groups = range(1, 39); + + $sql = implode(',', $groups); + $db->update_query("templategroups", array('isdefault' => 1), "gid IN ({$sql})"); + + if($db->table_exists('reportedposts')) + { + $db->update_query("reportedposts", array('type' => 'post')); + } + + $db->insert_query("questions", array('question' => 'Jaki jest wynik działania 2+2?', 'answer' => '4\ncztery', 'active' => '1')); + + $query = $db->simple_select("attachtypes", "COUNT(*) as numexists", "extension='psd'"); + if($db->fetch_field($query, "numexists") == 0) + { + $db->insert_query("attachtypes", array('name' => "Plik Adobe Photoshop", 'mimetype' => 'application/x-photoshop', 'extension' => "psd", 'maxsize' => '1024', 'icon' => 'images/attachtypes/psd.png')); + } + // SQLite... As we modify tables below we need to close all cursors before... + if($db->type == "sqlite") + { + $query->closeCursor(); + } + + $query = $db->simple_select("templategroups", "COUNT(*) as numexists", "prefix='video'"); + if($db->fetch_field($query, "numexists") == 0) + { + $db->insert_query("templategroups", array('prefix' => 'video', 'title' => '', 'isdefault' => '1')); + } + // SQLite... As we modify tables below we need to close all cursors before... + if($db->type == "sqlite") + { + $query->closeCursor(); + } + + $query = $db->simple_select("templategroups", "COUNT(*) as numexists", "prefix='php'"); + if($db->fetch_field($query, "numexists") != 0) + { + $db->update_query("templategroups", array('prefix' => 'announcement', 'title' => ''), "prefix='php'"); + } + // SQLite... As we modify tables below we need to close all cursors before... + if($db->type == "sqlite") + { + $query->closeCursor(); + } + + $query = $db->simple_select("templategroups", "COUNT(*) as numexists", "prefix='redirect'"); + if($db->fetch_field($query, "numexists") != 0) + { + $db->update_query("templategroups", array('prefix' => 'posticons', 'title' => ''), "prefix='redirect'"); + } + // SQLite... As we modify tables below we need to close all cursors before... + if($db->type == "sqlite") + { + $query->closeCursor(); + } + + // Sync usergroups with canbereported; no moderators or banned groups + echo "

    Aktualizowanie uprawnień grup...

    "; + $groups = array(); + $usergroups = $cache->read('usergroups'); + + foreach($usergroups as $group) + { + if($group['canmodcp'] || $group['isbannedgroup']) + { + continue; + } + + $groups[] = "'{$group['gid']}'"; + } + + $usergroups = implode(',', $groups); + $db->update_query('usergroups', array('canbereported' => 1), "gid IN ({$usergroups})"); + + $db->update_query('usergroups', array('canviewboardclosed' => 1), 'cancp = 1'); + + if($db->table_exists('reportedposts')) + { + if($db->field_exists("pid", "reportedposts") && !$db->field_exists("id", "reportedposts")) + { + switch($db->type) + { + case "pgsql": + $db->rename_column("reportedposts", "pid", "id", "int", true, "'0'"); + break; + default: + $db->rename_column("reportedposts", "pid", "id", "int unsigned NOT NULL default '0'"); + } + } + + if($db->field_exists("tid", "reportedposts") && !$db->field_exists("id2", "reportedposts")) + { + switch($db->type) + { + case "pgsql": + $db->rename_column("reportedposts", "tid", "id2", "int", true, "'0'"); + break; + default: + $db->rename_column("reportedposts", "tid", "id2", "int unsigned NOT NULL default '0'"); + } + } + + if($db->field_exists("fid", "reportedposts") && !$db->field_exists("id3", "reportedposts")) + { + switch($db->type) + { + case "pgsql": + $db->rename_column("reportedposts", "fid", "id3", "int", true, "'0'"); + break; + default: + $db->rename_column("reportedposts", "fid", "id3", "int unsigned NOT NULL default '0'"); + } + } + } + + if($db->table_exists('reportedposts')) + { + if($db->table_exists("reportedcontent")) + { + $db->drop_table("reportedcontent"); + } + + $db->rename_table("reportedposts", "reportedcontent"); + + $cache->delete('reportedposts'); + } + + $db->update_query("settings", array('optionscode' => 'select\r\n0=No CAPTCHA\r\n1=MyBB Default CAPTCHA\r\n2=reCAPTCHA\r\n3=Are You a Human'), "name='captchaimage'"); + $db->update_query("settings", array('optionscode' => 'select\r\ninstant=Instant Activation\r\nverify=Send Email Verification\r\nrandompass=Send Random Password\r\nadmin=Administrator Activation\r\nboth=Email Verification & Administrator Activation'), "name='regtype'"); + $db->update_query("settings", array('optionscode' => $db->escape_string('php +')), "name='timezoneoffset'"); + + // Update tasks + $added_tasks = sync_tasks(); + + // For the version check task, set a random date and hour (so all MyBB installs don't query mybb.com all at the same time) + $update_array = array( + 'hour' => rand(0, 23), + 'weekday' => rand(0, 6) + ); + + $db->update_query("tasks", $update_array, "file = 'versioncheck'"); + + echo "

    Dodano {$added_tasks} nowych zadań.

    "; + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + $output->print_footer("30_threadcount"); +} + +function upgrade30_threadcount() +{ + global $db, $output; + + $output->print_header("Zliczanie liczby wątków użytkowników"); + + if(!$_POST['theadspage']) + { + $threads = 500; + } + else + { + $threads = $_POST['theadspage']; + } + + if($_POST['threadstart']) + { + $startat = $_POST['threadstart']; + $upper = $startat+$threads; + $lower = $startat; + } + else + { + $startat = 0; + $upper = $threads; + $lower = 0; + } + + $query = $db->simple_select("users", "COUNT(uid) AS usercount"); + $cnt = $db->fetch_array($query); + + if($upper > $cnt['usercount']) + { + $upper = $cnt['usercount']; + } + + echo "

    Zliczanie wÄ…tków użytkowników od #{$lower} do #{$upper} (ÅÄ…cznie {$cnt['usercount']})

    "; + flush(); + + $threadnum = false; + + $query = $db->simple_select("users", "threadnum, uid", "", array('limit_start' => $lower, 'limit' => $threads)); + while($thread = $db->fetch_array($query)) + { + $query2 = $db->simple_select("threads", "COUNT(tid) AS thread_count", "uid='{$thread['uid']}' AND visible = 1"); + $num_threads = $db->fetch_field($query2, "thread_count"); + + $db->update_query("users", array('threadnum' => $num_threads), "uid = '{$thread['uid']}'"); + + $threadnum = true; + } + + $remaining = $upper-$cnt['usercount']; + if($remaining && $threadnum) + { + $nextact = "30_threadcount"; + $startat = $startat+$threads; + $contents = "

    Done. Naciśnij przycisk Dalej, aby przejść do kolejnego zestawu użytkowników.

    "; + } + else + { + $nextact = "30_dbchanges_optimize1"; + $contents = "

    Zakończono

    Liczby wątków utworzonych przez poszczególnych użytkowników zostały ustalone. Naciśnij przycisk Dalej, aby kontynuować.

    "; + } + $output->print_contents($contents); + + global $footer_extra; + $footer_extra = ""; + + $output->print_footer($nextact); +} + +function upgrade30_dbchanges_optimize1() +{ + global $output, $mybb, $db; + + $output->print_header("Wykonywanie optymalizacji"); + + echo "

    Trwa wykonywanie wymaganych optymalizacji bazy danych...

    "; + flush(); + + switch($db->type) + { + case "pgsql": + $db->modify_column("adminoptions", "loginattempts", "smallint", "set", "'0'"); + $db->modify_column("adminviews", "perpage", "smallint", "set", "'0'"); + $db->modify_column("calendars", "disporder", "smallint", "set", "'0'"); + $db->modify_column("calendars", "eventlimit", "smallint", "set", "'0'"); + $db->modify_column("events", "timezone", "varchar(5)", "set", "''"); + $db->modify_column("forums", "lastposttid", "int", "set", "'0'"); + $db->modify_column("mailerrors", "smtpcode", "smallint", "set", "'0'"); + $db->modify_column("maillogs", "touid", "int", "set", "'0'"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."polls ALTER COLUMN numvotes DROP DEFAULT"); // We need to drop the default first as PostgreSQL can't cast default values + $db->modify_column("polls", "numvotes", "int USING (trim(numvotes)::int)", "set", "'0'"); + $db->modify_column("profilefields", "postnum", "smallint", "set", "'0'"); + $db->modify_column("reputation", "reputation", "smallint", "set", "'0'"); + $db->modify_column("spiders", "theme", "smallint", "set", "'0'"); + $db->modify_column("spiders", "usergroup", "smallint", "set", "'0'"); + $db->modify_column("templates", "sid", "smallint", "set", "'0'"); + $db->modify_column("themestylesheets", "tid", "smallint", "set", "'0'"); + $db->modify_column("usergroups", "canusesigxposts", "smallint", "set", "'0'"); + $db->modify_column("users", "timezone", "varchar(5)", "set", "''"); + $db->modify_column("users", "reputation", "int", "set", "'0'"); + $db->modify_column("warninglevels", "percentage", "smallint", "set", "'0'"); + $db->modify_column("warningtypes", "points", "smallint", "set", "'0'"); + $db->modify_column("warnings", "points", "smallint", "set", "'0'"); + break; + case "sqlite": + $db->modify_column("adminoptions", "loginattempts", "smallint NOT NULL default '0'"); + $db->modify_column("adminviews", "perpage", "smallint NOT NULL default '0'"); + $db->modify_column("calendars", "disporder", "smallint NOT NULL default '0'"); + $db->modify_column("calendars", "eventlimit", "smallint NOT NULL default '0'"); + $db->modify_column("events", "timezone", "varchar(5) NOT NULL default ''"); + $db->modify_column("forums", "lastposttid", "int NOT NULL default '0'"); + $db->modify_column("mailerrors", "smtpcode", "smallint NOT NULL default '0'"); + $db->modify_column("maillogs", "touid", "int NOT NULL default '0'"); + $db->modify_column("polls", "numvotes", "int NOT NULL default '0'"); + $db->modify_column("profilefields", "postnum", "smallint NOT NULL default '0'"); + $db->modify_column("reputation", "reputation", "smallint NOT NULL default '0'"); + $db->modify_column("spiders", "theme", "smallint NOT NULL default '0'"); + $db->modify_column("spiders", "usergroup", "smallint NOT NULL default '0'"); + $db->modify_column("templates", "sid", "smallint NOT NULL default '0'"); + $db->modify_column("themestylesheets", "tid", "smallint NOT NULL default '0'"); + $db->modify_column("usergroups", "canusesigxposts", "smallint NOT NULL default '0'"); + $db->modify_column("users", "timezone", "varchar(5) NOT NULL default ''"); + $db->modify_column("users", "reputation", "int NOT NULL default '0'"); + $db->modify_column("warninglevels", "percentage", "smallint NOT NULL default '0'"); + $db->modify_column("warningtypes", "points", "smallint NOT NULL default '0'"); + $db->modify_column("warnings", "points", "smallint NOT NULL default '0'"); + break; + default: + $db->modify_column("adminoptions", "loginattempts", "smallint unsigned NOT NULL default '0'"); + $db->modify_column("adminviews", "perpage", "smallint(4) NOT NULL default '0'"); + $db->modify_column("calendars", "disporder", "smallint unsigned NOT NULL default '0'"); + $db->modify_column("calendars", "eventlimit", "smallint(3) NOT NULL default '0'"); + $db->modify_column("events", "timezone", "varchar(5) NOT NULL default ''"); + $db->modify_column("forums", "lastposttid", "int unsigned NOT NULL default '0'"); + $db->modify_column("mailerrors", "smtpcode", "smallint(5) unsigned NOT NULL default '0'"); + $db->modify_column("maillogs", "touid", "int unsigned NOT NULL default '0'"); + $db->modify_column("polls", "numvotes", "int unsigned NOT NULL default '0'"); + $db->modify_column("profilefields", "postnum", "smallint unsigned NOT NULL default '0'"); + $db->modify_column("reputation", "reputation", "smallint NOT NULL default '0'"); + $db->modify_column("spiders", "theme", "smallint unsigned NOT NULL default '0'"); + $db->modify_column("spiders", "usergroup", "smallint unsigned NOT NULL default '0'"); + $db->modify_column("templates", "sid", "smallint NOT NULL default '0'"); + $db->modify_column("themestylesheets", "tid", "smallint unsigned NOT NULL default '0'"); + $db->modify_column("usergroups", "canusesigxposts", "smallint unsigned NOT NULL default '0'"); + $db->modify_column("users", "timezone", "varchar(5) NOT NULL default ''"); + $db->modify_column("users", "reputation", "int NOT NULL default '0'"); + $db->modify_column("warninglevels", "percentage", "smallint(3) NOT NULL default '0'"); + $db->modify_column("warningtypes", "points", "smallint unsigned NOT NULL default '0'"); + $db->modify_column("warnings", "points", "smallint unsigned NOT NULL default '0'"); + break; + } + + if($db->type != "pgsql") + { + // PgSQL doesn't support longtext + if($db->type == "sqlite") + { + // And SQLite doesn't like text columns without a default value... + $db->modify_column("themestylesheets", "stylesheet", "longtext NOT NULL default ''"); + } + else + { + // ...while MySQL hates text columns with a default value + $db->modify_column("themestylesheets", "stylesheet", "longtext NOT NULL"); + } + } + + global $footer_extra; + $footer_extra = ""; + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + $output->print_footer("30_dbchanges_optimize2"); +} + +function upgrade30_dbchanges_optimize2() +{ + global $output, $mybb, $db; + + $output->print_header("Wykonywanie optymalizacji"); + + echo "

    Trwa wykonywanie wymaganych optymalizacji bazy danych...

    "; + echo "

    Dodawanie indeksów do tabel...

    "; + flush(); + + if($db->index_exists('sessions', 'location1')) + { + $db->drop_index('sessions', 'location1'); + } + + if($db->index_exists('sessions', 'location2')) + { + $db->drop_index('sessions', 'location2'); + } + + if($db->type == "mysql" || $db->type == "mysqli") + { + $update_data = array( + 'adminlog' => 'uid', + 'banfilters' => 'type', + 'events' => 'cid', + 'forumsubscriptions' => 'uid', + 'moderatorlog' => array('uid', 'fid'), + 'polls' => 'tid', + 'reportedcontent' => 'reportstatus', + 'settings' => 'gid', + 'themestylesheets' => 'tid', + 'warnings' => 'uid', + 'forumpermissions' => array('fid' => array('fid', 'gid')), + 'sessions' => array('location' => array('location1', 'location2')), + 'templates' => array('sid' => array('sid', 'title')) + ); + + foreach($update_data as $table => $index) + { + if(!is_array($index)) + { + $index = array($index); + } + + foreach($index as $_index => $keys) + { + if(!is_array($keys)) + { + if(!$db->index_exists($table, $keys)) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."{$table} ADD INDEX (`{$keys}`)"); + } + } + else + { + if(!$db->index_exists($table, $_index)) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."{$table} ADD INDEX `{$_index}`(`".implode('`, `', $keys)."`)"); + } + } + } + } + } + + echo "

    Usuwanie starych indeksów z tabel...

    "; + + if($db->index_exists('attachments', 'posthash')) + { + $db->drop_index('attachments', 'posthash'); + } + + if($db->index_exists('reportedcontent', 'dateline')) + { + $db->drop_index('reportedcontent', 'dateline'); + } + + if($db->index_exists('reputation', 'pid')) + { + $db->drop_index('reputation', 'pid'); + } + + if($db->index_exists('reputation', 'dateline')) + { + $db->drop_index('reputation', 'dateline'); + } + + if($db->index_exists('users', 'birthday')) + { + $db->drop_index('users', 'birthday'); + } + + global $footer_extra; + $footer_extra = ""; + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + $output->print_footer("30_dbchanges_optimize3"); +} + +function upgrade30_dbchanges_optimize3() +{ + global $cache, $output, $mybb, $db; + + $output->print_header("Wykonywanie optymalizacji"); + + echo "

    Trwa wykonywanie wymaganych optymalizacji bazy danych...

    "; + flush(); + + $to_tinyint = array( + "adminoptions" => array("codepress"), + "adminviews" => array("visibility"), + "announcements" => array("allowhtml", "allowmycode", "allowsmilies"), + "attachments" => array("visible"), + "banfilters" => array("type"), + "calendars" => array("startofweek", "showbirthdays", "moderation", "allowhtml", "allowmycode", "allowimgcode", "allowvideocode", "allowsmilies"), + "calendarpermissions" => array("canviewcalendar", "canaddevents", "canbypasseventmod", "canmoderateevents"), + "events" => array("visible", "private", "ignoretimezone", "usingtime"), + "forumpermissions" => array("canview", "canviewthreads", "canonlyviewownthreads", "candlattachments", "canpostthreads", "canpostreplys", "canpostattachments", "canratethreads", "caneditposts", "candeleteposts", "candeletethreads", "caneditattachments", "canpostpolls", "canvotepolls", "cansearch"), + "forums" => array("active", "open", "allowhtml", "allowmycode", "allowsmilies", "allowimgcode", "allowvideocode", "allowpicons", "allowtratings", "usepostcounts", "showinjump", "overridestyle", "rulestype"), + "groupleaders" => array("canmanagemembers", "canmanagerequests"), + "helpdocs" => array("usetranslation", "enabled"), + "helpsections" => array("usetranslation", "enabled"), + "moderators" => array("isgroup", "caneditposts", "candeleteposts", "canviewips", "canopenclosethreads", "canmanagethreads", "canmovetononmodforum", "canusecustomtools"), + "mycode" => array("active"), + "polls" => array("closed", "multiple", "public"), + "posts" => array("includesig", "smilieoff", "visible"), + "privatemessages" => array("status", "includesig", "smilieoff", "receipt"), + "profilefields" => array("required"), + "reportedcontent" => array("reportstatus"), + "sessions" => array("anonymous", "nopermission"), + "settinggroups" => array("isdefault"), + "settings" => array("isdefault"), + "smilies" => array("showclickable"), + "tasks" => array("enabled", "logging"), + "themes" => array("def"), + "threads" => array("sticky", "visible"), + "threadsubscriptions" => array("notification"), + "usergroups" => array("isbannedgroup", "canview", "canviewthreads", "canviewprofiles", "candlattachments", "canviewboardclosed", "canpostthreads", "canpostreplys", "canpostattachments", "canratethreads", "caneditposts", "candeleteposts", "candeletethreads", "caneditattachments", "canpostpolls", "canvotepolls", "canundovotes", "canusepms", "cansendpms", "cantrackpms", "candenypmreceipts", "cansendemail", "cansendemailoverride", "canviewmemberlist", "canviewcalendar", "canaddevents", "canbypasseventmod", "canmoderateevents", "canviewonline", "canviewwolinvis", "canviewonlineips", "cancp", "issupermod", "cansearch", "canusercp", "canuploadavatars", "canratemembers", "canchangename", "canbereported", "showforumteam", "usereputationsystem", "cangivereputations", "candisplaygroup", "cancustomtitle", "canwarnusers", "canreceivewarnings", "canmodcp", "showinbirthdaylist", "canoverridepm", "canusesig", "signofollow"), + "users" => array("allownotices", "hideemail", "subscriptionmethod", "invisible", "receivepms", "receivefrombuddy", "pmnotice", "pmnotify", "showsigs", "showavatars", "showquickreply", "showredirect", "showcodebuttons", "coppauser", "classicpostbit"), + "warnings" => array("expired") + ); + + foreach($to_tinyint as $table => $columns) + { + echo "

    {$table}: Zmiana typu kolumny na tinyint

    "; + $change_column = array(); + foreach($columns as $column) + { + if($db->type == "pgsql") + { + $db->modify_column($table, $column, "smallint", "set", "'0'"); + } + else if($db->type == "sqlite") + { + $change_column[] = "CHANGE {$column} {$column} tinyint(1) NOT NULL default '0'"; + } + else + { + $change_column[] = "MODIFY {$column} tinyint(1) NOT NULL default '0'"; + } + } + if($db->type != "pgsql") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."{$table} ".implode(", ", $change_column)); + } + } + + global $footer_extra; + $footer_extra = ""; + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + $output->print_footer("30_dbchanges_optimize4"); +} + +function upgrade30_dbchanges_optimize4() +{ + global $cache, $output, $mybb, $db; + + $output->print_header("Wykonywanie optymalizacji"); + + echo "

    Trwa wykonywanie wymaganych optymalizacji bazy danych...

    "; + flush(); + + $to_int = array( + "adminlog" => array("dateline"), + "adminsessions" => array("dateline", "lastactive"), + "announcements" => array("startdate", "enddate"), + "attachments" => array("dateuploaded"), + "awaitingactivation" => array("dateline"), + "banfilters" => array("lastuse", "dateline"), + "banned" => array("dateline", "lifted"), + "captcha" => array("dateline"), + "delayedmoderation" => array("delaydateline", "dateline"), + "forumsread" => array("dateline"), + "joinrequests" => array("dateline"), + "massemails" => array("dateline", "senddate"), + "mailerrors" => array("dateline"), + "maillogs" => array("dateline"), + "moderatorlog" => array("dateline"), + "polls" => array("dateline", "timeout"), + "pollvotes" => array("dateline"), + "posts" => array("dateline", "edittime"), + "privatemessages" => array("dateline", "deletetime", "statustime", "readtime"), + "promotionlogs" => array("dateline"), + "reportedcontent" => array("dateline", "lastreport"), + "reputation" => array("dateline"), + "searchlog" => array("dateline"), + "sessions" => array("time"), + "spiders" => array("lastvisit"), + "stats" => array("dateline"), + "tasks" => array("nextrun", "lastrun", "locked"), + "tasklog" => array("dateline"), + "templates" => array("dateline"), + "themestylesheets" => array("lastmodified"), + "threads" => array("dateline", "lastpost"), + "threadsread" => array("dateline"), + "threadsubscriptions" => array("dateline"), + "threadsread" => array("dateline"), + "usergroups" => array("reputationpower", "maxreputationsday", "maxreputationsperuser", "maxreputationsperthread", "attachquota"), + "users" => array("regdate", "lastactive", "lastvisit", "lastpost", "timeonline", "moderationtime", "suspensiontime", "suspendsigtime"), + "warningtypes" => array("expirationtime"), + "warnings" => array("dateline", "expires", "daterevoked") + ); + + foreach($to_int as $table => $columns) + { + echo "

    {$table}: Zmiana typu kolumny na int

    "; + $change_column = array(); + foreach($columns as $column) + { + if($db->type == "pgsql") + { + $db->modify_column($table, $column, "int", "set", "'0'"); + } + else if($db->type == "sqlite") + { + $change_column[] = "CHANGE {$column} {$column} int unsigned NOT NULL default '0'"; + } + else + { + $change_column[] = "MODIFY {$column} int unsigned NOT NULL default '0'"; + } + } + if($db->type != "pgsql") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."{$table} ".implode(", ", $change_column)); + } + } + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + $output->print_footer("30_dbchanges_smilies"); +} + +function upgrade30_dbchanges_smilies() +{ + global $cache, $output, $db; + + $output->print_header("Aktualizacja emotikon"); + + echo "

    Trwa wykonywanie aktualizacji emotikon w bazie danych...

    "; + flush(); + + if($db->type == 'pgsql') + { + $db->modify_column("smilies", "find", "text", "set"); + } + else + { + $db->modify_column("smilies", "find", "text NOT NULL"); + } + + $query = $db->simple_select('smilies', 'sid, image, find', '', array('order_by' => 'image, sid')); + $last_image = null; + $last_sid = 0; + $skip = array(); + while($smilie = $db->fetch_array($query)) + { + if(in_array($smilie['sid'], $skip)) + { + continue; + } + + if($smilie['image'] == $last_image && $smilie['image'] != null) + { + $dupe_query = $db->simple_select('smilies', 'sid, find', 'image = "'.$db->escape_string($smilie['image']).'"'); + $dupes = ''; + $find = array(); + $skip = array(); + while($dupe = $db->fetch_array($dupe_query)) + { + if($dupe['sid'] != $last_sid) + { + $dupes .= (int)$dupe['sid'].','; + $find[] = trim($dupe['find']); + $skip[] = (int)$dupe['sid']; + } + else + { + $find[] = $dupe['find']; + } + } + $dupes = rtrim($dupes, ','); + $db->delete_query('smilies', 'sid IN('.$dupes.')'); + $db->update_query('smilies', array('find' => implode("\n", $find)), 'sid = "'.(int)$last_sid.'"'); + $db->free_result($dupe_query); + } + else + { + $last_sid = $smilie['sid']; + $last_image = $smilie['image']; + } + } + + $cache->update_smilies(); + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + $output->print_footer("30_dbchanges_ip"); +} + +function upgrade30_dbchanges_ip() +{ + global $mybb, $db, $output; + + $output->print_header("Konwersja IP"); + + $ipstart = $iptable = ''; + + switch($mybb->input['iptask']) + { + case 8: + echo "

    Dodawanie indeksów w bazie (3/3)...

    "; + flush(); + + if(!$db->index_exists('users', 'lastip')) + { + // This may take a while + if($db->type == "mysql" || $db->type == "mysqli") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD INDEX lastip (lastip)"); + } + elseif($db->type == "pgsql") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD INDEX (`lastip`)"); + } + } + $next_task = 9; + break; + case 7: + echo "

    Dodawanie indeksów w bazie (2/3)...

    "; + flush(); + + if(!$db->index_exists('users', 'regip')) + { + // This may take a while + if($db->type == "mysql" || $db->type == "mysqli") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD INDEX regip (regip)"); + } + elseif($db->type == "pgsql") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD INDEX (`regip`)"); + } + } + $next_task = 8; + break; + case 6: + echo "

    Dodawanie indeksów w bazie (1/3)...

    "; + flush(); + + if(!$db->index_exists('posts', 'ipaddress')) + { + // This may take a while + if($db->type == "mysql" || $db->type == "mysqli") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts ADD INDEX ipaddress (ipaddress)"); + } + elseif($db->type == "pgsql") + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts ADD INDEX (`ipaddress`)"); + } + } + $next_task = 7; + break; + case 5: + if(!$_POST['ipspage']) + { + $ipp = 5000; + } + else + { + $ipp = $_POST['ipspage']; + } + + if($_POST['ipstart']) + { + $startat = $_POST['ipstart']; + $upper = $startat+$ipp-1; + $lower = $startat; + } + else + { + $startat = 0; + $upper = $ipp; + $lower = 0; + } + + $next_task = 5; + switch($mybb->input['iptable']) + { + case 7: + echo "

    Konwersja adresów IP użytkowników...

    "; + flush(); + $query = $db->simple_select("users", "COUNT(uid) AS ipcount"); + if($db->type == "mysql" || $db->type == "mysqli") + { + $next_task = 6; + } + else + { + $next_task = 9; + } + break; + case 6: + echo "

    Konwersja adresów IP wątków...

    "; + flush(); + $query = $db->simple_select("threadratings", "COUNT(rid) AS ipcount"); + break; + case 5: + echo "

    Konwersja adresów IP sesji...

    "; + flush(); + $query = $db->simple_select("sessions", "COUNT(sid) AS ipcount"); + break; + case 4: + echo "

    Konwersja adresów IP postów...

    "; + flush(); + $query = $db->simple_select("posts", "COUNT(pid) AS ipcount"); + break; + case 3: + echo "

    Konwersja adresów IP logów moderatorów...

    "; + flush(); + $query = $db->simple_select("moderatorlog", "COUNT(DISTINCT ipaddress) AS ipcount"); + break; + case 2: + echo "

    Konwersja adresów IP logów wiadomości...

    "; + flush(); + $query = $db->simple_select("maillogs", "COUNT(mid) AS ipcount"); + break; + default: + echo "

    Konwersja adresów IP logów administratorów...

    "; + flush(); + $query = $db->simple_select("adminlog", "COUNT(DISTINCT ipaddress) AS ipcount"); + break; + } + $cnt = $db->fetch_array($query); + + if($upper > $cnt['ipcount']) + { + $upper = $cnt['ipcount']; + } + + echo "

    Konwersja adresów IP od {$lower} do {$upper} (ÅÄ…cznie {$cnt['ipcount']})

    "; + flush(); + + $ipaddress = false; + + switch($mybb->input['iptable']) + { + case 7: + $query = $db->simple_select("users", "uid, regip, lastip", "", array('limit_start' => $lower, 'limit' => $ipp)); + break; + case 6: + $query = $db->simple_select("threadratings", "rid, ipaddress", "", array('limit_start' => $lower, 'limit' => $ipp)); + break; + case 5: + $query = $db->simple_select("sessions", "sid, ip", "", array('limit_start' => $lower, 'limit' => $ipp)); + break; + case 4: + $query = $db->simple_select("posts", "pid, ipaddress", "", array('limit_start' => $lower, 'limit' => $ipp)); + break; + case 3: + $query = $db->simple_select("moderatorlog", "DISTINCT(ipaddress)", "", array('limit_start' => $lower, 'limit' => $ipp)); + break; + case 2: + $query = $db->simple_select("maillogs", "mid, ipaddress", "", array('limit_start' => $lower, 'limit' => $ipp)); + break; + default: + $query = $db->simple_select("adminlog", "DISTINCT(ipaddress)", "", array('limit_start' => $lower, 'limit' => $ipp)); + $mybb->input['iptable'] = 1; + break; + } + while($data = $db->fetch_array($query)) + { + // Skip invalid IPs + switch($mybb->input['iptable']) + { + case 7: + $ip1 = my_inet_pton($db->unescape_binary($data['regip'])); + $ip2 = my_inet_pton($db->unescape_binary($data['lastip'])); + if($ip1 === false && $ip2 === false) + { + continue; + } + break; + case 5: + $ip = my_inet_pton($db->unescape_binary($data['ip'])); + if($ip === false) + { + continue; + } + break; + case 6: + case 4: + case 3: + case 2: + default: + $ip = my_inet_pton($db->unescape_binary($data['ipaddress'])); + if($ip === false) + { + continue; + } + break; + } + + switch($mybb->input['iptable']) + { + case 7: + $db->update_query("users", array('regip' => $db->escape_binary($ip1), 'lastip' => $db->escape_binary($ip2)), "uid = '".(int)$data['uid']."'"); + break; + case 6: + $db->update_query("threadratings", array('ipaddress' => $db->escape_binary($ip)), "rid = '".(int)$data['rid']."'"); + break; + case 5: + $db->update_query("sessions", array('ip' => $db->escape_binary($ip)), "sid = '".(int)$data['sid']."'"); + break; + case 4: + $db->update_query("posts", array('ipaddress' => $db->escape_binary($ip)), "pid = '".(int)$data['pid']."'"); + break; + case 3: + $db->update_query("moderatorlog", array('ipaddress' => $db->escape_binary($ip)), "ipaddress = '".$db->escape_string($data['ipaddress'])."'"); + break; + case 2: + $db->update_query("maillogs", array('ipaddress' => $db->escape_binary($ip)), "mid = '".(int)$data['mid']."'"); + break; + default: + $db->update_query("adminlog", array('ipaddress' => $db->escape_binary($ip)), "ipaddress = '".$db->escape_string($data['ipaddress'])."'"); + break; + } + $ipaddress = true; + } + + $remaining = $upper-$cnt['ipcount']; + if($remaining && $ipaddress) + { + $startat = $startat+$ipp; + $ipstart = ""; + $iptable = $mybb->input['iptable']; + } + else + { + $iptable = $mybb->input['iptable']+1; + } + if($iptable <= 10) + { + $iptable = ""; + } + break; + case 4: + $next_task = 4; + switch($mybb->input['iptable']) + { + case 10: + echo "

    Aktualizacja tabeli użytkowników (4/4)...

    "; + flush(); + + $table = 'users'; + $column = 'lastip'; + $next_task = 5; + break; + case 9: + echo "

    Aktualizacja tabeli użytkowników (3/4)...

    "; + flush(); + + $table = 'users'; + $column = 'regip'; + break; + case 8: + echo "

    Aktualizacja tabeli wątków...

    "; + flush(); + + $table = 'threadratings'; + $column = 'ipaddress'; + break; + case 7: + echo "

    Aktualizacja tabeli sesji...

    "; + flush(); + + $table = 'sessions'; + $column = 'ip'; + break; + case 6: + echo "

    Aktualizacja tabeli logów wyszukiwania...

    "; + flush(); + + $table = 'searchlog'; + $column = 'ipaddress'; + // Skip conversion + $db->delete_query('searchlog'); + break; + case 5: + echo "

    Aktualizacja tabeli postów (2/2)...

    "; + flush(); + + $table = 'posts'; + $column = 'ipaddress'; + break; + case 4: + echo "

    Aktualizacja tabeli logów moderatorów...

    "; + flush(); + + $table = 'moderatorlog'; + $column = 'ipaddress'; + break; + case 3: + echo "

    Aktualizacja tabeli logów wiadomości...

    "; + flush(); + + $table = 'maillogs'; + $column = 'ipaddress'; + break; + case 2: + echo "

    Aktualizacja tabeli sesji administratorów...

    "; + flush(); + + $table = 'adminsessions'; + $column = 'ip'; + // Skip conversion + $db->delete_query('adminsessions'); + break; + default: + echo "

    Aktualizacja tabeli logów administratorów...

    "; + flush(); + + $mybb->input['iptable'] = 1; + $table = 'adminlog'; + $column = 'ipaddress'; + break; + } + // Truncate invalid IPs + $db->write_query("UPDATE ".TABLE_PREFIX."{$table} SET {$column} = SUBSTR({$column}, 16) WHERE LENGTH({$column})>16"); + switch($db->type) + { + case "pgsql": + // Drop default value before converting the column + $db->modify_column($table, $column, false, false); + $db->modify_column($table, $column, "bytea USING {$column}::bytea", 'set', "''"); + break; + case "sqlite": + $db->modify_column($table, $column, "blob(16) NOT NULL default ''"); + break; + default: + $db->modify_column($table, $column, "varbinary(16) NOT NULL default ''"); + break; + } + if($mybb->input['iptable'] < 10) + { + $iptable = "input['iptable']+1)."\" />"; + } + break; + case 3: + echo "

    Aktualizacja tabeli użytkowników (2/4)...

    "; + flush(); + + if($db->field_exists('longlastip', 'users')) + { + // This may take a while + $db->drop_column("users", "longlastip"); + } + $next_task = 4; + break; + case 2: + echo "

    Aktualizacja tabeli użytkowników (1/4)...

    "; + flush(); + + if($db->field_exists('longregip', 'users')) + { + // This may take a while + $db->drop_column("users", "longregip"); + } + $next_task = 3; + break; + default: + echo "

    Aktualizacja tabeli postów (1/2)...

    "; + flush(); + + if($db->field_exists('longipaddress', 'posts')) + { + // This may take a while + $db->drop_column("posts", "longipaddress"); + } + $next_task = 2; + break; + } + + if($next_task == 9) + { + $contents = "

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "; + $nextact = "30_updatetheme"; + } + else + { + $contents = "

    {$iptable}{$ipstart}Zakończono. Naciśnij Dalej, aby kontynuować konwersję adresów IP.

    "; + + global $footer_extra; + $footer_extra = ""; + $nextact = "30_dbchanges_ip"; + } + + $output->print_contents($contents); + + $output->print_footer($nextact); +} + +function upgrade30_updatetheme() +{ + global $db, $mybb, $output, $config; + + if(file_exists(MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions_themes.php")) + { + require_once MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions_themes.php"; + } + else if(file_exists(MYBB_ROOT."admin/inc/functions_themes.php")) + { + require_once MYBB_ROOT."admin/inc/functions_themes.php"; + } + else + { + $output->print_error("Upewnij się, że katalog administracyjny (/admin) został poprawnie załadowany na serwer."); + } + + $output->print_header("Aktualizacja stylów"); + + // New default user star + $contents = "

    Aktualizacja domyślnej ikony gwiazdki... "; + $db->update_query("usergroups", array('starimage' => 'images/star.png'), "starimage='images/star.gif'"); + $contents .= "zakończono.

    "; + + $contents .= "

    Dodawanie nowego arkusza stylów... "; + + $query = $db->simple_select("themes", "*", "tid='1'"); + + $theme = $db->fetch_array($query); + $properties = my_unserialize($theme['properties']); + $stylesheets = my_unserialize($theme['stylesheets']); + + $old = array("global.css", "usercp.css", "modcp.css", "star_ratings.css"); + require_once MYBB_ROOT."inc/class_xml.php"; + $colors = @file_get_contents(INSTALL_ROOT.'resources/mybb_theme.xml'); + $parser = new XMLParser($colors); + $tree = $parser->get_tree(); + + if(is_array($tree) && is_array($tree['theme'])) + { + if(is_array($tree['theme']['stylesheets'])) + { + foreach($tree['theme']['stylesheets']['stylesheet'] as $stylesheet) + { + $new_stylesheet = array( + "name" => $db->escape_string($stylesheet['attributes']['name']), + "tid" => 1, + "attachedto" => $db->escape_string($stylesheet['attributes']['attachedto']), + "stylesheet" => $db->escape_string($stylesheet['value']), + "lastmodified" => TIME_NOW, + "cachefile" => $db->escape_string($stylesheet['attributes']['name']) + ); + + if(in_array($new_stylesheet['name'], $old)) + { + // We can update the disporder here + $properties['disporder'][$stylesheet['attributes']['name']] = $stylesheet['attributes']['disporder']; + } + else + { + // Insert new stylesheet + $sid = $db->insert_query("themestylesheets", $new_stylesheet); + $css_url = "css.php?stylesheet={$sid}"; + + $cached = cache_stylesheet($tid, $stylesheet['attributes']['name'], $stylesheet['value']); + + if($cached) + { + $css_url = $cached; + } + + // Add to display and stylesheet list + $properties['disporder'][$stylesheet['attributes']['name']] = $stylesheet['attributes']['disporder']; + $attachedto = $stylesheet['attributes']['attachedto']; + if(!$attachedto) + { + $attachedto = "global"; + } + + // private.php?compose,folders|usercp.php,global|global + $attachedto = explode("|", $attachedto); + foreach($attachedto as $attached_file) + { + $attached_actions = explode(",", $attached_file); + $attached_file = array_shift($attached_actions); + if(count($attached_actions) == 0) + { + $attached_actions = array("global"); + } + + foreach($attached_actions as $action) + { + $stylesheets[$attached_file][$action][] = $css_url; + } + } + } + } + } + } + + $update_array = array( + "properties" => $db->escape_string(serialize($properties)), + "stylesheets" => $db->escape_string(serialize($stylesheets)) + ); + + $db->update_query("themes", $update_array, "tid = '1'"); + + $contents .= "zakończono.

    "; + + $contents .= "

    Dodawanie porządku wyświetlania do wszystkich arkuszy stylów... "; + + $query = $db->simple_select("themes", "tid,properties,stylesheets"); + while($theme = $db->fetch_array($query)) + { + $properties = my_unserialize($theme['properties']); + $stylesheets = my_unserialize($theme['stylesheets']); + + // Disporder already set? + if(isset($properties['disporder']) && !empty($properties['disporder'])) + { + continue; + } + + $disporder = 1; + + // First go through all own stylesheets + $query2 = $db->simple_select("themestylesheets", "name", "tid='{$theme['tid']}'"); + while($name = $db->fetch_field($query2, "name")) + { + $properties['disporder'][$name] = $disporder; + $disporder++; + } + + // Next go through the inherited stylesheets + if(!empty($stylesheets)) + { + foreach($stylesheets as $a) + { + foreach($a as $file => $stylesheet) + { + // Don't ask me... Throws an error otherwise + if(empty($stylesheet)) + { + continue; + } + foreach($stylesheet as $s) + { + $name = pathinfo($s, PATHINFO_BASENAME); + if(empty($properties['disporder']) || !in_array($name, array_keys($properties['disporder']))) + { + $properties['disporder'][$name] = $disporder; + $disporder++; + } + } + } + } + } + + $db->update_query("themes", array("properties" => $db->escape_string(serialize($properties))), "tid='{$theme['tid']}'"); + } + + $contents .= "zakończono.

    "; + + $contents .= "

    Dodawanie domyślnych kolorów... "; + + $query = $db->simple_select("themes", "*", "tid = '2'"); + + // Someone deleted the default theme... :o + if($db->num_rows($query) != 0) + { + $theme = $db->fetch_array($query); + $properties = my_unserialize($theme['properties']); + $stylesheets = my_unserialize($theme['stylesheets']); + + $properties['editortheme'] = "mybb.css"; // New editor, so reset the theme for it + $properties['tablespace'] = 5; + $properties['borderwidth'] = 0; + // Reset the logo if it's still the default one + if($properties['logo'] == "images/logo.gif") + { + $properties['logo'] = "images/logo.png"; + } + + require_once MYBB_ROOT."inc/class_xml.php"; + $colors = @file_get_contents(INSTALL_ROOT.'resources/mybb_theme_colors.xml'); + $parser = new XMLParser($colors); + $tree = $parser->get_tree(); + + if(is_array($tree) && is_array($tree['colors'])) + { + if(is_array($tree['colors']['scheme'])) + { + foreach($tree['colors']['scheme'] as $tag => $value) + { + $exp = explode("=", $value['value']); + + $properties['colors'][$exp[0]] = $exp[1]; + } + } + + if(is_array($tree['colors']['stylesheets'])) + { + $count = count($properties['disporder']) + 1; + foreach($tree['colors']['stylesheets']['stylesheet'] as $stylesheet) + { + $new_stylesheet = array( + "name" => $db->escape_string($stylesheet['attributes']['name']), + "tid" => 2, + "attachedto" => $db->escape_string($stylesheet['attributes']['attachedto']), + "stylesheet" => $db->escape_string($stylesheet['value']), + "lastmodified" => TIME_NOW, + "cachefile" => $db->escape_string($stylesheet['attributes']['name']) + ); + + $sid = $db->insert_query("themestylesheets", $new_stylesheet); + $css_url = "css.php?stylesheet={$sid}"; + + $cached = cache_stylesheet($tid, $stylesheet['attributes']['name'], $stylesheet['value']); + + if($cached) + { + $css_url = $cached; + } + + // Add to display and stylesheet list + $properties['disporder'][$stylesheet['attributes']['name']] = $count; + $stylesheets[$stylesheet['attributes']['attachedto']]['global'][] = $css_url; + + ++$count; + } + } + + $update_array = array( + "properties" => $db->escape_string(serialize($properties)), + "stylesheets" => $db->escape_string(serialize($stylesheets)) + ); + + $db->update_query("themes", $update_array, "tid = '2'"); + } + } + + $contents .= "zakończono.

    "; + + $contents .= '

    Przebudowa pamięci podręcznej oraz zmniejszanie istniejących arkuszy stylów...

    '; + + $num_re_cached = recache_existing_styles(); + + $contents .= "Zakończono. {$num_re_cached} arkuszów stylów zostało zaktualizowanych w pamięci podręcznej."; + + echo $contents; + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + + if(!isset($config['secret_pin']) && is_writable(MYBB_ROOT."inc/config.php")) + { + $output->print_footer("30_acppin"); + } + else + { + $output->print_footer("30_done"); + } +} + +function upgrade30_acppin() +{ + global $config, $output; + + $output->print_header("Dodawanie PINu ACP"); + + echo "

    Dodaliśmy nową możliwość zabezpieczenia forum w MyBB 1.8: opcję ustawienia numeru PIN, który każdorazowo należy wpisać podczas logowania do ACP.
    \n"; + echo "Jeśli nie chcesz korzystać z tej opcji, po prostu opuść ten krok (pozostaw pole puste). PIN możesz ustawić też w późniejszym czasie (informacje o tym, jak to zrobić, znajdziesz w pomocy).

    \n"; + echo '
    +
    Konfiguracja PINu ACP
    + + + + + + + + + + +
    Numer PIN ACP
    +
    '; + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + + $output->print_footer("30_acppin_submit"); +} + +function upgrade30_acppin_submit() +{ + global $db, $mybb, $output, $config; + + $output->print_header("Zapisywanie pliku konfiguracyjnego"); + + $content = "

    Zapisywanie Twojego PINu (jeśli został wpisany) do pliku config.php... "; + + if(!is_writable(MYBB_ROOT."inc/config.php")) + { + $content .= "Błąd (config.php nie jest zapisywalny)"; + } + else if(isset($config['secret_pin'])) + { + $content .= "Pominięto (PIN został ustawiony wcześniej)"; + } + else + { + $pin = addslashes($mybb->get_input('pin')); + + $file = @fopen(MYBB_ROOT."inc/config.php", "r+"); + + $contents = ''; + while(!@feof($file)) + { + $contents .= @fread($file, 8436); + } + + $contents_temp = str_replace(array("\r", "\t", "\n", " ", "\0", "\x0B"), '', $contents); + + // Set the pointer before the closing php tag to remove it + $pos = strrpos($contents, "?>"); + if(my_substr($contents_temp, -2) == "?>") + { + @fseek($file, $pos, SEEK_SET); + } + + @fwrite($file, " +/** + * Admin CP Secret PIN + * If you wish to request a PIN + * when someone tries to login + * on your Admin CP, enter it below. + */ + +\$config['secret_pin'] = '{$pin}';"); + + @fclose($file); + + $content .= "Zakończono"; + } + + echo $content."

    "; + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + + $output->print_footer("30_done"); +} + +/** + * Re-cache the existing stylesheets so that they get minified. + * + * @return int The number of re-cached stylesheets. + */ +function recache_existing_styles() +{ + global $db; + + $query = $db->simple_select('themestylesheets', '*'); + + $num_updated = 0; + + while($stylesheet = $db->fetch_array($query)) + { + if (cache_stylesheet((int) $stylesheet['tid'], $stylesheet['name'], $stylesheet['stylesheet'])) + { + ++$num_updated; + } + } + + return $num_updated; +} diff --git a/Upload/install/resources/upgrade31.php b/Upload/install/resources/upgrade31.php new file mode 100644 index 0000000..2378599 --- /dev/null +++ b/Upload/install/resources/upgrade31.php @@ -0,0 +1,60 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +function upgrade31_dbchanges() +{ + global $db, $output; + + $output->print_header("Wykonywanie aktualizacji"); + + echo "

    Trwa wykonywanie wymaganych aktualizacji bazy danych...

    "; + flush(); + + $query = $db->simple_select("templategroups", "COUNT(*) as numexists", "prefix='sendthread'"); + if($db->fetch_field($query, "numexists") == 0) + { + $db->insert_query("templategroups", array('prefix' => 'sendthread', 'title' => '', 'isdefault' => '1')); + } + + $db->update_query('settings', array('optionscode' => 'numeric'), 'name IN (\'statslimit\', \'maxmultipagelinks\', \'deleteinvites\', \'gziplevel\', \'subforumsindex\', \'showbirthdayspostlimit\', \'threadsperpage\') AND optionscode=\'text\''); + $db->update_query('settings', array('optionscode' => 'numeric'), 'name IN (\'hottopic\', \'hottopicviews\', \'announcementlimit\', \'postsperpage\', \'threadreadcut\', \'similarityrating\', \'similarlimit\') AND optionscode=\'text\''); + $db->update_query('settings', array('optionscode' => 'numeric'), 'name IN (\'minnamelength\', \'maxnamelength\', \'minpasswordlength\', \'maxpasswordlength\', \'betweenregstime\', \'maxregsbetweentime\', \'failedcaptchalogincount\') AND optionscode=\'text\''); + $db->update_query('settings', array('optionscode' => 'numeric'), 'name IN (\'failedlogincount\', \'failedlogintime\', \'regtime\', \'maxsigimages\', \'siglength\', \'avatarsize\', \'customtitlemaxlength\') AND optionscode=\'text\''); + $db->update_query('settings', array('optionscode' => 'numeric'), 'name IN (\'minmessagelength\', \'maxmessagelength\', \'postfloodsecs\', \'postmergemins\', \'maxpostimages\', \'maxpostvideos\', \'subscribeexcerpt\') AND optionscode=\'text\''); + $db->update_query('settings', array('optionscode' => 'numeric'), 'name IN (\'wordwrap\', \'maxquotedepth\', \'polloptionlimit\', \'maxpolloptions\', \'polltimelimit\', \'maxattachments\', \'attachthumbh\') AND optionscode=\'text\''); + $db->update_query('settings', array('optionscode' => 'numeric'), 'name IN (\'attachthumbw\', \'membersperpage\', \'repsperpage\', \'maxreplength\', \'minreplength\', \'maxwarningpoints\', \'pmfloodsecs\') AND optionscode=\'text\''); + $db->update_query('settings', array('optionscode' => 'numeric'), 'name IN (\'maxpmquotedepth\', \'wolcutoffmins\', \'refreshwol\', \'prunepostcount\', \'dayspruneregistered\', \'dayspruneunactivated\', \'portal_numannouncements\') AND optionscode=\'text\''); + $db->update_query('settings', array('optionscode' => 'numeric'), 'name IN (\'portal_showdiscussionsnum\', \'searchfloodtime\', \'minsearchword\', \'searchhardlimit\', \'smilieinsertertot\', \'smilieinsertercols\', \'maxloginattempts\') AND optionscode=\'text\''); + $db->update_query('settings', array('optionscode' => 'numeric'), 'name IN (\'loginattemptstimeout\', \'contact_maxsubjectlength\', \'contact_minmessagelength\', \'contact_maxmessagelength\', \'purgespammerpostlimit\', \'purgespammerbangroup\', \'statscachetime\') AND optionscode=\'text\''); + + // Update help documents + $query = $db->simple_select('helpdocs', 'document', 'hid=\'3\''); + $helpdoc = $db->fetch_array($query); + if(my_strpos($helpdoc['document'], ';key={1}') !== false) + { + $helpdoc['document'] = str_replace(';key={1}', ';my_post_key={1}', $helpdoc['document']); + } + $db->update_query('helpdocs', array('document' => $helpdoc['document']), 'hid=\'3\''); + + $output->print_contents("

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "); + $output->print_footer("31_done"); +} diff --git a/Upload/install/resources/upgrade4.php b/Upload/install/resources/upgrade4.php new file mode 100644 index 0000000..ce2661b --- /dev/null +++ b/Upload/install/resources/upgrade4.php @@ -0,0 +1,81 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 1, + "requires_deactivated_plugins" => 1, +); + +@set_time_limit(0); + +function upgrade4_dbchanges() +{ + global $db, $output; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + + $db->write_query("UPDATE ".TABLE_PREFIX."users SET style='0' WHERE style='-1';"); + $db->write_query("UPDATE ".TABLE_PREFIX."users SET displaygroup='0' WHERE displaygroup='-1';"); + $db->write_query("UPDATE ".TABLE_PREFIX."forums SET style='0' WHERE style='-1';"); + $query = $db->simple_select("adminoptions", "uid='0'"); + $test = $db->fetch_array($query); + if(!isset($test['uid'])) + { + $db->write_query("UPDATE ".TABLE_PREFIX."adminoptions SET uid='0' WHERE uid='-1';"); + } + + if($db->field_exists('messageindex', "threads")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads DROP messageindex;"); + } + if($db->field_exists('subjectindex', "threads")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads DROP subjectindex;"); + } + if($db->field_exists('moderators', "forums")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums DROP moderators;"); + } + + if($db->field_exists('version', "templates")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."templates DROP version;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."templates ADD version varchar(20) NOT NULL default '0';"); + + if($db->field_exists('status', "templates")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."templates DROP status;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."templates ADD status varchar(10) NOT NULL default '';"); + + if($db->field_exists('dateline', "templates")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."templates DROP dateline;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."templates ADD dateline int(10) NOT NULL default '0';"); + + $db->write_query("UPDATE ".TABLE_PREFIX."templates SET version='100.06' WHERE sid>0"); + + echo "Zakończono

    "; + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("4_done"); +} + diff --git a/Upload/install/resources/upgrade5.php b/Upload/install/resources/upgrade5.php new file mode 100644 index 0000000..ce3d965 --- /dev/null +++ b/Upload/install/resources/upgrade5.php @@ -0,0 +1,620 @@ + 1, + "revert_all_themes" => 1, + "revert_all_settings" => 2, + "requires_deactivated_plugins" => 1, +); + +@set_time_limit(0); + +function upgrade5_dbchanges() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users CHANGE avatartype avatartype varchar(10) NOT NULL;"); + if($db->field_exists('totalpms', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP totalpms;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD totalpms int(10) NOT NULL default '0' AFTER showcodebuttons;"); + + + if($db->field_exists('newpms', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP newpms;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD newpms int(10) NOT NULL default '0' AFTER totalpms;"); + + + if($db->field_exists('unreadpms', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP unreadpms;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD unreadpms int(10) NOT NULL default '0' AFTER newpms;"); + + + if($db->field_exists('showredirect', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP showredirect;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD showredirect char(3) NOT NULL default '' AFTER showquickreply;"); + + + if($db->field_exists('avatardimensions', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP avatardimensions;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users ADD avatardimensions varchar(10) NOT NULL default '' AFTER avatar;"); + + + if($db->field_exists('unapprovedposts', "threads")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads DROP unapprovedposts;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads ADD unapprovedposts INT(10) unsigned NOT NULL default '0' AFTER visible;"); + + + if($db->field_exists('unapprovedthreads', "forums")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums DROP unapprovedthreads;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums ADD unapprovedthreads INT(10) unsigned NOT NULL default '0' AFTER rules;"); + + + if($db->field_exists('unapprovedposts', "forums")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums DROP unapprovedposts;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums ADD unapprovedposts INT(10) unsigned NOT NULL default '0' AFTER rules;"); + + + if($db->field_exists('defaultdatecut', "forums")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums DROP defaultdatecut;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums ADD defaultdatecut smallint(4) unsigned NOT NULL default '0' AFTER unapprovedposts;"); + + + if($db->field_exists('defaultsortby', "forums")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums DROP defaultsortby;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums ADD defaultsortby varchar(10) NOT NULL default '' AFTER defaultdatecut;"); + + + if($db->field_exists('defaultsortorder', "forums")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums DROP defaultsortorder;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums ADD defaultsortorder varchar(4) NOT NULL default '' AFTER defaultsortby;"); + + + if($db->field_exists('lastposteruid', "forums")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums DROP lastposteruid;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums ADD lastposteruid int(10) unsigned NOT NULL default '0' AFTER lastposter;"); + + + if($db->field_exists('lastpostsubject', "forums")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums DROP lastpostsubject;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forums ADD lastpostsubject varchar(120) NOT NULL default '' AFTER lastposttid"); + + + if($db->field_exists('lastposteruid', "threads")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads DROP lastposteruid;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads ADD lastposteruid int unsigned NOT NULL default '0' AFTER lastposter"); + + + if($db->field_exists('canmanagemembers', "groupleaders")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."groupleaders DROP canmanagemembers;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."groupleaders ADD canmanagemembers char(3) NOT NULL default '' AFTER uid;"); + + + if($db->field_exists('canmanagerequests', "groupleaders")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."groupleaders DROP canmanagerequests;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."groupleaders ADD canmanagerequests char(3) NOT NULL default '' AFTER canmanagemembers;"); + + + if($db->field_exists('caneditlangs', "adminoptions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminoptions DROP caneditlangs;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminoptions ADD caneditlangs char(3) NOT NULL default '' AFTER canedithelp;"); + + + if($db->field_exists('canrundbtools', "adminoptions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminoptions DROP canrundbtools;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."adminoptions ADD canrundbtools char(3) NOT NULL default ''"); + + + if($db->field_exists('allowedgroups', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP allowedgroups;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes ADD allowedgroups text NOT NULL AFTER extracss;"); + + + if($db->field_exists('canmovetononmodforum', "moderators")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."moderators DROP canmovetononmodforum;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."moderators ADD canmovetononmodforum char(3) NOT NULL default '' AFTER canmanagethreads;"); + + + if($db->field_exists('csscached', "themes")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes DROP csscached;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."themes ADD csscached bigint(30) NOT NULL default '0'"); + + + $db->write_query("UPDATE ".TABLE_PREFIX."adminoptions SET caneditlangs='yes' WHERE canrunmaint='yes'"); + $db->write_query("UPDATE ".TABLE_PREFIX."adminoptions SET caneditlangs='no' WHERE canrunmaint='no'"); + $db->write_query("UPDATE ".TABLE_PREFIX."adminoptions SET canrundbtools='yes' WHERE canrunmaint='yes'"); + $db->write_query("UPDATE ".TABLE_PREFIX."adminoptions SET canrundbtools='no' WHERE canrunmaint='no'"); + $db->write_query("UPDATE ".TABLE_PREFIX."settings SET optionscode='select\r\ninstant=Instant Activation\r\nverify=Send Email Verification\r\nrandompass=Send Random Password\r\nadmin=Administrator Activation' WHERE name = 'regtype'"); + $db->write_query("UPDATE ".TABLE_PREFIX."users SET totalpms='-1', newpms='-1', unreadpms='-1'"); + $db->write_query("UPDATE ".TABLE_PREFIX."settings SET name='maxmessagelength' WHERE name='messagelength'"); + + $collation = $db->build_create_table_collation(); + + $db->drop_table("mycode"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."mycode ( + cid int unsigned NOT NULL auto_increment, + title varchar(100) NOT NULL default '', + description text NOT NULL, + regex text NOT NULL, + replacement text NOT NULL, + active char(3) NOT NULL default '', + PRIMARY KEY(cid) + ) ENGINE=MyISAM{$collation};"); + + $db->drop_table("templategroups"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."templategroups ( + gid int unsigned NOT NULL auto_increment, + prefix varchar(50) NOT NULL default '', + title varchar(100) NOT NULL default '', + PRIMARY KEY (gid) + ) ENGINE=MyISAM{$collation};"); + + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('1','calendar','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('2','editpost','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('3','email','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('4','emailsubject','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('5','forumbit','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('6','forumjump','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('7','forumdisplay','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('8','index','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('9','error','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('10','memberlist','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('11','multipage','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('12','private','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('13','portal','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('14','postbit','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('15','redirect','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('16','showthread','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('17','usercp','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('18','online','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('19','moderation','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('20','nav','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('21','search','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('22','showteam','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('23','reputation','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('24','newthread','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('25','newreply','');"); + $db->write_query("INSERT INTO ".TABLE_PREFIX."templategroups (gid,prefix,title) VALUES ('26','member','');"); + + $db->drop_table("searchlog"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."searchlog ( + sid varchar(32) NOT NULL default '', + uid int unsigned NOT NULL default '0', + dateline bigint(30) NOT NULL default '0', + ipaddress varchar(120) NOT NULL default '', + threads text NOT NULL, + posts text NOT NULL, + searchtype varchar(10) NOT NULL default '', + resulttype varchar(10) NOT NULL default '', + querycache text NOT NULL, + keywords text NOT NULL, + PRIMARY KEY (sid) + ) ENGINE=MyISAM{$collation};"); + + $db->write_query("UPDATE ".TABLE_PREFIX."settings SET name='bannedemails' WHERE name='emailban' LIMIT 1"); + $db->write_query("UPDATE ".TABLE_PREFIX."settings SET name='bannedips' WHERE name='ipban' LIMIT 1"); + + $query = $db->simple_select("settings", "value", "name='bannedusernames'"); + $bannedusernames = $db->fetch_field($query, 'sid'); + $bannedusernames = explode(" ", $bannedusernames); + $bannedusernames = implode(",", $bannedusernames); + $query = $db->write_query("UPDATE ".TABLE_PREFIX."settings SET value='".$db->escape_string($bannedusernames)."' WHERE name='bannedusernames'"); + + $query = $db->simple_select("settings", "value", "name='bannedemails'"); + $bannedemails = $db->fetch_field($query, 'sid'); + $bannedemails = explode(" ", $bannedemails); + $bannedemails = implode(",", $bannedemails); + $query = $db->write_query("UPDATE ".TABLE_PREFIX."settings SET value='".$db->escape_string($bannedemails)."' WHERE name='bannedemails'"); + + $query = $db->simple_select("settings", "value", "name='bannedips'"); + $bannedips = $db->fetch_field($query, 'sid'); + $bannedips = explode(" ", $bannedips); + $bannedips = implode(",", $bannedips); + $db->update_query("settings", array('value' => $db->escape_string($bannedips)), "name='bannedips'"); + + $db->drop_table("reputation"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."reputation ( + rid int unsigned NOT NULL auto_increment, + uid int unsigned NOT NULL default '0', + adduid int unsigned NOT NULL default '0', + reputation bigint(30) NOT NULL default '0', + dateline bigint(30) NOT NULL default '0', + comments text NOT NULL, + PRIMARY KEY(rid) + ) ENGINE=MyISAM{$collation};"); + + $db->drop_table("mailqueue"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."mailqueue ( + mid int unsigned NOT NULL auto_increment, + mailto varchar(200) NOT NULL, + mailfrom varchar(200) NOT NULL, + subject varchar(200) NOT NULL, + message text NOT NULL, + headers text NOT NULL, + PRIMARY KEY(mid) + ) ENGINE=MyISAM{$collation};"); + + $db->update_query("users", array('reputation' => 0)); + + $db->update_query("usergroups", array('reputationpower' => 1)); + $db->update_query("usergroups", array('reputationpower' => 2), "cancp='yes'"); + + if($db->field_exists('rating', "users")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."users DROP rating;"); + } + + if($db->field_exists('attachmentcount', "threads")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads DROP attachmentcount;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads ADD attachmentcount int(10) unsigned NOT NULL default '0'"); + + + if($db->field_exists('posthash', "posts")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts DROP posthash;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."posts ADD posthash varchar(32) NOT NULL default '' AFTER visible"); + + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."attachtypes CHANGE extension extension varchar(10) NOT NULL;"); + + if($db->field_exists('deletetime', "threads")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads DROP deletetime;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."threads ADD deletetime int(10) unsigned NOT NULL default '0' AFTER attachmentcount"); + + + if($db->field_exists('loginattempts', "sessions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."sessions DROP loginattempts;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."sessions ADD loginattempts tinyint(2) NOT NULL default '1'"); + + + if($db->field_exists('failedlogin', "sessions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."sessions DROP failedlogin;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."sessions ADD failedlogin bigint(30) NOT NULL default '0'"); + + + if($db->field_exists('canviewthreads', "usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups DROP canviewthreads;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups ADD canviewthreads char(3) NOT NULL default '' AFTER canview"); + + + if($db->field_exists('canviewthreads', "forumpermissions")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forumpermissions DROP canviewthreads;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."forumpermissions ADD canviewthreads char(3) NOT NULL default '' AFTER canview"); + + + $db->drop_table("captcha"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."captcha ( + imagehash varchar(32) NOT NULL default '', + imagestring varchar(8) NOT NULL default '', + dateline bigint(30) NOT NULL default '0' + ) ENGINE=MyISAM{$collation};"); + + if($db->field_exists('data', "moderatorlog")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."moderatorlog DROP data;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."moderatorlog ADD data text NOT NULL AFTER action;"); + + + $db->drop_table("adminsessions"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."adminsessions ( + sid varchar(32) NOT NULL default '', + uid int unsigned NOT NULL default '0', + loginkey varchar(50) NOT NULL default '', + ip varchar(40) NOT NULL default '', + dateline bigint(30) NOT NULL default '0', + lastactive bigint(30) NOT NULL default '0' + ) ENGINE=MyISAM{$collation};"); + + $db->drop_table("modtools"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."modtools ( + tid smallint unsigned NOT NULL auto_increment, + name varchar(200) NOT NULL, + description text NOT NULL, + forums text NOT NULL, + type char(1) NOT NULL default '', + postoptions text NOT NULL, + threadoptions text NOT NULL, + PRIMARY KEY (tid) + ) ENGINE=MyISAM{$collation};"); + + if($db->field_exists('disporder', "usergroups")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups DROP disporder;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."usergroups ADD disporder smallint(6) NOT NULL default '0' AFTER image"); + + + $db->write_query("UPDATE ".TABLE_PREFIX."usergroups SET canviewthreads=canview"); + $db->write_query("UPDATE ".TABLE_PREFIX."forumpermissions SET canviewthreads=canview"); + + $contents .= "Zakończono

    "; + $contents .= "

    Naciśnij przycisk Dalej, aby kontynouwać proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("5_redoconfig"); +} + +function upgrade5_redoconfig() +{ + global $db, $output, $config, $mybb; + $output->print_header("Tworzenie nowego pliku config.php"); + + $uid = 0; + if($mybb->input['username'] != '' && !$mybb->input['uid']) + { + $user = get_user_by_username($mybb->input['username']); + + $uid = (int)$user['uid']; + + if(!$uid) + { + echo "

    Wpisany login nie został odnaleziony.
    Upewnij się, że wpisano poprawny login.

    "; + } + } + else if($mybb->input['uid']) + { + $uid = $mybb->input['uid']; + } + + if(!$uid) + { + echo "

    Wpisz login głównego administratora. Identyfikator tego użytkownika zostanie zapisany w pliku konfiguracyjnym. Zapobiegnie to zbanowaniu, zmianie danych lub usunięciu tego konta przez innego administratora.

    "; + echo "

    Login:

    "; + echo "

    "; + $output->print_footer("5_redoconfig"); + exit; + } + + $fh = @fopen(MYBB_ROOT."inc/config.php", "w"); + if(!$fh) + { + echo "

    Nie można otworzyć pliku inc/config.php
    Przed rozpoczęciem procesu aktualizacji należy zmienić uprawnienia pliku inc/config.php tak, aby skrypt aktualizacji mógł zapisywać do tego pliku.

    "; + $output->print_footer("5_redoconfig"); + exit; + } + + if(!$config['admindir']) + { + $config['admindir'] = "admin"; + } + + if(!$config['cachestore']) + { + $config['cachestore'] = "db"; + } + $configdata = ""; + + fwrite($fh, $configdata); + fclose($fh); + echo "

    Nowy plik konfiguracyjny został pomyślnie zapisany.

    "; + echo "

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_footer("5_lastposts"); + +} + +function upgrade5_lastposts() +{ + global $db, $output; + $output->print_header("Przebudowywanie informacji o ostatnich postach"); + + if(!$_POST['tpp']) + { + echo "

    Nastęnym krokiem w aktualizacji jest przebudowanie informacji o ostatnim poście w każdym wątku na Twoim forum. Wpisz w poniższe pole ilość wpisów, które mają zostać przetworzone na stronę.

    "; + echo "

    Wpisów na stronę:

    "; + echo "

    Jeżeli wszystko gotowe, naciśnij przycisk Dalej, aby rozpocząć proces przebudowy.

    "; + $output->print_footer("5_lastposts"); + } + else + { + require_once MYBB_ROOT."inc/functions_rebuild.php"; + + $query = $db->simple_select("threads", "COUNT(*) as num_threads", "closed NOT LIKE 'moved|%'"); + $num_threads = $db->fetch_field($query, 'num_threads'); + $tpp = (int)$_POST['tpp']; + $start = (int)$_POST['start']; + $end = $start+$tpp; + if($end > $num_threads) + { + $end = $num_threads; + } + echo "

    Aktualizacja {$start} do {$end} z {$num_threads}...

    "; + + $query = $db->simple_select("threads", "tid, firstpost", "closed NOT LIKE 'moved|%'", array("order_by" => "tid", "order_dir" => "asc", "limit" => $tpp, "limit_start" => $start)); + + while($thread = $db->fetch_array($query)) + { + rebuild_thread_counters($thread['tid']); + if($thread['firstpost'] == 0) + { + update_first_post($thread['tid']); + } + } + echo "

    Zakończono

    "; + if($end >= $num_threads) + { + echo "

    Proces przebudowy został pomyślnie zakończony. Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji."; + $output->print_footer("5_forumlastposts"); + } + else + { + echo "

    Naciśnij przycisk Dalej, aby kontynuować proces przebudowy.

    "; + echo ""; + echo ""; + $output->print_footer("5_lastposts"); + } + } +} + +function upgrade5_forumlastposts() +{ + global $db, $output; + $output->print_header("Przebudowywanie ostatnich postów na forum"); + echo "

    Trwa przebudowywanie informacji o ostatnich postach na forum...

    "; + $query = $db->simple_select("forums", "fid"); + while($forum = $db->fetch_array($query)) + { + update_forum_lastpost($forum['fid']); + } + echo "

    Zakończono"; + echo "

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_footer("5_indexes"); +} + +function upgrade5_indexes() +{ + global $db, $output; + + $output->print_header("Indeksowanie"); + echo "

    Trwa sprawdzanie i tworzenie indeksów bazy danych...

    "; + + + if($db->is_fulltext("threads", "subject")) + { + $db->drop_index("threads", "subject"); + } + if($db->is_fulltext("threads", "subject_2")) + { + $db->drop_index("threads", "subject_2"); + } + + if($db->supports_fulltext("threads")) + { + $db->create_fulltext_index("threads", "subject"); + } + if($db->supports_fulltext_boolean("posts")) + { + if(!$db->is_fulltext("posts", "message")) + { + $db->create_fulltext_index("posts", "message"); + } + } + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("5_done"); +} diff --git a/Upload/install/resources/upgrade6.php b/Upload/install/resources/upgrade6.php new file mode 100644 index 0000000..9bd0c9e --- /dev/null +++ b/Upload/install/resources/upgrade6.php @@ -0,0 +1,41 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0, + "requires_deactivated_plugins" => 0, +); + +@set_time_limit(0); + +function upgrade6_dbchanges() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + + $db->write_query("ALTER TABLE ".TABLE_PREFIX."mycode CHANGE regex regex text NOT NULL"); + $db->write_query("ALTER TABLE ".TABLE_PREFIX."mycode CHANGE replacement replacement text NOT NULL"); + + $contents = "Zakończono

    "; + $contents .= "

    Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("6_done"); +} + diff --git a/Upload/install/resources/upgrade7.php b/Upload/install/resources/upgrade7.php new file mode 100644 index 0000000..04b0bb6 --- /dev/null +++ b/Upload/install/resources/upgrade7.php @@ -0,0 +1,26 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0, + "requires_deactivated_plugins" => 0, +); + +@set_time_limit(0); + +/* Nothing to do from 1.2.1 to 1.2.2 */ + diff --git a/Upload/install/resources/upgrade8.php b/Upload/install/resources/upgrade8.php new file mode 100644 index 0000000..a0167a8 --- /dev/null +++ b/Upload/install/resources/upgrade8.php @@ -0,0 +1,50 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0, + "requires_deactivated_plugins" => 0, +); + +@set_time_limit(0); + +function upgrade8_dbchanges() +{ + global $db, $output, $mybb; + + $output->print_header("Wykonywanie zapytań"); + + echo "

    Trwa wykonywanie wymaganych zapytań do bazy danych...

    "; + + if($db->field_exists('oldadditionalgroups', "banned")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."banned DROP oldadditionalgroups;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."banned ADD oldadditionalgroups TEXT NOT NULL AFTER oldgroup"); + + + if($db->field_exists('olddisplaygroup', "banned")) + { + $db->write_query("ALTER TABLE ".TABLE_PREFIX."banned DROP olddisplaygroup;"); + } + $db->write_query("ALTER TABLE ".TABLE_PREFIX."banned ADD olddisplaygroup int NOT NULL default '0' AFTER oldadditionalgroups"); + + $contents .= "Naciśnij przycisk Dalej, aby kontynuować proces aktualizacji.

    "; + $output->print_contents($contents); + $output->print_footer("8_done"); +} + diff --git a/Upload/install/resources/upgrade9.php b/Upload/install/resources/upgrade9.php new file mode 100644 index 0000000..02482a3 --- /dev/null +++ b/Upload/install/resources/upgrade9.php @@ -0,0 +1,25 @@ + 0, + "revert_all_themes" => 0, + "revert_all_settings" => 0 +); + +@set_time_limit(0); + +/* Nothing to do from 1.2.3 to 1.2.7 */ + diff --git a/Upload/install/resources/usergroups.xml b/Upload/install/resources/usergroups.xml new file mode 100644 index 0000000..c3a429a --- /dev/null +++ b/Upload/install/resources/usergroups.xml @@ -0,0 +1,613 @@ + + + + + + <![CDATA[Goście]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <![CDATA[Zarejestrowani]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <![CDATA[Moderatorzy globalni]]> + + {username}]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <![CDATA[Administratorzy]]> + + {username}]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <![CDATA[Nieaktywowani]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <![CDATA[Moderatorzy]]> + + {username}]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <![CDATA[Zbanowani]]> + + {username}]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Upload/install/stylesheet.css b/Upload/install/stylesheet.css new file mode 100644 index 0000000..803b4c7 --- /dev/null +++ b/Upload/install/stylesheet.css @@ -0,0 +1,387 @@ +/** + * MyBB Installer CSS + * (c) 2014 MyBB Group + */ + +body { + font-family: 'Lucida Grande', Tahoma, Verdana, Arial, sans-serif; + font-size: 12px; + background: #fff; + color: #333; + margin: 0; +} + +a { + color: #035488; + text-decoration: none; +} + +a:hover { + color: #444; + text-decoration: underline; +} + +#container { + margin: auto auto; + width: 880px; +} + +/* Logo */ +#logo h1 { + background: #fff url('images/logo.png') no-repeat 0 5px; + height: 82px; + margin: 0 0 2px 0; + padding: 3px; +} + +/* Header */ +#header { + clear: both; + background: #efefef; + border-top: 1px solid #ccc; + border-bottom: 1px solid #ccc; + padding: 12px; + font-size: 20px; + color: #444; + margin-bottom: 20px; +} + +/* Inner Container */ +#inner_container { + background: #fff; +} + +/* Progress Side bar */ +#progress { + width: 230px; + float: left; + margin: 0; + padding: 10px 0 0 5px; + padding-right: 0px; + font-size: 11px; + border-right: 1px solid #e7e7e7; +} +#progress ul { + list-style: none; + padding: 0 0 0 10px; + margin: 0; +} + +#progress li { + color: #888; + font-weight: normal; + margin: 4px 0 12px; + padding: 2px 0 1px 24px; + background-image: url("images/inactive.png"); + background-position: 0 0; + background-repeat: no-repeat; +} + +#progress li.active { + background-image: url("images/active.png"); + color: #333; + padding-top: 0; + font-size: 14px; + font-weight: bold; +} + +#progress li.intro { + background-position: 0 -20px; +} + +#progress li.license { + background-position: 0 -40px; +} + +#progress li.requirements_check { + background-position: 0 -60px; +} + +#progress li.database_info { + background-position: 0 -80px; +} + +#progress li.create_tables { + background-position: 0 -100px; +} + +#progress li.populate_tables { + background-position: 0 -120px; +} + +#progress li.templates { + background-position: 0 -140px; +} + +#progress li.configuration { + background-position: 0 -160px; +} + +#progress li.adminuser { + background-position: 0 -180px; +} + +#progress li.final { + background-position: 0 -200px; +} + +/* Content Area */ +#content { + margin-left: 235px; + width: 580px; + padding: 10px 20px 0 30px; + border-left: 1px solid #e7e7e7; +} + +* html #content { + width: 580px; +} + +/* Heading Styles */ +h2 { + margin: 0; + font-size: 20px; + padding-bottom: 5px; + border-bottom: 1px dotted #ccc; +} + +h3 { + font-size: 14px; + margin: 5px 0; +} + +h4 { + font-size: 12px; + margin: 5px 0; +} + +/* License Agreement */ +.license_agreement { + margin: 10px auto; + padding: 10px; + overflow: scroll; + height: 400px; + width: 560px; + border: 1px solid #ccc; +} + +.license_agreement ul { + padding: 0; + margin: 15px; +} + +/* Next Button */ +#next_button, .next_button { + text-align: right; + width: auto; +} + +/* Footer */ +#footer { + clear: both; + background: #f5f5f5; + margin-top: 20px; + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + padding: 8px; + font-size: 11px; + text-align: right; + vertical-align: middle; + color: #666; + margin-bottom: 20px; +} + +/* Tables */ +.border_wrapper { + margin: 0; + padding: 1px; + margin-top: 14px; + border-top: 0; + border: 1px solid #ccc; + border-radius: 6px; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; +} + +.border_wrapper div.title { + background: #0066a2 url(images/thead.png) top left repeat-x; + color: #fff; + border-bottom: 1px solid #263c30; + padding: 8px; + font-weight: bold; + text-align: left; + font-size: 120%; + border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + -webkit-border-radius: 5px 5px 0 0; +} + +.border_wrapper div.title a { + color: #fff; + text-decoration: none; +} + +table.general { + background: #ccc; + width: 100%; +} + +table.general td { + border-top: 1px solid #fafafa; + border-bottom: 1px solid #ccc; + border-right: 1px solid #ccc; + border-left: 1px solid #fafafa; +} + +table.general tr td:last-child { + border-right: 0; +} + +table.general tr td:first-child { + border-left: 0; +} + +table.general tr:last-child td { + border-bottom: 0; +} + +table.bottom_cell_border td { + border-right: 0; + border-left: 0; +} + +table.general tr.last td { + border-bottom: 0; +} + +table.bottom_cell_border td { + border-right: 0; + border-left: 0; +} + +table.general td { + background: #f5f5f5; + padding: 6px; + vertical-align: top; +} + +table.general th { + background: #0f0f0f url(images/tcat.png) repeat-x; + color: #fff; + border-top: 1px solid #444; + border-bottom: 1px solid #000; + padding: 8px; + font-size: 96%; + font-weight: bold; + text-align: left; +} + +table.general th a, table.general th { + color: #fff; + text-decoration: none; +} + +table .alt_row td { + background: #f1f1f1; +} + +/* Forms */ +input.text_input { + border: 1px solid #aaa; + width: 300px; + padding: 4px; + font-size: 13px; + font-family: 'Lucida Grande', Tahoma, Verdana, Arial, sans-serif; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + outline: 0; +} + +select { + border: 1px solid #aaa; + padding: 4px; + font-size: 12px; + font-family: 'Lucida Grande', Tahoma, Verdana, Arial, sans-serif; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + outline: 0; +} + +input.text_input:focus, select:focus { + border: 1px solid #777; +} + +input.submit_button { + border: 1px solid #999; + padding: 4px 7px; + background: #e3e3e3 url(images/submit_bg.png) repeat-x top; + color: #444; + font-weight: bold; + font-family: 'Lucida Grande', Tahoma, Verdana, Arial, sans-serif; + margin-right: 3px; + font-size: 1.1em; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + margin-top: 4px; + margin-right: 3px; +} + +input.submit_button:hover { + border: 1px solid #666; + cursor: pointer; +} + +label { + font-weight: bold; +} + +.field_description, small { + color: #444; + font-size: 11px; +} + +/* Misc */ +.invisible { + display: none; +} + +.pass { + color: green; +} + +.fail { + color: red; +} + +.error { + background: #FFF6BF; + border: 1px solid #FFD324; + margin: 10px auto; + padding: 5px 10px 10px 10px; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.error p { + margin-bottom: 0; +} + +.success { + background: #D6ECA6; + border: 1px solid #8DC93E; + text-align: center; + margin: 10px auto; + padding: 10px; + font-weight: bold; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.upgrade_note { + background: #efefef; +} \ No newline at end of file diff --git a/Upload/install/upgrade.php b/Upload/install/upgrade.php new file mode 100644 index 0000000..6e59ef4 --- /dev/null +++ b/Upload/install/upgrade.php @@ -0,0 +1,1094 @@ + $config['dbtype'], + "database" => $config['database'], + "table_prefix" => $config['table_prefix'], + "hostname" => $config['hostname'], + "username" => $config['username'], + "password" => $config['password'], + "encoding" => $config['db_encoding'], + ); +} +$mybb->config = &$config; + +// Include the files necessary for installation +require_once MYBB_ROOT."inc/class_timers.php"; +require_once MYBB_ROOT."inc/class_xml.php"; +require_once MYBB_ROOT.'inc/class_language.php'; + +$lang = new MyLanguage(); +$lang->set_path(MYBB_ROOT.'install/resources/'); +$lang->load('language'); + +// If we're upgrading from an SQLite installation, make sure we still work. +if($config['database']['type'] == 'sqlite3' || $config['database']['type'] == 'sqlite2') +{ + $config['database']['type'] = 'sqlite'; +} + +require_once MYBB_ROOT."inc/db_{$config['database']['type']}.php"; +switch($config['database']['type']) +{ + case "sqlite": + $db = new DB_SQLite; + break; + case "pgsql": + $db = new DB_PgSQL; + break; + case "mysqli": + $db = new DB_MySQLi; + break; + default: + $db = new DB_MySQL; +} + +// Connect to Database +define('TABLE_PREFIX', $config['database']['table_prefix']); +$db->connect($config['database']); +$db->set_table_prefix(TABLE_PREFIX); +$db->type = $config['database']['type']; + +// Load Settings +if(file_exists(MYBB_ROOT."inc/settings.php")) +{ + require_once MYBB_ROOT."inc/settings.php"; +} + +if(!file_exists(MYBB_ROOT."inc/settings.php") || !$settings) +{ + if(function_exists('rebuild_settings')) + { + rebuild_settings(); + } + else + { + $options = array( + "order_by" => "title", + "order_dir" => "ASC" + ); + + $query = $db->simple_select("settings", "value, name", "", $options); + + $settings = array(); + while($setting = $db->fetch_array($query)) + { + $setting['value'] = str_replace("\"", "\\\"", $setting['value']); + $settings[$setting['name']] = $setting['value']; + } + } +} + +$settings['wolcutoff'] = $settings['wolcutoffmins']*60; +$settings['bbname_orig'] = $settings['bbname']; +$settings['bbname'] = strip_tags($settings['bbname']); + +// Fix for people who for some specify a trailing slash on the board URL +if(substr($settings['bburl'], -1) == "/") +{ + $settings['bburl'] = my_substr($settings['bburl'], 0, -1); +} + +$mybb->settings = &$settings; +$mybb->parse_cookies(); + +require_once MYBB_ROOT."inc/class_datacache.php"; +$cache = new datacache; + +// Load cache +$cache->cache(); + +$mybb->cache = &$cache; + +require_once MYBB_ROOT."inc/class_session.php"; +$session = new session; +$session->init(); +$mybb->session = &$session; + +// Include the necessary contants for installation +$grouppermignore = array("gid", "type", "title", "description", "namestyle", "usertitle", "stars", "starimage", "image"); +$groupzerogreater = array("pmquota", "maxpmrecipients", "maxreputationsday", "attachquota", "maxemails", "maxwarningsday", "maxposts", "edittimelimit", "canusesigxposts", "maxreputationsperthread"); +$displaygroupfields = array("title", "description", "namestyle", "usertitle", "stars", "starimage", "image"); +$fpermfields = array("canview", "candlattachments", "canpostthreads", "canpostreplys", "canpostattachments", "canratethreads", "caneditposts", "candeleteposts", "candeletethreads", "caneditattachments", "canpostpolls", "canvotepolls", "cansearch"); + +// Include the installation resources +require_once INSTALL_ROOT."resources/output.php"; +$output = new installerOutput; +$output->script = "upgrade.php"; +$output->title = "Kreator aktualizacji MyBB"; + +if(file_exists("lock")) +{ + $output->print_error($lang->locked); +} +else +{ + $mybb->input['action'] = $mybb->get_input('action'); + if($mybb->input['action'] == "logout" && $mybb->user['uid']) + { + // Check session ID if we have one + if($mybb->get_input('logoutkey') != $mybb->user['logoutkey']) + { + $output->print_error("Twój ID nie może zostać zweryfikowany i nie można dokonać wylogowania. Być może szkodliwy kod JavaScript próbuje wylogować Cię automatycznie. Jeżeli chcesz się wylogować, kliknij łącze \"Wyloguj\" u góry strony."); + } + + my_unsetcookie("mybbuser"); + my_unsetcookie("sid"); + if($mybb->user['uid']) + { + $time = TIME_NOW; + $lastvisit = array( + "lastactive" => $time-900, + "lastvisit" => $time, + ); + $db->update_query("users", $lastvisit, "uid='".$mybb->user['uid']."'"); + $db->delete_query("sessions", "sid='".$session->sid."'"); + } + header("Location: upgrade.php"); + } + else if($mybb->input['action'] == "do_login" && $mybb->request_method == "post") + { + require_once MYBB_ROOT."inc/functions_user.php"; + + if(!username_exists($mybb->get_input('username'))) + { + $output->print_error("Wpisany login jest niepoprawny."); + } + $options = array( + 'fields' => array('username', 'password', 'salt', 'loginkey') + ); + $user = get_user_by_username($mybb->get_input('username'), $options); + + if(!$user['uid']) + { + $output->print_error("Wpisany login jest niepoprawny."); + } + else + { + $user = validate_password_from_uid($user['uid'], $mybb->get_input('password'), $user); + if(!$user['uid']) + { + $output->print_error("Wpisane hasło jest nieprawidłowe. Jeżeli nie pamiętasz swojego hasła, kliknij tutaj, aby je odzyskać i spróbuj ponownie."); + } + } + + $db->delete_query("sessions", "ip='".$db->escape_string($session->ipaddress)."' AND sid != '".$session->sid."'"); + + $newsession = array( + "uid" => $user['uid'] + ); + + $db->update_query("sessions", $newsession, "sid='".$session->sid."'"); + + // Temporarily set the cookie remember option for the login cookies + $mybb->user['remember'] = $user['remember']; + + my_setcookie("mybbuser", $user['uid']."_".$user['loginkey'], null, true); + my_setcookie("sid", $session->sid, -1, true); + + header("Location: ./upgrade.php"); + } + + $output->steps = array($lang->upgrade); + + if($mybb->user['uid'] == 0) + { + $output->print_header($lang->please_login, "errormsg", 0, 1); + + $output->print_contents('

    '.$lang->login_desc.'

    +
    +
    + + + + + + + + + + + + + + + + +
    '.$lang->login.'
    '.$lang->login_username.':
    '.$lang->login_password.':
    '.$lang->login_password_desc.'
    +
    +
    + + +
    +
    '); + $output->print_footer(""); + + exit; + } + else if($mybb->usergroup['cancp'] != 1 && $mybb->usergroup['cancp'] != 'yes') + { + $output->print_error($lang->sprintf($lang->no_permision, $mybb->user['logoutkey'])); + } + + if(!$mybb->input['action'] || $mybb->input['action'] == "intro") + { + $output->print_header(); + + if($db->table_exists("upgrade_data")) + { + $db->drop_table("upgrade_data"); + } + $db->write_query("CREATE TABLE ".TABLE_PREFIX."upgrade_data ( + title varchar(30) NOT NULL, + contents text NOT NULL, + UNIQUE (title) + );"); + + $dh = opendir(INSTALL_ROOT."resources"); + + $upgradescripts = array(); + while(($file = readdir($dh)) !== false) + { + if(preg_match("#upgrade([0-9]+).php$#i", $file, $match)) + { + $upgradescripts[$match[1]] = $file; + $key_order[] = $match[1]; + } + } + closedir($dh); + natsort($key_order); + $key_order = array_reverse($key_order); + + // Figure out which version we last updated from (as of 1.6) + $version_history = $cache->read("version_history"); + + // If array is empty then we must be upgrading to 1.6 since that's when this feature was added + if(empty($version_history)) + { + $next_update_version = 17; // 16+1 + } + else + { + $next_update_version = (int)(end($version_history)+1); + } + + $vers = ''; + foreach($key_order as $k => $key) + { + $file = $upgradescripts[$key]; + $upgradescript = file_get_contents(INSTALL_ROOT."resources/$file"); + preg_match("#Upgrade Script:(.*)#i", $upgradescript, $verinfo); + preg_match("#upgrade([0-9]+).php$#i", $file, $keynum); + if(trim($verinfo[1])) + { + if($keynum[1] == $next_update_version) + { + $vers .= "\n"; + } + else + { + $vers .= "\n"; + } + } + } + unset($upgradescripts); + unset($upgradescript); + + $output->print_contents($lang->sprintf($lang->upgrade_welcome, $mybb->version)."

    ".$lang->upgrade_send_stats); + $output->print_footer("doupgrade"); + } + elseif($mybb->input['action'] == "doupgrade") + { + add_upgrade_store("allow_anonymous_info", $mybb->get_input('allow_anonymous_info', 1)); + require_once INSTALL_ROOT."resources/upgrade".$mybb->get_input('from', 1).".php"; + if($db->table_exists("datacache") && $upgrade_detail['requires_deactivated_plugins'] == 1 && $mybb->get_input('donewarning') != "true") + { + $plugins = $cache->read('plugins', true); + if(!empty($plugins['active'])) + { + $output->print_header(); + $lang->plugin_warning = "input['from'])."\" />\n\n

    Ostrzeżenie:

    Na Twoim forum ".count($plugins['active'])." pluginów wciąż jest aktywnych. Aktywne pluginy mogą sprawić problemy podczas przeprowadzania procesu aktualizacji lub całkowicie go zakłócić. Wysoce zalecane jest wyłączenie wszystkich pluginów przed przystąpieniem do procesu aktualizacji.


    "; + $output->print_contents($lang->sprintf($lang->plugin_warning, $mybb->version)); + $output->print_footer("doupgrade"); + } + else + { + add_upgrade_store("startscript", $mybb->get_input('from', 1)); + $runfunction = next_function($mybb->get_input('from', 1)); + } + } + else + { + add_upgrade_store("startscript", $mybb->get_input('from', 1)); + $runfunction = next_function($mybb->get_input('from', 1)); + } + } + $currentscript = get_upgrade_store("currentscript"); + $system_upgrade_detail = get_upgrade_store("upgradedetail"); + + if($mybb->input['action'] == "templates") + { + $runfunction = "upgradethemes"; + } + elseif($mybb->input['action'] == "rebuildsettings") + { + $runfunction = "buildsettings"; + } + elseif($mybb->input['action'] == "buildcaches") + { + $runfunction = "buildcaches"; + } + elseif($mybb->input['action'] == "finished") + { + $runfunction = "upgradedone"; + } + else // Busy running modules, come back later + { + $bits = explode("_", $mybb->input['action'], 2); + if($bits[1]) // We're still running a module + { + $from = $bits[0]; + $runfunction = next_function($bits[0], $bits[1]); + + } + } + + // Fetch current script we're in + if(function_exists($runfunction)) + { + $runfunction(); + } +} + +function upgradethemes() +{ + global $output, $db, $system_upgrade_detail, $lang, $mybb; + + $output->print_header($lang->upgrade_templates_reverted); + + $charset = $db->build_create_table_collation(); + + if($system_upgrade_detail['revert_all_templates'] > 0) + { + $db->drop_table("templates"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."templates ( + tid int unsigned NOT NULL auto_increment, + title varchar(120) NOT NULL default '', + template text NOT NULL, + sid int(10) NOT NULL default '0', + version varchar(20) NOT NULL default '0', + status varchar(10) NOT NULL default '', + dateline int(10) NOT NULL default '0', + PRIMARY KEY (tid) + ) ENGINE=MyISAM{$charset};"); + } + + if($system_upgrade_detail['revert_all_themes'] > 0) + { + $db->drop_table("themes"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."themes ( + tid smallint unsigned NOT NULL auto_increment, + name varchar(100) NOT NULL default '', + pid smallint unsigned NOT NULL default '0', + def smallint(1) NOT NULL default '0', + properties text NOT NULL, + stylesheets text NOT NULL, + allowedgroups text NOT NULL, + PRIMARY KEY (tid) + ) ENGINE=MyISAM{$charset};"); + + $db->drop_table("themestylesheets"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."themestylesheets( + sid int unsigned NOT NULL auto_increment, + name varchar(30) NOT NULL default '', + tid int unsigned NOT NULL default '0', + attachedto text NOT NULL, + stylesheet text NOT NULL, + cachefile varchar(100) NOT NULL default '', + lastmodified bigint(30) NOT NULL default '0', + PRIMARY KEY(sid) + ) ENGINE=MyISAM{$charset};"); + + $contents = @file_get_contents(INSTALL_ROOT.'resources/mybb_theme.xml'); + if(file_exists(MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions_themes.php")) + { + require_once MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions_themes.php"; + } + else if(file_exists(MYBB_ROOT."admin/inc/functions_themes.php")) + { + require_once MYBB_ROOT."admin/inc/functions_themes.php"; + } + else + { + $output->print_error("Upewnij się, że katalog /admin został poprawnie załadowany na serwer."); + } + import_theme_xml($contents, array("templateset" => -2, "no_templates" => 1, "version_compat" => 1)); + $tid = build_new_theme("Default", null, 1); + + $db->update_query("themes", array("def" => 1), "tid='{$tid}'"); + $db->update_query("users", array('style' => $tid)); + $db->update_query("forums", array('style' => 0)); + + $db->drop_table("templatesets"); + $db->write_query("CREATE TABLE ".TABLE_PREFIX."templatesets ( + sid smallint unsigned NOT NULL auto_increment, + title varchar(120) NOT NULL default '', + PRIMARY KEY (sid) + ) ENGINE=MyISAM{$charset};"); + + $db->insert_query("templatesets", array('title' => 'Default Templates')); + } + else + { + // Re-import master + $contents = @file_get_contents(INSTALL_ROOT.'resources/mybb_theme.xml'); + if(file_exists(MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions_themes.php")) + { + require_once MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions.php"; + require_once MYBB_ROOT.$mybb->config['admin_dir']."/inc/functions_themes.php"; + } + elseif(file_exists(MYBB_ROOT."admin/inc/functions_themes.php")) + { + require_once MYBB_ROOT."admin/inc/functions.php"; + require_once MYBB_ROOT."admin/inc/functions_themes.php"; + } + else + { + $output->print_error(); + } + + // Import master theme + import_theme_xml($contents, array("tid" => 1, "no_templates" => 1, "version_compat" => 1)); + } + + $sid = -2; + + // Now deal with the master templates + $contents = @file_get_contents(INSTALL_ROOT.'resources/mybb_theme.xml'); + $parser = new XMLParser($contents); + $tree = $parser->get_tree(); + + $theme = $tree['theme']; + + if(is_array($theme['templates'])) + { + $templates = $theme['templates']['template']; + foreach($templates as $template) + { + $templatename = $db->escape_string($template['attributes']['name']); + $templateversion = (int)$template['attributes']['version']; + $templatevalue = $db->escape_string($template['value']); + $time = TIME_NOW; + $query = $db->simple_select("templates", "tid", "sid='-2' AND title='".$db->escape_string($templatename)."'"); + $oldtemp = $db->fetch_array($query); + if($oldtemp['tid']) + { + $update_array = array( + 'template' => $templatevalue, + 'version' => $templateversion, + 'dateline' => $time + ); + $db->update_query("templates", $update_array, "title='".$db->escape_string($templatename)."' AND sid='-2'"); + } + else + { + $insert_array = array( + 'title' => $templatename, + 'template' => $templatevalue, + 'sid' => $sid, + 'version' => $templateversion, + 'dateline' => $time + ); + + $db->insert_query("templates", $insert_array); + ++$newcount; + } + } + } + + $output->print_contents($lang->upgrade_templates_reverted_success); + $output->print_footer("rebuildsettings"); +} + +function buildsettings() +{ + global $db, $output, $system_upgrade_detail, $lang; + + if(!is_writable(MYBB_ROOT."inc/settings.php")) + { + $output->print_header("Przebudowywanie ustawień"); + echo "

    Błąd: Nie można otworzyć inc/settings.php

    Przed uruchomieniem procesu aktualizacji sprawdź uprawnienia dostępu dla tego pliku.

    "; + $output->print_footer("rebuildsettings"); + exit; + } + $synccount = sync_settings($system_upgrade_detail['revert_all_settings']); + + $output->print_header($lang->upgrade_settings_sync); + $output->print_contents($lang->sprintf($lang->upgrade_settings_sync_success, $synccount[1], $synccount[0])); + $output->print_footer("buildcaches"); +} + +function buildcaches() +{ + global $db, $output, $cache, $lang, $mybb; + + $output->print_header($lang->upgrade_datacache_building); + + $contents .= $lang->upgrade_building_datacache; + require_once MYBB_ROOT."inc/class_datacache.php"; + $cache = new datacache; + $cache->update_version(); + $cache->update_attachtypes(); + $cache->update_smilies(); + $cache->update_badwords(); + $cache->update_usergroups(); + $cache->update_forumpermissions(); + $cache->update_stats(); + $cache->update_statistics(); + $cache->update_moderators(); + $cache->update_forums(); + $cache->update_usertitles(); + $cache->update_reportedcontent(); + $cache->update_awaitingactivation(); + $cache->update_mycode(); + $cache->update_profilefields(); + $cache->update_posticons(); + $cache->update_update_check(); + $cache->update_tasks(); + $cache->update_spiders(); + $cache->update_bannedips(); + $cache->update_banned(); + $cache->update_birthdays(); + $cache->update_most_replied_threads(); + $cache->update_most_viewed_threads(); + $cache->update_groupleaders(); + $cache->update_threadprefixes(); + $cache->update_forumsdisplay(); + + $contents .= $lang->done."

    "; + + $output->print_contents("$contents

    ".$lang->upgrade_continue."

    "); + $output->print_footer("finished"); +} + +function upgradedone() +{ + global $db, $output, $mybb, $lang, $config; + + ob_start(); + $output->print_header("Aktualizacja zakończona"); + + $allow_anonymous_info = get_upgrade_store("allow_anonymous_info"); + if($allow_anonymous_info == 1) + { + require_once MYBB_ROOT."inc/functions_serverstats.php"; + $build_server_stats = build_server_stats(0, '', $mybb->version_code, $mybb->config['database']['encoding']); + + if($build_server_stats['info_sent_success'] == false) + { + echo $build_server_stats['info_image']; + } + } + ob_end_flush(); + + // Attempt to run an update check + require_once MYBB_ROOT.'inc/functions_task.php'; + run_task(12); + + if(is_writable("./")) + { + $lock = @fopen("./lock", "w"); + $written = @fwrite($lock, "1"); + @fclose($lock); + if($written) + { + $lock_note = $lang->sprintf($lang->upgrade_locked, $config['admin_dir']); + } + } + if(!$written) + { + $lock_note = "

    ".$lang->upgrade_removedir."

    "; + } + + // Rebuild inc/settings.php at the end of the upgrade + if(function_exists('rebuild_settings')) + { + rebuild_settings(); + } + else + { + $options = array( + "order_by" => "title", + "order_dir" => "ASC" + ); + + $query = $db->simple_select("settings", "value, name", "", $options); + while($setting = $db->fetch_array($query)) + { + $setting['value'] = str_replace("\"", "\\\"", $setting['value']); + $settings[$setting['name']] = $setting['value']; + } + } + + $output->print_contents($lang->sprintf($lang->upgrade_congrats, $mybb->version, $lock_note)); + $output->print_footer(); +} + +function whatsnext() +{ + global $output, $db, $system_upgrade_detail, $lang; + + if($system_upgrade_detail['revert_all_templates'] > 0) + { + $output->print_header($lang->upgrade_template_reversion); + $output->print_contents($lang->upgrade_template_reversion_success); + $output->print_footer("templates"); + } + else + { + upgradethemes(); + } +} + +function next_function($from, $func="dbchanges") +{ + global $oldvers, $system_upgrade_detail, $currentscript, $cache; + + load_module("upgrade".$from.".php"); + if(function_exists("upgrade".$from."_".$func)) + { + $function = "upgrade".$from."_".$func; + } + else + { + // We're done with our last upgrade script, so add it to the upgrade scripts we've already completed. + $version_history = $cache->read("version_history"); + $version_history[$from] = $from; + $cache->update("version_history", $version_history); + + $from = $from+1; + if(file_exists(INSTALL_ROOT."resources/upgrade".$from.".php")) + { + $function = next_function($from); + } + } + + if(!$function) + { + $function = "whatsnext"; + } + return $function; +} + +function load_module($module) +{ + global $system_upgrade_detail, $currentscript, $upgrade_detail; + + require_once INSTALL_ROOT."resources/".$module; + if($currentscript != $module) + { + foreach($upgrade_detail as $key => $val) + { + if(!$system_upgrade_detail[$key] || $val > $system_upgrade_detail[$key]) + { + $system_upgrade_detail[$key] = $val; + } + } + add_upgrade_store("upgradedetail", $system_upgrade_detail); + add_upgrade_store("currentscript", $module); + } +} + +function get_upgrade_store($title) +{ + global $db; + + $query = $db->simple_select("upgrade_data", "*", "title='".$db->escape_string($title)."'"); + $data = $db->fetch_array($query); + return my_unserialize($data['contents']); +} + +function add_upgrade_store($title, $contents) +{ + global $db; + + $replace_array = array( + "title" => $db->escape_string($title), + "contents" => $db->escape_string(serialize($contents)) + ); + $db->replace_query("upgrade_data", $replace_array, "title"); +} + +function sync_settings($redo=0) +{ + global $db; + + $settingcount = $groupcount = 0; + $settings = $settinggroups = array(); + if($redo == 2) + { + $db->drop_table("settinggroups"); + switch($db->type) + { + case "pgsql": + $db->write_query("CREATE TABLE ".TABLE_PREFIX."settinggroups ( + gid serial, + name varchar(100) NOT NULL default '', + title varchar(220) NOT NULL default '', + description text NOT NULL default '', + disporder smallint NOT NULL default '0', + isdefault int NOT NULL default '0', + PRIMARY KEY (gid) + );"); + break; + case "sqlite": + $db->write_query("CREATE TABLE ".TABLE_PREFIX."settinggroups ( + gid INTEGER PRIMARY KEY, + name varchar(100) NOT NULL default '', + title varchar(220) NOT NULL default '', + description TEXT NOT NULL, + disporder smallint NOT NULL default '0', + isdefault int(1) NOT NULL default '0' + );"); + break; + case "mysql": + default: + $db->write_query("CREATE TABLE ".TABLE_PREFIX."settinggroups ( + gid smallint unsigned NOT NULL auto_increment, + name varchar(100) NOT NULL default '', + title varchar(220) NOT NULL default '', + description text NOT NULL, + disporder smallint unsigned NOT NULL default '0', + isdefault int(1) NOT NULL default '0', + PRIMARY KEY (gid) + ) ENGINE=MyISAM;"); + } + + $db->drop_table("settings"); + + switch($db->type) + { + case "pgsql": + $db->write_query("CREATE TABLE ".TABLE_PREFIX."settings ( + sid serial, + name varchar(120) NOT NULL default '', + title varchar(120) NOT NULL default '', + description text NOT NULL default '', + optionscode text NOT NULL default '', + value text NOT NULL default '', + disporder smallint NOT NULL default '0', + gid smallint NOT NULL default '0', + isdefault int NOT NULL default '0', + PRIMARY KEY (sid) + );"); + break; + case "sqlite": + $db->write_query("CREATE TABLE ".TABLE_PREFIX."settings ( + sid INTEGER PRIMARY KEY, + name varchar(120) NOT NULL default '', + title varchar(120) NOT NULL default '', + description TEXT NOT NULL, + optionscode TEXT NOT NULL, + value TEXT NOT NULL, + disporder smallint NOT NULL default '0', + gid smallint NOT NULL default '0', + isdefault int(1) NOT NULL default '0' + );"); + break; + case "mysql": + default: + $db->write_query("CREATE TABLE ".TABLE_PREFIX."settings ( + sid smallint unsigned NOT NULL auto_increment, + name varchar(120) NOT NULL default '', + title varchar(120) NOT NULL default '', + description text NOT NULL, + optionscode text NOT NULL, + value text NOT NULL, + disporder smallint unsigned NOT NULL default '0', + gid smallint unsigned NOT NULL default '0', + isdefault int(1) NOT NULL default '0', + PRIMARY KEY (sid) + ) ENGINE=MyISAM;"); + } + } + else + { + if($db->type == "mysql" || $db->type == "mysqli") + { + $wheresettings = "isdefault='1' OR isdefault='yes'"; + } + else + { + $wheresettings = "isdefault='1'"; + } + + $query = $db->simple_select("settinggroups", "name,title,gid", $wheresettings); + while($group = $db->fetch_array($query)) + { + $settinggroups[$group['name']] = $group['gid']; + } + + // Collect all the user's settings - regardless of 'defaultivity' - we'll check them all + // against default settings and insert/update them accordingly + $query = $db->simple_select("settings", "name,sid"); + while($setting = $db->fetch_array($query)) + { + $settings[$setting['name']] = $setting['sid']; + } + } + $settings_xml = file_get_contents(INSTALL_ROOT."resources/settings.xml"); + $parser = new XMLParser($settings_xml); + $parser->collapse_dups = 0; + $tree = $parser->get_tree(); + $settinggroupnames = array(); + $settingnames = array(); + + foreach($tree['settings'][0]['settinggroup'] as $settinggroup) + { + $settinggroupnames[] = $settinggroup['attributes']['name']; + + $groupdata = array( + "name" => $db->escape_string($settinggroup['attributes']['name']), + "title" => $db->escape_string($settinggroup['attributes']['title']), + "description" => $db->escape_string($settinggroup['attributes']['description']), + "disporder" => (int)$settinggroup['attributes']['disporder'], + "isdefault" => $settinggroup['attributes']['isdefault'] + ); + if(!$settinggroups[$settinggroup['attributes']['name']] || $redo == 2) + { + $gid = $db->insert_query("settinggroups", $groupdata); + ++$groupcount; + } + else + { + $gid = $settinggroups[$settinggroup['attributes']['name']]; + $db->update_query("settinggroups", $groupdata, "gid='{$gid}'"); + } + + if(!$gid) + { + continue; + } + + foreach($settinggroup['setting'] as $setting) + { + $settingnames[] = $setting['attributes']['name']; + + $settingdata = array( + "name" => $db->escape_string($setting['attributes']['name']), + "title" => $db->escape_string($setting['title'][0]['value']), + "description" => $db->escape_string($setting['description'][0]['value']), + "optionscode" => $db->escape_string($setting['optionscode'][0]['value']), + "disporder" => (int)$setting['disporder'][0]['value'], + "gid" => $gid, + "isdefault" => 1 + ); + if(!$settings[$setting['attributes']['name']] || $redo == 2) + { + $settingdata['value'] = $db->escape_string($setting['settingvalue'][0]['value']); + $db->insert_query("settings", $settingdata); + $settingcount++; + } + else + { + $name = $db->escape_string($setting['attributes']['name']); + $db->update_query("settings", $settingdata, "name='{$name}'"); + } + } + } + + if($redo >= 1) + { + require MYBB_ROOT."inc/settings.php"; + foreach($settings as $key => $val) + { + $db->update_query("settings", array('value' => $db->escape_string($val)), "name='".$db->escape_string($key)."'"); + } + } + unset($settings); + $query = $db->simple_select("settings", "*", "", array('order_by' => 'title')); + while($setting = $db->fetch_array($query)) + { + $setting['value'] = str_replace("\"", "\\\"", $setting['value']); + $settings .= "\$settings['{$setting['name']}'] = \"".$setting['value']."\";\n"; + } + $settings = "drop_table("tasks"); + switch($db->type) + { + case "pgsql": + $db->write_query("CREATE TABLE ".TABLE_PREFIX."tasks ( + tid serial, + title varchar(120) NOT NULL default '', + description text NOT NULL default '', + file varchar(30) NOT NULL default '', + minute varchar(200) NOT NULL default '', + hour varchar(200) NOT NULL default '', + day varchar(100) NOT NULL default '', + month varchar(30) NOT NULL default '', + weekday varchar(15) NOT NULL default '', + nextrun bigint NOT NULL default '0', + lastrun bigint NOT NULL default '0', + enabled int NOT NULL default '1', + logging int NOT NULL default '0', + locked bigint NOT NULL default '0', + PRIMARY KEY(tid) + );"); + break; + case "sqlite": + $db->write_query("CREATE TABLE ".TABLE_PREFIX."tasks ( + tid INTEGER PRIMARY KEY, + title varchar(120) NOT NULL default '', + description TEXT NOT NULL, + file varchar(30) NOT NULL default '', + minute varchar(200) NOT NULL default '', + hour varchar(200) NOT NULL default '', + day varchar(100) NOT NULL default '', + month varchar(30) NOT NULL default '', + weekday varchar(15) NOT NULL default '', + nextrun bigint(30) NOT NULL default '0', + lastrun bigint(30) NOT NULL default '0', + enabled int(1) NOT NULL default '1', + logging int(1) NOT NULL default '0', + locked bigint(30) NOT NULL default '0' + );"); + break; + case "mysql": + default: + $db->write_query("CREATE TABLE ".TABLE_PREFIX."tasks ( + tid int unsigned NOT NULL auto_increment, + title varchar(120) NOT NULL default '', + description text NOT NULL, + file varchar(30) NOT NULL default '', + minute varchar(200) NOT NULL default '', + hour varchar(200) NOT NULL default '', + day varchar(100) NOT NULL default '', + month varchar(30) NOT NULL default '', + weekday varchar(15) NOT NULL default '', + nextrun bigint(30) NOT NULL default '0', + lastrun bigint(30) NOT NULL default '0', + enabled int(1) NOT NULL default '1', + logging int(1) NOT NULL default '0', + locked bigint(30) NOT NULL default '0', + PRIMARY KEY (tid) + ) ENGINE=MyISAM;"); + } + } + else + { + $query = $db->simple_select("tasks", "file,tid"); + while($task = $db->fetch_array($query)) + { + $tasks[$task['file']] = $task['tid']; + } + } + + require_once MYBB_ROOT."inc/functions_task.php"; + $task_file = file_get_contents(INSTALL_ROOT.'resources/tasks.xml'); + $parser = new XMLParser($task_file); + $parser->collapse_dups = 0; + $tree = $parser->get_tree(); + + // Resync tasks + foreach($tree['tasks'][0]['task'] as $task) + { + if(!$tasks[$task['file'][0]['value']] || $redo == 2) + { + $new_task = array( + 'title' => $db->escape_string($task['title'][0]['value']), + 'description' => $db->escape_string($task['description'][0]['value']), + 'file' => $db->escape_string($task['file'][0]['value']), + 'minute' => $db->escape_string($task['minute'][0]['value']), + 'hour' => $db->escape_string($task['hour'][0]['value']), + 'day' => $db->escape_string($task['day'][0]['value']), + 'weekday' => $db->escape_string($task['weekday'][0]['value']), + 'month' => $db->escape_string($task['month'][0]['value']), + 'enabled' => $db->escape_string($task['enabled'][0]['value']), + 'logging' => $db->escape_string($task['logging'][0]['value']) + ); + + $new_task['nextrun'] = fetch_next_run($new_task); + + $db->insert_query("tasks", $new_task); + $taskcount++; + } + else + { + $update_task = array( + 'title' => $db->escape_string($task['title'][0]['value']), + 'description' => $db->escape_string($task['description'][0]['value']), + 'file' => $db->escape_string($task['file'][0]['value']), + ); + + $db->update_query("tasks", $update_task, "file='".$db->escape_string($task['file'][0]['value'])."'"); + } + } + + return $taskcount; +} + +function write_settings() +{ + global $db; + $query = $db->simple_select("settings", "*", "", array('order_by' => 'title')); + while($setting = $db->fetch_array($query)) + { + $setting['value'] = $db->escape_string($setting['value']); + $settings .= "\$settings['{$setting['name']}'] = \"{$setting['value']}\";\n"; + } + if(!empty($settings)) + { + $settings = " \ No newline at end of file diff --git a/Upload/jscripts/bbcodes_sceditor.js b/Upload/jscripts/bbcodes_sceditor.js new file mode 100644 index 0000000..3c2f4b5 --- /dev/null +++ b/Upload/jscripts/bbcodes_sceditor.js @@ -0,0 +1,600 @@ +// This was taken from the SCEditor plugin for MyBB + +$(document).ready(function($) { + 'use strict'; + + var $document = $(document); + + + /*********************** + * Add custom MyBB CSS * + ***********************/ + $('').appendTo('body'); + + + + /******************************************** + * Update editor to use align= as alignment * + ********************************************/ + $.sceditor.plugins.bbcode.bbcode + .set('align', { + html: function(element, attrs, content) { + return '
    ' + content + '
    '; + }, + isInline: false + }) + .set('center', { format: '[align=center]{0}[/align]' }) + .set('left', { format: '[align=left]{0}[/align]' }) + .set('right', { format: '[align=right]{0}[/align]' }) + .set('justify', { format: '[align=justify]{0}[/align]' }); + + $.sceditor.command + .set('center', { txtExec: ['[align=center]', '[/align]'] }) + .set('left', { txtExec: ['[align=left]', '[/align]'] }) + .set('right', { txtExec: ['[align=right]', '[/align]'] }) + .set('justify', { txtExec: ['[align=justify]', '[/align]'] }); + + + + /************************************************ + * Update font to support MyBB's BBCode dialect * + ************************************************/ + $.sceditor.plugins.bbcode.bbcode + .set('list', { + html: function(element, attrs, content) { + var type = (attrs.defaultattr === '1' ? 'ol' : 'ul'); + + if(attrs.defaultattr === 'a') + type = 'ol type="a"'; + + return '<' + type + '>' + content + ''; + }, + + breakAfter: false + }) + .set('ul', { format: '[list]{0}[/list]' }) + .set('ol', { + format: function($elm, content) { + var type = ($elm.attr('type') === 'a' ? 'a' : '1'); + + return '[list=' + type + ']' + content + '[/list]'; + } + }) + .set('li', { format: '[*]{0}', excludeClosing: true }) + .set('*', { excludeClosing: true, isInline: true }); + + $.sceditor.command + .set('bulletlist', { txtExec: ['[list]\n[*]', '\n[/list]'] }) + .set('orderedlist', { txtExec: ['[list=1]\n[*]', '\n[/list]'] }); + + + + /*********************************************************** + * Update size tag to use xx-small-xx-large instead of 1-7 * + ***********************************************************/ + $.sceditor.plugins.bbcode.bbcode.set('size', { + format: function($elm, content) { + var fontSize, + sizes = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'], + size = $elm.data('scefontsize'); + + if(!size) + { + fontSize = $elm.css('fontSize'); + + // Most browsers return px value but IE returns 1-7 + if(fontSize.indexOf('px') > -1) { + // convert size to an int + fontSize = fontSize.replace('px', '') - 0; + size = 1; + + if(fontSize > 9) + size = 1; + if(fontSize > 12) + size = 2; + if(fontSize > 15) + size = 3; + if(fontSize > 17) + size = 4; + if(fontSize > 23) + size = 5; + if(fontSize > 31) + size = 6; + if(fontSize > 47) + size = 7; + } + else + size = (~~fontSize) + 1; + + if(size > 7) + size = 7; + if(size < 1) + size = 1; + + size = sizes[size-1]; + } + + return '[size=' + size + ']' + content + '[/size]'; + }, + html: function(token, attrs, content) { + return '' + content + ''; + } + }); + + $.sceditor.command.set('size', { + _dropDown: function(editor, caller, callback) { + var content = $('
    '), + clickFunc = function (e) { + callback($(this).data('size')); + editor.closeDropDown(true); + e.preventDefault(); + }; + + for (var i=1; i <= 7; i++) + content.append($('' + i + '').click(clickFunc)); + + editor.createDropDown(caller, 'fontsize-picker', content); + }, + txtExec: function(caller) { + var editor = this, + sizes = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large']; + + $.sceditor.command.get('size')._dropDown( + editor, + caller, + function(size) { + size = (~~size); + size = (size > 7) ? 7 : ( (size < 1) ? 1 : size ); + + editor.insertText('[size=' + sizes[size-1] + ']', '[/size]'); + } + ); + } + }); + + + + /******************************************** + * Update quote to support pid and dateline * + ********************************************/ + $.sceditor.plugins.bbcode.bbcode.set('quote', { + format: function(element, content) { + var author = '', + $elm = $(element), + $cite = $elm.children('cite').first(); + $cite.html($cite.text()); + + if($cite.length === 1 || $elm.data('author')) + { + author = $cite.text() || $elm.data('author'); + + $elm.data('author', author); + $cite.remove(); + + content = this.elementToBbcode($(element)); + author = '=' + author.replace(/(^\s+|\s+$)/g, ''); + + $elm.prepend($cite); + } + + if($elm.data('pid')) + author += " pid='" + $elm.data('pid') + "'"; + + if($elm.data('dateline')) + author += " dateline='" + $elm.data('dateline') + "'"; + + return '[quote' + author + ']' + content + '[/quote]'; + }, + html: function(token, attrs, content) { + var data = ''; + + if(attrs.pid) + data += ' data-pid="' + attrs.pid + '"'; + + if(attrs.dateline) + data += ' data-dateline="' + attrs.dateline + '"'; + + if(typeof attrs.defaultattr !== "undefined") + content = '' + attrs.defaultattr.replace(/ /g, ' ') + '' + content; + + return '' + content + ''; + }, + quoteType: function(val, name) { + return "'" + val.replace("'", "\\'") + "'"; + }, + breakStart: true, + breakEnd: true + }); + + + + /************************************************************ + * Update font tag to allow limiting to only first in stack * + ************************************************************/ + $.sceditor.plugins.bbcode.bbcode.set('font', { + format: function(element, content) { + var font; + + if(element[0].nodeName.toLowerCase() !== 'font' || !(font = element.attr('face'))) + font = element.css('font-family'); + + + if(typeof font == 'string' && font != '' && font != 'defaultattr') + { + return '[font=' + this.stripQuotes(font) + ']' + content + '[/font]'; + } + else + { + return content; + } + }, + html: function(token, attrs, content) { + if(typeof attrs.defaultattr == 'string' && attrs.defaultattr != '' && attrs.defaultattr != '{defaultattr}') + { + return '' + content + ''; + } + else + { + return content; + } + } + }); + + + + /************************ + * Add MyBB PHP command * + ************************/ + $.sceditor.plugins.bbcode.bbcode.set('php', { + allowsEmpty: true, + isInline: false, + allowedChildren: ['#', '#newline'], + format: '[php]{0}[/php]', + html: '{0}' + }); + + $.sceditor.command.set("php", { + _dropDown: function (editor, caller, html) { + var $content; + + $content = $( + '
    ' + + ' ' + + '",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:k.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("'; + } else { + msgbox +='
    '; + } + msgbox += '
    '+ + '
    '+ + '
    '+ opts.closeText +'
    '+ + '
    '+ + ''+ + '
    '+ + ''; + + $.prompt.jqib = $(msgbox).appendTo($body); + $.prompt.jqi = $.prompt.jqib.children('.'+ opts.prefix);//.data('jqi',opts); + $.prompt.jqif = $.prompt.jqib.children('.'+ opts.prefix +'fade'); + + //if a string was passed, convert to a single state + if(message.constructor === String){ + message = { + state0: { + title: opts.title, + html: message, + buttons: opts.buttons, + position: opts.position, + focus: opts.focus, + defaultButton: opts.defaultButton, + submit: opts.submit + } + }; + } + + //build the states + $.prompt.options.states = {}; + var k,v; + for(k in message){ + v = $.extend({},$.prompt.defaults.state,{name:k},message[k]); + $.prompt.addState(v.name, v); + + if($.prompt.currentStateName === ''){ + $.prompt.currentStateName = v.name; + } + } + + //Events + $.prompt.jqi.on('click', '.'+ opts.prefix +'buttons button', function(e){ + var $t = $(this), + $state = $t.parents('.'+ opts.prefix +'state'), + stateobj = $.prompt.options.states[$state.data('jqi-name')], + msg = $state.children('.'+ opts.prefix +'message'), + clicked = stateobj.buttons[$t.text()] || stateobj.buttons[$t.html()], + forminputs = {}; + + // if for some reason we couldn't get the value + if(clicked === undefined){ + for(var i in stateobj.buttons){ + if(stateobj.buttons[i].title === $t.text() || stateobj.buttons[i].title === $t.html()){ + clicked = stateobj.buttons[i].value; + } + } + } + + //collect all form element values from all states. + $.each($.prompt.jqi.children('form').serializeArray(),function(i,obj){ + if (forminputs[obj.name] === undefined) { + forminputs[obj.name] = obj.value; + } else if (typeof forminputs[obj.name] === Array || typeof forminputs[obj.name] === 'object') { + forminputs[obj.name].push(obj.value); + } else { + forminputs[obj.name] = [forminputs[obj.name],obj.value]; + } + }); + + // trigger an event + var promptsubmite = new $.Event('impromptu:submit'); + promptsubmite.stateName = stateobj.name; + promptsubmite.state = $state; + $state.trigger(promptsubmite, [clicked, msg, forminputs]); + + if(!promptsubmite.isDefaultPrevented()){ + $.prompt.close(true, clicked,msg,forminputs); + } + }); + + // if the fade is clicked blink the prompt + var fadeClicked = function(){ + if(opts.persistent){ + var offset = (opts.top.toString().indexOf('%') >= 0? ($window.height()*(parseInt(opts.top,10)/100)) : parseInt(opts.top,10)), + top = parseInt($.prompt.jqi.css('top').replace('px',''),10) - offset; + + //$window.scrollTop(top); + $('html,body').animate({ scrollTop: top }, 'fast', function(){ + var i = 0; + $.prompt.jqib.addClass(opts.prefix +'warning'); + var intervalid = setInterval(function(){ + $.prompt.jqib.toggleClass(opts.prefix +'warning'); + if(i++ > 1){ + clearInterval(intervalid); + $.prompt.jqib.removeClass(opts.prefix +'warning'); + } + }, 100); + }); + } + else { + $.prompt.close(true); + } + }; + + // listen for esc or tab keys + var keyDownEventHandler = function(e){ + var key = (window.event) ? event.keyCode : e.keyCode; + + //escape key closes + if(key === 27) { + fadeClicked(); + } + + //enter key pressed trigger the default button if its not on it, ignore if it is a textarea + if(key === 13){ + var $defBtn = $.prompt.getCurrentState().find('.'+ opts.prefix +'defaultbutton'); + var $tgt = $(e.target); + + if($tgt.is('textarea,.'+opts.prefix+'button') === false && $defBtn.length > 0){ + e.preventDefault(); + $defBtn.click(); + } + } + + //constrain tabs, tabs should iterate through the state and not leave + if (key === 9){ + var $inputels = $('input,select,textarea,button',$.prompt.getCurrentState()); + var fwd = !e.shiftKey && e.target === $inputels[$inputels.length-1]; + var back = e.shiftKey && e.target === $inputels[0]; + if (fwd || back) { + setTimeout(function(){ + if (!$inputels){ + return; + } + var el = $inputels[back===true ? $inputels.length-1 : 0]; + + if (el){ + el.focus(); + } + },10); + return false; + } + } + }; + + $.prompt.position(); + $.prompt.style(); + + $.prompt.jqif.click(fadeClicked); + $window.resize({animate:false}, $.prompt.position); + $.prompt.jqi.find('.'+ opts.prefix +'close').click($.prompt.close); + $.prompt.jqib.on("keydown",keyDownEventHandler) + .on('impromptu:loaded', opts.loaded) + .on('impromptu:close', opts.close) + .on('impromptu:statechanging', opts.statechanging) + .on('impromptu:statechanged', opts.statechanged); + + // Show it + $.prompt.jqif[opts.show](opts.overlayspeed); + $.prompt.jqi[opts.show](opts.promptspeed, function(){ + + var $firstState = $.prompt.jqi.find('.'+ opts.prefix +'states .'+ opts.prefix +'state').eq(0); + $.prompt.goToState($firstState.data('jqi-name')); + + $.prompt.jqib.trigger('impromptu:loaded'); + }); + + // Timeout + if(opts.timeout > 0){ + $.prompt.timeout = setTimeout(function(){ $.prompt.close(true); },opts.timeout); + } + + return $.prompt.jqib; + }; + + $.prompt.defaults = { + prefix:'jqi', + classes: { + box: '', + fade: '', + prompt: '', + form: '', + close: '', + title: '', + message: '', + buttons: '', + button: '', + defaultButton: '' + }, + title: '', + closeText: '×', + buttons: { + Ok: true + }, + loaded: function(e){}, + submit: function(e,v,m,f){}, + close: function(e,v,m,f){}, + statechanging: function(e, from, to){}, + statechanged: function(e, to){}, + opacity: 0.6, + zIndex: 999, + overlayspeed: 'slow', + promptspeed: 'fast', + show: 'fadeIn', + focus: 0, + defaultButton: 0, + useiframe: false, + top: '15%', + position: { + container: null, + x: null, + y: null, + arrow: null, + width: null + }, + persistent: true, + timeout: 0, + states: {}, + state: { + name: null, + title: '', + html: '', + buttons: { + Ok: true + }, + focus: 0, + defaultButton: 0, + position: { + container: null, + x: null, + y: null, + arrow: null, + width: null + }, + submit: function(e,v,m,f){ + return true; + } + } + }; + + /** + * currentPrefix String - At any time this show be the prefix + * of the current prompt ex: "jqi" + */ + $.prompt.currentPrefix = $.prompt.defaults.prefix; + + /** + * currentStateName String - At any time this is the current state + * of the current prompt ex: "state0" + */ + $.prompt.currentStateName = ""; + + /** + * setDefaults - Sets the default options + * @param o Object - Options to set as defaults + * @return void + */ + $.prompt.setDefaults = function(o) { + $.prompt.defaults = $.extend({}, $.prompt.defaults, o); + }; + + /** + * setStateDefaults - Sets the default options for a state + * @param o Object - Options to set as defaults + * @return void + */ + $.prompt.setStateDefaults = function(o) { + $.prompt.defaults.state = $.extend({}, $.prompt.defaults.state, o); + }; + + /** + * position - Repositions the prompt (Used internally) + * @return void + */ + $.prompt.position = function(e){ + var restoreFx = $.fx.off, + $state = $.prompt.getCurrentState(), + stateObj = $.prompt.options.states[$state.data('jqi-name')], + pos = stateObj? stateObj.position : undefined, + $window = $(window), + bodyHeight = document.body.scrollHeight, //$(document.body).outerHeight(true), + windowHeight = $(window).height(), + documentHeight = $(document).height(), + height = bodyHeight > windowHeight ? bodyHeight : windowHeight, + top = parseInt($window.scrollTop(),10) + ($.prompt.options.top.toString().indexOf('%') >= 0? + (windowHeight*(parseInt($.prompt.options.top,10)/100)) : parseInt($.prompt.options.top,10)); + + // when resizing the window turn off animation + if(e !== undefined && e.data.animate === false){ + $.fx.off = true; + } + + $.prompt.jqib.css({ + position: "absolute", + height: height, + width: "100%", + top: 0, + left: 0, + right: 0, + bottom: 0 + }); + $.prompt.jqif.css({ + position: "fixed", + height: height, + width: "100%", + top: 0, + left: 0, + right: 0, + bottom: 0 + }); + + // tour positioning + if(pos && pos.container){ + var offset = $(pos.container).offset(); + + if($.isPlainObject(offset) && offset.top !== undefined){ + $.prompt.jqi.css({ + position: "absolute" + }); + $.prompt.jqi.animate({ + top: offset.top + pos.y, + left: offset.left + pos.x, + marginLeft: 0, + width: (pos.width !== undefined)? pos.width : null + }); + top = (offset.top + pos.y) - ($.prompt.options.top.toString().indexOf('%') >= 0? (windowHeight*(parseInt($.prompt.options.top,10)/100)) : parseInt($.prompt.options.top,10)); + $('html,body').animate({ scrollTop: top }, 'slow', 'swing', function(){}); + } + } + // custom state width animation + else if(pos && pos.width){ + $.prompt.jqi.css({ + position: "absolute", + left: '50%' + }); + $.prompt.jqi.animate({ + top: pos.y || top, + left: pos.x || '50%', + marginLeft: ((pos.width/2)*-1), + width: pos.width + }); + } + // standard prompt positioning + else{ + $.prompt.jqi.css({ + position: "absolute", + top: top, + left: '50%',//$window.width()/2, + marginLeft: (($.prompt.jqi.outerWidth(false)/2)*-1) + }); + } + + // restore fx settings + if(e !== undefined && e.data.animate === false){ + $.fx.off = restoreFx; + } + }; + + /** + * style - Restyles the prompt (Used internally) + * @return void + */ + $.prompt.style = function(){ + $.prompt.jqif.css({ + zIndex: $.prompt.options.zIndex, + display: "none", + opacity: $.prompt.options.opacity + }); + $.prompt.jqi.css({ + zIndex: $.prompt.options.zIndex+1, + display: "none" + }); + $.prompt.jqib.css({ + zIndex: $.prompt.options.zIndex + }); + }; + + /** + * get - Get the prompt + * @return jQuery - the prompt + */ + $.prompt.get = function(state) { + return $('.'+ $.prompt.currentPrefix); + }; + + /** + * addState - Injects a state into the prompt + * @param statename String - Name of the state + * @param stateobj Object - options for the state + * @param afterState String - selector of the state to insert after + * @return jQuery - the newly created state + */ + $.prompt.addState = function(statename, stateobj, afterState) { + var state = "", + $state = null, + arrow = "", + title = "", + opts = $.prompt.options, + $jqistates = $('.'+ $.prompt.currentPrefix +'states'), + defbtn,k,v,i=0; + + stateobj = $.extend({},$.prompt.defaults.state, {name:statename}, stateobj); + + if(stateobj.position.arrow !== null){ + arrow = '
    '; + } + if(stateobj.title && stateobj.title !== ''){ + title = '
    '+ stateobj.title +'
    '; + } + state += ''; + + $state = $(state); + + $state.on('impromptu:submit', stateobj.submit); + + if(afterState !== undefined){ + $jqistates.find('#'+ $.prompt.currentPrefix +'state_'+ afterState).after($state); + } + else{ + $jqistates.append($state); + } + + $.prompt.options.states[statename] = stateobj; + + return $state; + }; + + /** + * removeState - Removes a state from the prompt + * @param state String - Name of the state + * @param newState String - Name of the state to transition to + * @return Boolean - returns true on success, false on failure + */ + $.prompt.removeState = function(state, newState) { + var $state = $.prompt.getState(state), + rm = function(){ $state.remove(); }; + + if($state.length === 0){ + return false; + } + + // transition away from it before deleting + if($state.css('display') !== 'none'){ + if(newState !== undefined && $.prompt.getState(newState).length > 0){ + $.prompt.goToState(newState, false, rm); + } + else if($state.next().length > 0){ + $.prompt.nextState(rm); + } + else if($state.prev().length > 0){ + $.prompt.prevState(rm); + } + else{ + $.prompt.close(); + } + } + else{ + $state.slideUp('slow', rm); + } + + return true; + }; + + /** + * getState - Get the state by its name + * @param state String - Name of the state + * @return jQuery - the state + */ + $.prompt.getState = function(state) { + return $('#'+ $.prompt.currentPrefix +'state_'+ state); + }; + $.prompt.getStateContent = function(state) { + return $.prompt.getState(state); + }; + + /** + * getCurrentState - Get the current visible state + * @return jQuery - the current visible state + */ + $.prompt.getCurrentState = function() { + return $.prompt.getState($.prompt.getCurrentStateName()); + }; + + /** + * getCurrentStateName - Get the name of the current visible state + * @return String - the current visible state's name + */ + $.prompt.getCurrentStateName = function() { + return $.prompt.currentStateName; + }; + + /** + * goToState - Goto the specified state + * @param state String - name of the state to transition to + * @param subState Boolean - true to be a sub state within the currently open state + * @param callback Function - called when the transition is complete + * @return jQuery - the newly active state + */ + $.prompt.goToState = function(state, subState, callback) { + var $jqi = $.prompt.get(), + jqiopts = $.prompt.options, + $state = $.prompt.getState(state), + stateobj = jqiopts.states[$state.data('jqi-name')], + promptstatechanginge = new $.Event('impromptu:statechanging'); + + // subState can be ommitted + if(typeof subState === 'function'){ + callback = subState; + subState = false; + } + + $.prompt.jqib.trigger(promptstatechanginge, [$.prompt.getCurrentStateName(), state]); + + if(!promptstatechanginge.isDefaultPrevented() && $state.length > 0){ + $.prompt.jqi.find('.'+ $.prompt.currentPrefix +'parentstate').removeClass($.prompt.currentPrefix +'parentstate'); + + if(subState){ // hide any open substates + // get rid of any substates + $.prompt.jqi.find('.'+ $.prompt.currentPrefix +'substate').not($state) + .slideUp(jqiopts.promptspeed) + .removeClass('.'+ $.prompt.currentPrefix +'substate') + .find('.'+ $.prompt.currentPrefix +'arrow').hide(); + + // add parent state class so it can be visible, but blocked + $.prompt.jqi.find('.'+ $.prompt.currentPrefix +'state:visible').addClass($.prompt.currentPrefix +'parentstate'); + + // add substate class so we know it will be smaller + $state.addClass($.prompt.currentPrefix +'substate'); + } + else{ // hide any open states + $.prompt.jqi.find('.'+ $.prompt.currentPrefix +'state').not($state) + .slideUp(jqiopts.promptspeed) + .find('.'+ $.prompt.currentPrefix +'arrow').hide(); + } + $.prompt.currentStateName = stateobj.name; + + $state.slideDown(jqiopts.promptspeed,function(){ + var $t = $(this); + + // if focus is a selector, find it, else its button index + if(typeof(stateobj.focus) === 'string'){ + $t.find(stateobj.focus).eq(0).focus(); + } + else{ + $t.find('.'+ $.prompt.currentPrefix +'defaultbutton').focus(); + } + + $t.find('.'+ $.prompt.currentPrefix +'arrow').show(jqiopts.promptspeed); + + if (typeof callback === 'function'){ + $.prompt.jqib.on('impromptu:statechanged', callback); + } + $.prompt.jqib.trigger('impromptu:statechanged', [state]); + if (typeof callback === 'function'){ + $.prompt.jqib.off('impromptu:statechanged', callback); + } + }); + if(!subState){ + $.prompt.position(); + } + } + return $state; + }; + + /** + * nextState - Transition to the next state + * @param callback Function - called when the transition is complete + * @return jQuery - the newly active state + */ + $.prompt.nextState = function(callback) { + var $next = $('#'+ $.prompt.currentPrefix +'state_'+ $.prompt.getCurrentStateName()).next(); + if($next.length > 0){ + $.prompt.goToState( $next.attr('id').replace($.prompt.currentPrefix +'state_',''), callback ); + } + return $next; + }; + + /** + * prevState - Transition to the previous state + * @param callback Function - called when the transition is complete + * @return jQuery - the newly active state + */ + $.prompt.prevState = function(callback) { + var $prev = $('#'+ $.prompt.currentPrefix +'state_'+ $.prompt.getCurrentStateName()).prev(); + if($prev.length > 0){ + $.prompt.goToState( $prev.attr('id').replace($.prompt.currentPrefix +'state_',''), callback ); + } + return $prev; + }; + + /** + * close - Closes the prompt + * @param callback Function - called when the transition is complete + * @param clicked String - value of the button clicked (only used internally) + * @param msg jQuery - The state message body (only used internally) + * @param forvals Object - key/value pairs of all form field names and values (only used internally) + * @return jQuery - the newly active state + */ + $.prompt.close = function(callCallback, clicked, msg, formvals){ + if($.prompt.timeout){ + clearTimeout($.prompt.timeout); + $.prompt.timeout = false; + } + + if($.prompt.jqib){ + $.prompt.jqib.fadeOut('fast',function(){ + + $.prompt.jqib.trigger('impromptu:close', [clicked,msg,formvals]); + + $.prompt.jqib.remove(); + + $(window).off('resize',$.prompt.position); + }); + } + $.prompt.currentStateName = ""; + }; + + /** + * Enable using $('.selector').prompt({}); + * This will grab the html within the prompt as the prompt message + */ + $.fn.prompt = function(options){ + if(options === undefined){ + options = {}; + } + if(options.withDataAndEvents === undefined){ + options.withDataAndEvents = false; + } + + $.prompt($(this).clone(options.withDataAndEvents).html(),options); + }; + +})(jQuery); + +/*! + * jQuery Cookie Plugin v1.3.1 + * https://github.com/carhartl/jquery-cookie + * + * Copyright 2013 Klaus Hartl + * Released under the MIT license + */ +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as anonymous module. + define(['jquery'], factory); + } else { + // Browser globals. + factory(jQuery); + } +}(function ($) { + + var pluses = /\+/g; + + function raw(s) { + return s; + } + + function decoded(s) { + return decodeURIComponent(s.replace(pluses, ' ')); + } + + function converted(s) { + if (s.indexOf('"') === 0) { + // This is a quoted cookie as according to RFC2068, unescape + s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); + } + try { + return config.json ? JSON.parse(s) : s; + } catch(er) {} + } + + var config = $.cookie = function (key, value, options) { + + // write + if (value !== undefined) { + options = $.extend({}, config.defaults, options); + + if (typeof options.expires === 'number') { + var days = options.expires, t = options.expires = new Date(); + t.setDate(t.getDate() + days); + } + + value = config.json ? JSON.stringify(value) : String(value); + + return (document.cookie = [ + config.raw ? key : encodeURIComponent(key), + '=', + config.raw ? value : encodeURIComponent(value), + options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE + options.path ? '; path=' + options.path : '', + options.domain ? '; domain=' + options.domain : '', + options.secure ? '; secure' : '' + ].join('')); + } + + // read + var decode = config.raw ? raw : decoded; + var cookies = document.cookie.split('; '); + var result = key ? undefined : {}; + for (var i = 0, l = cookies.length; i < l; i++) { + var parts = cookies[i].split('='); + var name = decode(parts.shift()); + var cookie = decode(parts.join('=')); + + if (key && key === name) { + result = converted(cookie); + break; + } + + if (!key) { + result[name] = converted(cookie); + } + } + + return result; + }; + + config.defaults = {}; + + $.removeCookie = function (key, options) { + if ($.cookie(key) !== undefined) { + // Must not alter options, thus extending a fresh object... + $.cookie(key, '', $.extend({}, options, { expires: -1 })); + return true; + } + return false; + }; + +})); \ No newline at end of file diff --git a/Upload/jscripts/jquery.plugins.min.js b/Upload/jscripts/jquery.plugins.min.js new file mode 100644 index 0000000..cf4f355 --- /dev/null +++ b/Upload/jscripts/jquery.plugins.min.js @@ -0,0 +1 @@ +(function(e){var t=function(){return false===e.support.boxModel&&e.support.objectAll&&e.support.leadingWhitespace}();e.jGrowl=function(t,n){if(e("#jGrowl").size()===0)e('
    ').addClass(n&&n.position?n.position:e.jGrowl.defaults.position).appendTo("body");e("#jGrowl").jGrowl(t,n)};e.fn.jGrowl=function(t,n){if(e.isFunction(this.each)){var r=arguments;return this.each(function(){if(e(this).data("jGrowl.instance")===undefined){e(this).data("jGrowl.instance",e.extend(new e.fn.jGrowl,{notifications:[],element:null,interval:null}));e(this).data("jGrowl.instance").startup(this)}if(e.isFunction(e(this).data("jGrowl.instance")[t])){e(this).data("jGrowl.instance")[t].apply(e(this).data("jGrowl.instance"),e.makeArray(r).slice(1))}else{e(this).data("jGrowl.instance").create(t,n)}})}};e.extend(e.fn.jGrowl.prototype,{defaults:{pool:0,header:"",group:"",sticky:false,position:"top-right",glue:"after",theme:"default",themeState:"highlight",corners:"10px",check:250,life:3e3,closeDuration:"normal",openDuration:"normal",easing:"swing",closer:true,closeTemplate:"×",closerTemplate:"
    [ close all ]
    ",log:function(){},beforeOpen:function(){},afterOpen:function(){},open:function(){},beforeClose:function(){},close:function(){},animateOpen:{opacity:"show"},animateClose:{opacity:"hide"}},notifications:[],element:null,interval:null,create:function(t,n){var r=e.extend({},this.defaults,n);if(typeof r.speed!=="undefined"){r.openDuration=r.speed;r.closeDuration=r.speed}this.notifications.push({message:t,options:r});r.log.apply(this.element,[this.element,t,r])},render:function(t){var n=this;var r=t.message;var i=t.options;i.themeState=i.themeState===""?"":"ui-state-"+i.themeState;var s=e("
    ").addClass("jGrowl-notification "+i.themeState+" ui-corner-all"+(i.group!==undefined&&i.group!==""?" "+i.group:"")).append(e("
    ").addClass("jGrowl-close").html(i.closeTemplate)).append(e("
    ").addClass("jGrowl-header").html(i.header)).append(e("
    ").addClass("jGrowl-message").html(r)).data("jGrowl",i).addClass(i.theme).children("div.jGrowl-close").bind("click.jGrowl",function(){e(this).parent().trigger("jGrowl.beforeClose")}).parent();e(s).bind("mouseover.jGrowl",function(){e("div.jGrowl-notification",n.element).data("jGrowl.pause",true)}).bind("mouseout.jGrowl",function(){e("div.jGrowl-notification",n.element).data("jGrowl.pause",false)}).bind("jGrowl.beforeOpen",function(){if(i.beforeOpen.apply(s,[s,r,i,n.element])!==false){e(this).trigger("jGrowl.open")}}).bind("jGrowl.open",function(){if(i.open.apply(s,[s,r,i,n.element])!==false){if(i.glue=="after"){e("div.jGrowl-notification:last",n.element).after(s)}else{e("div.jGrowl-notification:first",n.element).before(s)}e(this).animate(i.animateOpen,i.openDuration,i.easing,function(){if(e.support.opacity===false)this.style.removeAttribute("filter");if(e(this).data("jGrowl")!==null)e(this).data("jGrowl").created=new Date;e(this).trigger("jGrowl.afterOpen")})}}).bind("jGrowl.afterOpen",function(){i.afterOpen.apply(s,[s,r,i,n.element])}).bind("jGrowl.beforeClose",function(){if(i.beforeClose.apply(s,[s,r,i,n.element])!==false)e(this).trigger("jGrowl.close")}).bind("jGrowl.close",function(){e(this).data("jGrowl.pause",true);e(this).animate(i.animateClose,i.closeDuration,i.easing,function(){if(e.isFunction(i.close)){if(i.close.apply(s,[s,r,i,n.element])!==false)e(this).remove()}else{e(this).remove()}})}).trigger("jGrowl.beforeOpen");if(i.corners!==""&&e.fn.corner!==undefined)e(s).corner(i.corners);if(e("div.jGrowl-notification:parent",n.element).size()>1&&e("div.jGrowl-closer",n.element).size()===0&&this.defaults.closer!==false){e(this.defaults.closerTemplate).addClass("jGrowl-closer "+this.defaults.themeState+" ui-corner-all").addClass(this.defaults.theme).appendTo(n.element).animate(this.defaults.animateOpen,this.defaults.speed,this.defaults.easing).bind("click.jGrowl",function(){e(this).siblings().trigger("jGrowl.beforeClose");if(e.isFunction(n.defaults.closer)){n.defaults.closer.apply(e(this).parent()[0],[e(this).parent()[0]])}})}},update:function(){e(this.element).find("div.jGrowl-notification:parent").each(function(){if(e(this).data("jGrowl")!==undefined&&e(this).data("jGrowl").created!==undefined&&e(this).data("jGrowl").created.getTime()+parseInt(e(this).data("jGrowl").life,10)<(new Date).getTime()&&e(this).data("jGrowl").sticky!==true&&(e(this).data("jGrowl.pause")===undefined||e(this).data("jGrowl.pause")!==true)){e(this).trigger("jGrowl.beforeClose")}});if(this.notifications.length>0&&(this.defaults.pool===0||e(this.element).find("div.jGrowl-notification:parent").size()
    ');this.interval=setInterval(function(){e(n).data("jGrowl.instance").update()},parseInt(this.defaults.check,10));if(t){e(this.element).addClass("ie6")}},shutdown:function(){e(this.element).removeClass("jGrowl").find("div.jGrowl-notification").trigger("jGrowl.close").parent().empty();clearInterval(this.interval)},close:function(){e(this.element).find("div.jGrowl-notification").each(function(){e(this).trigger("jGrowl.beforeClose")})}});e.jGrowl.defaults=e.fn.jGrowl.prototype.defaults})(jQuery);(function(e){var t=null;e.modal=function(n,r){e.modal.close();var i,s;this.$body=e("body");this.options=e.extend({},e.modal.defaults,r);this.options.doFade=!isNaN(parseInt(this.options.fadeDuration,10));if(n.is("a")){s=n.attr("href");if(/^#/.test(s)){this.$elm=e(s);if(this.$elm.length!==1)return null;this.open()}else{this.$elm=e("
    ");this.$body.append(this.$elm);i=function(e,t){t.elm.remove()};this.showSpinner();n.trigger(e.modal.AJAX_SEND);e.get(s).done(function(r){if(!t)return;n.trigger(e.modal.AJAX_SUCCESS);t.$elm.empty().append(r).on(e.modal.CLOSE,i);t.hideSpinner();t.open();n.trigger(e.modal.AJAX_COMPLETE)}).fail(function(){n.trigger(e.modal.AJAX_FAIL);t.hideSpinner();n.trigger(e.modal.AJAX_COMPLETE)})}}else{this.$elm=n;this.open()}};e.modal.prototype={constructor:e.modal,open:function(){var t=this;if(this.options.doFade){this.block();setTimeout(function(){t.show()},this.options.fadeDuration*this.options.fadeDelay)}else{this.block();this.show()}if(this.options.escapeClose){e(document).on("keydown.modal",function(t){if(t.which==27)e.modal.close()})}if(this.options.clickClose)this.blocker.click(e.modal.close)},close:function(){this.unblock();this.hide();if(!this.options.keepelement)this.$elm.remove();e(document).off("keydown.modal")},block:function(){var t=this.options.doFade?0:this.options.opacity;this.$elm.trigger(e.modal.BEFORE_BLOCK,[this._ctx()]);this.blocker=e('
    ').css({top:0,right:0,bottom:0,left:0,width:"100%",height:"100%",position:"fixed",zIndex:this.options.zIndex,background:this.options.overlay,opacity:t});this.$body.append(this.blocker);if(this.options.doFade){this.blocker.animate({opacity:this.options.opacity},this.options.fadeDuration)}this.$elm.trigger(e.modal.BLOCK,[this._ctx()])},unblock:function(){if(this.options.doFade){this.blocker.fadeOut(this.options.fadeDuration,function(){e(this).remove()})}else{this.blocker.remove()}},show:function(){this.$elm.trigger(e.modal.BEFORE_OPEN,[this._ctx()]);if(this.options.showClose){this.closeButton=e(''+this.options.closeText+"");this.$elm.append(this.closeButton)}this.$elm.addClass(this.options.modalClass+" current");this.center();if(this.options.doFade){this.$elm.fadeIn(this.options.fadeDuration)}else{this.$elm.show()}this.$elm.trigger(e.modal.OPEN,[this._ctx()])},hide:function(){this.$elm.trigger(e.modal.BEFORE_CLOSE,[this._ctx()]);if(this.closeButton)this.closeButton.remove();this.$elm.removeClass("current");if(this.options.doFade){this.$elm.fadeOut(this.options.fadeDuration)}else{this.$elm.hide()}this.$elm.trigger(e.modal.CLOSE,[this._ctx()])},showSpinner:function(){if(!this.options.showSpinner)return;this.spinner=this.spinner||e('
    ').append(this.options.spinnerHtml);this.$body.append(this.spinner);this.spinner.show()},hideSpinner:function(){if(this.spinner)this.spinner.remove()},center:function(){this.$elm.css({position:"fixed",top:"50%",left:"50%",marginTop:-(this.$elm.outerHeight()/2),marginLeft:-(this.$elm.outerWidth()/2),zIndex:this.options.zIndex+1})},_ctx:function(){return{elm:this.$elm,blocker:this.blocker,options:this.options}}};e.modal.prototype.resize=e.modal.prototype.center;e.modal.close=function(e){if(!t)return;if(e)e.preventDefault();t.close();var n=t.$elm;t=null;return n};e.modal.resize=function(){if(!t)return;t.resize()};e.modal.isActive=function(){return t?true:false};e.modal.defaults={overlay:"#000",opacity:.75,zIndex:1,escapeClose:true,clickClose:true,closeText:"Close",closeClass:"",modalClass:"modal",spinnerHtml:null,showSpinner:true,showClose:true,fadeDuration:null,fadeDelay:1,keepelement:false};e.modal.BEFORE_BLOCK="modal:before-block";e.modal.BLOCK="modal:block";e.modal.BEFORE_OPEN="modal:before-open";e.modal.OPEN="modal:open";e.modal.BEFORE_CLOSE="modal:before-close";e.modal.CLOSE="modal:close";e.modal.AJAX_SEND="modal:ajax:send";e.modal.AJAX_SUCCESS="modal:ajax:success";e.modal.AJAX_FAIL="modal:ajax:fail";e.modal.AJAX_COMPLETE="modal:ajax:complete";e.fn.modal=function(n){if(this.length===1){t=new e.modal(this,n)}return this};e(document).on("click.modal",'a[rel="modal:close"]',e.modal.close);e(document).on("click.modal",'a[rel="modal:open"]',function(t){t.preventDefault();e(this).modal()})})(jQuery);(function(e){var t="";var n=function(t,n){var t=e(t);var r=this;var i=e("#"+t.attr("id")+"_popup");if(typeof n=="undefined"){var n=true}this.open=function(s){s.preventDefault();if(i.is(":visible")){r.close();return}var o=t.offset();o.top+=t.outerHeight();if(t.offset().left+i.outerWidth()>e(window).width())var u=i.outerWidth()-t.outerWidth();else var u=0;i.css({position:"absolute",top:o.top,left:o.left-u});i.show();e("body, .popup_item").bind("click.close_popup",function(i){if(n){if(e(i.target).closest("#"+t.attr("id")).length==0){r.close()}}else{if(e(i.target).closest("#"+t.attr("id")).length==0&&e(i.target).closest("#"+t.attr("id")+"_popup").length==0){r.close()}}})};this.close=function(e){i.hide()}};e.fn.popupMenu=function(t){return this.each(function(){var r=new n(this,t);e(this).click(r.open)})}})(jQuery);(function(e){"use strict";e.prompt=function(t,n){if(n!==undefined&&n.classes!==undefined&&typeof n.classes==="string"){n={box:n.classes}}e.prompt.options=e.extend({},e.prompt.defaults,n);e.prompt.currentPrefix=e.prompt.options.prefix;if(e.prompt.timeout){clearTimeout(e.prompt.timeout)}e.prompt.timeout=false;var r=e.prompt.options,i=e(document.body),s=e(window);var o='
    ';if(r.useiframe&&e("object, applet").length>0){o+=''}else{o+='
    '}o+='
    '+'
    '+'
    '+r.closeText+"
    "+'
    '+""+"
    "+"
    ";e.prompt.jqib=e(o).appendTo(i);e.prompt.jqi=e.prompt.jqib.children("."+r.prefix);e.prompt.jqif=e.prompt.jqib.children("."+r.prefix+"fade");if(t.constructor===String){t={state0:{title:r.title,html:t,buttons:r.buttons,position:r.position,focus:r.focus,defaultButton:r.defaultButton,submit:r.submit}}}e.prompt.options.states={};var u,a;for(u in t){a=e.extend({},e.prompt.defaults.state,{name:u},t[u]);e.prompt.addState(a.name,a);if(e.prompt.currentStateName===""){e.prompt.currentStateName=a.name}}e.prompt.jqi.on("click","."+r.prefix+"buttons button",function(t){var n=e(this),i=n.parents("."+r.prefix+"state"),s=e.prompt.options.states[i.data("jqi-name")],o=i.children("."+r.prefix+"message"),u=s.buttons[n.text()]||s.buttons[n.html()],a={};if(u===undefined){for(var f in s.buttons){if(s.buttons[f].title===n.text()||s.buttons[f].title===n.html()){u=s.buttons[f].value}}}e.each(e.prompt.jqi.children("form").serializeArray(),function(e,t){if(a[t.name]===undefined){a[t.name]=t.value}else if(typeof a[t.name]===Array||typeof a[t.name]==="object"){a[t.name].push(t.value)}else{a[t.name]=[a[t.name],t.value]}});var l=new e.Event("impromptu:submit");l.stateName=s.name;l.state=i;i.trigger(l,[u,o,a]);if(!l.isDefaultPrevented()){e.prompt.close(true,u,o,a)}});var f=function(){if(r.persistent){var t=r.top.toString().indexOf("%")>=0?s.height()*(parseInt(r.top,10)/100):parseInt(r.top,10),n=parseInt(e.prompt.jqi.css("top").replace("px",""),10)-t;e("html,body").animate({scrollTop:n},"fast",function(){var t=0;e.prompt.jqib.addClass(r.prefix+"warning");var n=setInterval(function(){e.prompt.jqib.toggleClass(r.prefix+"warning");if(t++>1){clearInterval(n);e.prompt.jqib.removeClass(r.prefix+"warning")}},100)})}else{e.prompt.close(true)}};var l=function(t){var n=window.event?event.keyCode:t.keyCode;if(n===27){f()}if(n===13){var i=e.prompt.getCurrentState().find("."+r.prefix+"defaultbutton");var s=e(t.target);if(s.is("textarea,."+r.prefix+"button")===false&&i.length>0){t.preventDefault();i.click()}}if(n===9){var o=e("input,select,textarea,button",e.prompt.getCurrentState());var u=!t.shiftKey&&t.target===o[o.length-1];var a=t.shiftKey&&t.target===o[0];if(u||a){setTimeout(function(){if(!o){return}var e=o[a===true?o.length-1:0];if(e){e.focus()}},10);return false}}};e.prompt.position();e.prompt.style();e.prompt.jqif.click(f);s.resize({animate:false},e.prompt.position);e.prompt.jqi.find("."+r.prefix+"close").click(e.prompt.close);e.prompt.jqib.on("keydown",l).on("impromptu:loaded",r.loaded).on("impromptu:close",r.close).on("impromptu:statechanging",r.statechanging).on("impromptu:statechanged",r.statechanged);e.prompt.jqif[r.show](r.overlayspeed);e.prompt.jqi[r.show](r.promptspeed,function(){var t=e.prompt.jqi.find("."+r.prefix+"states ."+r.prefix+"state").eq(0);e.prompt.goToState(t.data("jqi-name"));e.prompt.jqib.trigger("impromptu:loaded")});if(r.timeout>0){e.prompt.timeout=setTimeout(function(){e.prompt.close(true)},r.timeout)}return e.prompt.jqib};e.prompt.defaults={prefix:"jqi",classes:{box:"",fade:"",prompt:"",form:"",close:"",title:"",message:"",buttons:"",button:"",defaultButton:""},title:"",closeText:"×",buttons:{Ok:true},loaded:function(e){},submit:function(e,t,n,r){},close:function(e,t,n,r){},statechanging:function(e,t,n){},statechanged:function(e,t){},opacity:.6,zIndex:999,overlayspeed:"slow",promptspeed:"fast",show:"fadeIn",focus:0,defaultButton:0,useiframe:false,top:"15%",position:{container:null,x:null,y:null,arrow:null,width:null},persistent:true,timeout:0,states:{},state:{name:null,title:"",html:"",buttons:{Ok:true},focus:0,defaultButton:0,position:{container:null,x:null,y:null,arrow:null,width:null},submit:function(e,t,n,r){return true}}};e.prompt.currentPrefix=e.prompt.defaults.prefix;e.prompt.currentStateName="";e.prompt.setDefaults=function(t){e.prompt.defaults=e.extend({},e.prompt.defaults,t)};e.prompt.setStateDefaults=function(t){e.prompt.defaults.state=e.extend({},e.prompt.defaults.state,t)};e.prompt.position=function(t){var n=e.fx.off,r=e.prompt.getCurrentState(),i=e.prompt.options.states[r.data("jqi-name")],s=i?i.position:undefined,o=e(window),u=document.body.scrollHeight,a=e(window).height(),f=e(document).height(),l=u>a?u:a,c=parseInt(o.scrollTop(),10)+(e.prompt.options.top.toString().indexOf("%")>=0?a*(parseInt(e.prompt.options.top,10)/100):parseInt(e.prompt.options.top,10));if(t!==undefined&&t.data.animate===false){e.fx.off=true}e.prompt.jqib.css({position:"absolute",height:l,width:"100%",top:0,left:0,right:0,bottom:0});e.prompt.jqif.css({position:"fixed",height:l,width:"100%",top:0,left:0,right:0,bottom:0});if(s&&s.container){var h=e(s.container).offset();if(e.isPlainObject(h)&&h.top!==undefined){e.prompt.jqi.css({position:"absolute"});e.prompt.jqi.animate({top:h.top+s.y,left:h.left+s.x,marginLeft:0,width:s.width!==undefined?s.width:null});c=h.top+s.y-(e.prompt.options.top.toString().indexOf("%")>=0?a*(parseInt(e.prompt.options.top,10)/100):parseInt(e.prompt.options.top,10));e("html,body").animate({scrollTop:c},"slow","swing",function(){})}}else if(s&&s.width){e.prompt.jqi.css({position:"absolute",left:"50%"});e.prompt.jqi.animate({top:s.y||c,left:s.x||"50%",marginLeft:s.width/2*-1,width:s.width})}else{e.prompt.jqi.css({position:"absolute",top:c,left:"50%",marginLeft:e.prompt.jqi.outerWidth(false)/2*-1})}if(t!==undefined&&t.data.animate===false){e.fx.off=n}};e.prompt.style=function(){e.prompt.jqif.css({zIndex:e.prompt.options.zIndex,display:"none",opacity:e.prompt.options.opacity});e.prompt.jqi.css({zIndex:e.prompt.options.zIndex+1,display:"none"});e.prompt.jqib.css({zIndex:e.prompt.options.zIndex})};e.prompt.get=function(t){return e("."+e.prompt.currentPrefix)};e.prompt.addState=function(t,n,r){var i="",s=null,o="",u="",a=e.prompt.options,f=e("."+e.prompt.currentPrefix+"states"),l,c,h,p=0;n=e.extend({},e.prompt.defaults.state,{name:t},n);if(n.position.arrow!==null){o='
    '}if(n.title&&n.title!==""){u='
    '+n.title+"
    "}i+='";s=e(i);s.on("impromptu:submit",n.submit);if(r!==undefined){f.find("#"+e.prompt.currentPrefix+"state_"+r).after(s)}else{f.append(s)}e.prompt.options.states[t]=n;return s};e.prompt.removeState=function(t,n){var r=e.prompt.getState(t),i=function(){r.remove()};if(r.length===0){return false}if(r.css("display")!=="none"){if(n!==undefined&&e.prompt.getState(n).length>0){e.prompt.goToState(n,false,i)}else if(r.next().length>0){e.prompt.nextState(i)}else if(r.prev().length>0){e.prompt.prevState(i)}else{e.prompt.close()}}else{r.slideUp("slow",i)}return true};e.prompt.getState=function(t){return e("#"+e.prompt.currentPrefix+"state_"+t)};e.prompt.getStateContent=function(t){return e.prompt.getState(t)};e.prompt.getCurrentState=function(){return e.prompt.getState(e.prompt.getCurrentStateName())};e.prompt.getCurrentStateName=function(){return e.prompt.currentStateName};e.prompt.goToState=function(t,n,r){var i=e.prompt.get(),s=e.prompt.options,o=e.prompt.getState(t),u=s.states[o.data("jqi-name")],a=new e.Event("impromptu:statechanging");if(typeof n==="function"){r=n;n=false}e.prompt.jqib.trigger(a,[e.prompt.getCurrentStateName(),t]);if(!a.isDefaultPrevented()&&o.length>0){e.prompt.jqi.find("."+e.prompt.currentPrefix+"parentstate").removeClass(e.prompt.currentPrefix+"parentstate");if(n){e.prompt.jqi.find("."+e.prompt.currentPrefix+"substate").not(o).slideUp(s.promptspeed).removeClass("."+e.prompt.currentPrefix+"substate").find("."+e.prompt.currentPrefix+"arrow").hide();e.prompt.jqi.find("."+e.prompt.currentPrefix+"state:visible").addClass(e.prompt.currentPrefix+"parentstate");o.addClass(e.prompt.currentPrefix+"substate")}else{e.prompt.jqi.find("."+e.prompt.currentPrefix+"state").not(o).slideUp(s.promptspeed).find("."+e.prompt.currentPrefix+"arrow").hide()}e.prompt.currentStateName=u.name;o.slideDown(s.promptspeed,function(){var n=e(this);if(typeof u.focus==="string"){n.find(u.focus).eq(0).focus()}else{n.find("."+e.prompt.currentPrefix+"defaultbutton").focus()}n.find("."+e.prompt.currentPrefix+"arrow").show(s.promptspeed);if(typeof r==="function"){e.prompt.jqib.on("impromptu:statechanged",r)}e.prompt.jqib.trigger("impromptu:statechanged",[t]);if(typeof r==="function"){e.prompt.jqib.off("impromptu:statechanged",r)}});if(!n){e.prompt.position()}}return o};e.prompt.nextState=function(t){var n=e("#"+e.prompt.currentPrefix+"state_"+e.prompt.getCurrentStateName()).next();if(n.length>0){e.prompt.goToState(n.attr("id").replace(e.prompt.currentPrefix+"state_",""),t)}return n};e.prompt.prevState=function(t){var n=e("#"+e.prompt.currentPrefix+"state_"+e.prompt.getCurrentStateName()).prev();if(n.length>0){e.prompt.goToState(n.attr("id").replace(e.prompt.currentPrefix+"state_",""),t)}return n};e.prompt.close=function(t,n,r,i){if(e.prompt.timeout){clearTimeout(e.prompt.timeout);e.prompt.timeout=false}if(e.prompt.jqib){e.prompt.jqib.fadeOut("fast",function(){e.prompt.jqib.trigger("impromptu:close",[n,r,i]);e.prompt.jqib.remove();e(window).off("resize",e.prompt.position)})}e.prompt.currentStateName=""};e.fn.prompt=function(t){if(t===undefined){t={}}if(t.withDataAndEvents===undefined){t.withDataAndEvents=false}e.prompt(e(this).clone(t.withDataAndEvents).html(),t)}})(jQuery);(function(e){if(typeof define==="function"&&define.amd){define(["jquery"],e)}else{e(jQuery)}})(function(e){function n(e){return e}function r(e){return decodeURIComponent(e.replace(t," "))}function i(e){if(e.indexOf('"')===0){e=e.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\")}try{return s.json?JSON.parse(e):e}catch(t){}}var t=/\+/g;var s=e.cookie=function(t,o,u){if(o!==undefined){u=e.extend({},s.defaults,u);if(typeof u.expires==="number"){var a=u.expires,f=u.expires=new Date;f.setDate(f.getDate()+a)}o=s.json?JSON.stringify(o):String(o);return document.cookie=[s.raw?t:encodeURIComponent(t),"=",s.raw?o:encodeURIComponent(o),u.expires?"; expires="+u.expires.toUTCString():"",u.path?"; path="+u.path:"",u.domain?"; domain="+u.domain:"",u.secure?"; secure":""].join("")}var l=s.raw?n:r;var c=document.cookie.split("; ");var h=t?undefined:{};for(var p=0,d=c.length;p"); + var list_element_a = $(""); + list_element_a.addClass(list_classes[i]) + .attr("title", lang.stars[i]) + .attr("href", "./ratethread.php?tid="+tid+"&rating="+i+"&my_post_key="+my_post_key) + .html(i); + list_element.append(list_element_a); + list.append(list_element); + } + }, + + add_rating: function(parameterString) + { + var tid = parameterString.match(/tid=(.*)&(.*)&/)[1]; + var rating = parameterString.match(/rating=(.*)&(.*)/)[1]; + $.ajax( + { + url: 'ratethread.php?ajax=1&my_post_key='+my_post_key+'&tid='+tid+'&rating='+rating, + async: true, + method: 'post', + dataType: 'json', + complete: function (request) + { + Rating.rating_added(request, tid); + } + }); + return false; + }, + + rating_added: function(request, element_id) + { + var json = $.parseJSON(request.responseText); + if(json.hasOwnProperty("errors")) + { + $.each(json.errors, function(i, error) + { + $.jGrowl(lang.ratings_update_error + ' ' + error); + }); + } + else if(json.hasOwnProperty("success")) + { + var element = $("#rating_thread_"+element_id); + element.parent().before(element.next()); + element.removeClass("star_rating_notrated"); + + $.jGrowl(json.success); + if(json.hasOwnProperty("average")) + { + $("#current_rating_"+element_id).html(json.average); + } + + var rating_elements = $(".star_rating"); + rating_elements.each(function() + { + var rating_element = $(this); + var elements = rating_element.find("li a"); + if(rating_element.hasClass('star_rating_notrated')) + { + elements.each(function() + { + var element = $(this); + if(element.attr("id") == "rating_thread_" + element_id) + { + element.attr("onclick", "return false;") + .css("cursor", "default") + .attr("title", $("#current_rating_"+element_id).text()); + } + }); + } + }); + $("#current_rating_"+element_id).css("width", json.width+"%"); + } + } +}; + +if(use_xmlhttprequest == 1) +{ + $(function() + { + Rating.init(); + }); +} \ No newline at end of file diff --git a/Upload/jscripts/report.js b/Upload/jscripts/report.js new file mode 100644 index 0000000..15fea7f --- /dev/null +++ b/Upload/jscripts/report.js @@ -0,0 +1,48 @@ +var Report = { + init: function() + { + $(document).ready(function(){ + }); + }, + + reportPost: function(pid) + { + MyBB.popupWindow("/report.php?type=post&pid="+pid); + }, + + reportUser: function(pid) + { + MyBB.popupWindow("/report.php?type=profile&pid="+pid); + }, + + reportReputation: function(pid) + { + MyBB.popupWindow("/report.php?type=reputation&pid="+pid); + }, + + submitReport: function(pid) + { + // Get form, serialize it and send it + var datastring = $(".reportData_"+pid).serialize(); + $.ajax({ + type: "POST", + url: "report.php", + data: datastring, + dataType: "html", + success: function(data) { + // Replace modal HTML + $('.modal_'+pid).fadeOut('slow', function() { + $('.modal_'+pid).html(data); + $('.modal_'+pid).fadeIn('slow'); + }); + }, + error: function(){ + alert(lang.unknown_error); + } + }); + + return false; + } +}; + +Report.init(); \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_plugins/bbcode.js b/Upload/jscripts/sceditor/editor_plugins/bbcode.js new file mode 100644 index 0000000..fff8d70 --- /dev/null +++ b/Upload/jscripts/sceditor/editor_plugins/bbcode.js @@ -0,0 +1,2 @@ +/* SCEditor v1.4.5 | (C) 2011-2013, Sam Clarke | sceditor.com/license */ +!function(a,b,c){"use strict";var d=a.sceditor.escapeEntities,e=a.sceditor.escapeUriScheme,f=a.sceditor.ie,g=f&&11>f;a.sceditor.BBCodeParser=function(b){if(!(this instanceof a.sceditor.BBCodeParser))return new a.sceditor.BBCodeParser(b);var e,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v=this,w={open:"open",content:"content",newline:"newline",close:"close"},x=function(a,b,c,d,e,f){var g=this;g.type=a,g.name=b,g.val=c,g.attrs=d||{},g.children=e||[],g.closing=f||null};x.prototype={clone:function(a){var b=this;return new x(b.type,b.name,b.val,b.attrs,a?b.children:[],b.closing?b.closing.clone():null)},splitAt:function(b){var c,d=this,e=0,f=d.children.length;if("number"!=typeof b&&(b=a.inArray(b,d.children)),0>b||b>f)return null;for(;f--;)f>=b?e++:f=0;return c=d.clone(),c.children=d.children.splice(b,e),c}},e=function(){v.opts=a.extend({},a.sceditor.BBCodeParser.defaults,b),v.bbcodes=a.sceditor.plugins.bbcode.bbcodes},v.tokenize=function(a){var b,c,d,e=[],f=[{type:"close",regex:/^\[\/[^\[\]]+\]/},{type:"open",regex:/^\[[^\[\]]+\]/},{type:"newline",regex:/^(\r\n|\r|\n)/},{type:"content",regex:/^([^\[\r\n]+|\[)/}];f.reverse();a:for(;a.length;){for(d=f.length;d--;)if(c=f[d].type,(b=a.match(f[d].regex))&&b[0]){e.push(h(c,b[0])),a=a.substr(b[0].length);continue a}a.length&&e.push(h(w.content,a)),a=""}return e},h=function(b,c){var d,e,f;return"open"===b&&(d=c.match(/\[([^\]\s=]+)(?:([^\]]+))?\]/))?(f=t(d[1]),d[2]&&(d[2]=a.trim(d[2]))&&(e=i(d[2]))):"close"===b&&(d=c.match(/\[\/([^\[\]]+)\]/))?f=t(d[1]):"newline"===b&&(f="#newline"),f&&("open"!==b&&"close"!==b||a.sceditor.plugins.bbcode.bbcodes[f])||(b="content",f="#"),new x(b,f,c,e)},i=function(b){var c,d=/([^\s=]+)=(?:(?:(["'])((?:\\\2|[^\2])*?)\2)|((?:.(?!\s\S+=))*.))/g,e=a.sceditor.plugins.bbcode.stripQuotes,f={};if("="===b.charAt(0)&&b.indexOf("=",1)<0)f.defaultattr=e(b.substr(1));else for("="===b.charAt(0)&&(b="defaultattr"+b);c=d.exec(b);)f[t(c[1])]=e(c[3])||c[4];return f},v.parse=function(a,b){var c=j(v.tokenize(a));return v.opts.fixInvalidChildren&&o(c),v.opts.removeEmptyTags&&n(c),v.opts.fixInvalidNesting&&l(c),k(c,null,b),v.opts.removeEmptyTags&&n(c),c},r=function(a,b,c){for(var d=c.length;d--;)if(c[d].type===b&&c[d].name===a)return!0;return!1},m=function(b,c){var d=b?v.bbcodes[b.name]:null,e=d?d.allowedChildren:null;return v.opts.fixInvalidChildren&&e&&e&&a.inArray(c.name||"#",e)<0?!1:!0},j=function(b){for(var c,d,e,f,g,h,i,j=[],k=[],l=[],m=function(){return u(l)},n=function(a){m()?m().children.push(a):k.push(a)},o=function(b){return m()&&(d=v.bbcodes[m().name])&&d.closedBy&&a.inArray(b,d.closedBy)>-1};c=b.shift();){switch(i=b[0],c.type){case w.open:o(c.name)&&l.pop(),n(c),d=v.bbcodes[c.name],d&&d.isSelfClosing||!d.closedBy&&!r(c.name,w.close,b)?d&&d.isSelfClosing||(c.type=w.content):l.push(c);break;case w.close:if(m()&&c.name!==m().name&&o("/"+c.name)&&l.pop(),m()&&c.name===m().name)m().closing=c,l.pop();else if(r(c.name,w.open,l)){for(;e=l.pop();){if(e.name===c.name){e.closing=c;break}f=e.clone(),j.length>1&&f.children.push(u(j)),j.push(f)}for(n(u(j)),g=j.length;g--;)l.push(j[g]);j.length=0}else c.type=w.content,n(c);break;case w.newline:m()&&i&&o((i.type===w.close?"/":"")+i.name)&&(i.type!==w.close||i.name!==m().name)&&(d=v.bbcodes[m().name],d&&d.breakAfter?l.pop():d&&d.isInline===!1&&v.opts.breakAfterBlock&&d.breakAfter!==!1&&l.pop()),n(c);break;default:n(c)}h=c}return k},k=function(a,b,c){var d,e,f,g,h,i,j,l,m=a.length,n=m;for(b&&(g=v.bbcodes[b.name]);n--;)if(d=a[n])if(d.type===w.newline){if(e=n>0?a[n-1]:null,f=m-1>n?a[n+1]:null,l=!1,!c&&g&&g.isSelfClosing!==!0&&(e?i||f||(g.isInline===!1&&v.opts.breakEndBlock&&g.breakEnd!==!1&&(l=!0),g.breakEnd&&(l=!0),i=l):(g.isInline===!1&&v.opts.breakStartBlock&&g.breakStart!==!1&&(l=!0),g.breakStart&&(l=!0))),e&&e.type===w.open&&(h=v.bbcodes[e.name])&&(c?h.isInline===!1&&(l=!0):(h.isInline===!1&&v.opts.breakAfterBlock&&h.breakAfter!==!1&&(l=!0),h.breakAfter&&(l=!0))),!c&&!j&&f&&f.type===w.open&&(h=v.bbcodes[f.name])&&(h.isInline===!1&&v.opts.breakBeforeBlock&&h.breakBefore!==!1&&(l=!0),h.breakBefore&&(l=!0),j=l,l)){a.splice(n,1);continue}l&&a.splice(n,1),j=!1}else d.type===w.open&&k(d.children,d,c)},l=function(b,c,d,e){var f,g,h,i,j,k,m=function(a){var b=v.bbcodes[a.name];return!b||b.isInline!==!1};for(c=c||[],e=e||b,g=0;g1?c[c.length-2].children:e,(i=a.inArray(h,j))>-1))return k.children.splice(a.inArray(f,k.children),1),void j.splice(i+1,0,f,k);c.push(f),l(f.children,c,d||m(f),e),c.pop(f)}},o=function(a,b){for(var c,d,e=a.length;e--;)(c=a[e])&&(m(b,c)||(c.name=null,c.type=w.content,m(b,c)?(d=[e+1,0].concat(c.children),c.closing&&(c.closing.name=null,c.closing.type=w.content,d.push(c.closing)),e+=d.length-1,Array.prototype.splice.apply(a,d)):b.children.splice(e,1)),c.type===w.open&&o(c.children,c))},n=function(b){var c,d,e,f=b.length;for(e=function(a){for(var b=a.length;b--;){if(a[b].type===w.open)return!1;if(a[b].type===w.close)return!1;if(a[b].type===w.content&&a[b].val&&/\S|\u00A0/.test(a[b].val))return!1}return!0};f--;)(c=b[f])&&c.type===w.open&&(d=v.bbcodes[c.name],n(c.children),e(c.children)&&d&&!d.isSelfClosing&&!d.allowsEmpty&&b.splice.apply(b,a.merge([f,1],c.children)))},v.toHTML=function(a,b){return p(v.parse(a,b),!0)},p=function(b,e){var h,i,j,k,l,m,n,o,q=[];for(n=function(a){return(!a||("undefined"!=typeof a.isHtmlInline?a.isHtmlInline:a.isInline))!==!1};b.length>0;)if(h=b.shift()){if(h.type===w.open)o=h.children[h.children.length-1]||{},i=v.bbcodes[h.name],l=e&&n(i),j=p(h.children,!1),i&&i.html?(n(i)||!n(v.bbcodes[o.name])||i.isPreFormatted||i.skipLastLineBreak||g||(j+="
    "),a.isFunction(i.html)?k=i.html.call(v,h,h.attrs,j):(h.attrs[0]=j,k=a.sceditor.plugins.bbcode.formatBBCodeString(i.html,h.attrs))):k=h.val+j+(h.closing?h.closing.val:"");else{if(h.type===w.newline){if(!e){q.push("
    ");continue}m||(q.push("
    "),(c.documentMode&&c.documentMode<8||8>f)&&q.push(" ")),g||q.push("
    "),b.length||q.push("
    "),q.push("
    \n"),m=!1;continue}l=e,k=d(h.val,!0)}l&&!m?(q.push("
    "),m=!0):!l&&m&&(q.push("
    \n"),m=!1),q.push(k)}return m&&q.push("
    \n"),q.join("")},v.toBBCode=function(a,b){return q(v.parse(a,b))},q=function(b){for(var c,d,e,f,g,h,i,j,k,l,m=[];b.length>0;)if(c=b.shift())if(e=v.bbcodes[c.name],f=!(!e||e.isInline!==!1),g=e&&e.isSelfClosing,i=f&&v.opts.breakBeforeBlock&&e.breakBefore!==!1||e&&e.breakBefore,j=f&&!g&&v.opts.breakStartBlock&&e.breakStart!==!1||e&&e.breakStart,k=f&&v.opts.breakEndBlock&&e.breakEnd!==!1||e&&e.breakEnd,l=f&&v.opts.breakAfterBlock&&e.breakAfter!==!1||e&&e.breakAfter,h=(e?e.quoteType:null)||v.opts.quoteType||a.sceditor.BBCodeParser.QuoteType.auto,e||c.type!==w.open)if(c.type===w.open){if(i&&m.push("\n"),m.push("["+c.name),c.attrs){c.attrs.defaultattr&&(m.push("="+s(c.attrs.defaultattr,h,"defaultattr")),delete c.attrs.defaultattr);for(d in c.attrs)c.attrs.hasOwnProperty(d)&&m.push(" "+d+"="+s(c.attrs[d],h,d))}m.push("]"),j&&m.push("\n"),c.children&&m.push(q(c.children)),g||e.excludeClosing||(k&&m.push("\n"),m.push("[/"+c.name+"]")),l&&m.push("\n"),c.closing&&g&&m.push(c.closing.val)}else m.push(c.val);else m.push(c.val),c.children&&m.push(q(c.children)),c.closing&&m.push(c.closing.val);return m.join("")},s=function(b,c,d){var e=a.sceditor.BBCodeParser.QuoteType,f=/\s|=/.test(b);return a.isFunction(c)?c(b,d):c===e.never||c===e.auto&&!f?b:'"'+b.replace("\\","\\\\").replace('"','\\"')+'"'},u=function(a){return a.length?a[a.length-1]:null},t=function(a){return a.toLowerCase()},e()},a.sceditor.BBCodeParser.QuoteType={always:1,never:2,auto:3},a.sceditor.BBCodeParser.defaults={breakBeforeBlock:!1,breakStartBlock:!1,breakEndBlock:!1,breakAfterBlock:!0,removeEmptyTags:!0,fixInvalidNesting:!0,fixInvalidChildren:!0,quoteType:a.sceditor.BBCodeParser.QuoteType.auto},a.sceditorBBCodePlugin=a.sceditor.plugins.bbcode=function(){var b,d,e,f,h,i,j=this;f=a.sceditor.plugins.bbcode.formatString,j.bbcodes=a.sceditor.plugins.bbcode.bbcodes,j.stripQuotes=a.sceditor.plugins.bbcode.stripQuotes;var k={},l={},m={ul:["li","ol","ul"],ol:["li","ol","ul"],table:["tr"],tr:["td","th"],code:["br","p","div"]};j.init=function(){j.opts=this.opts,b(),h(this),this.toBBCode=j.signalToSource,this.fromBBCode=j.signalToWysiwyg},h=function(b){var c=a.sceditor.command.get,d={bold:{txtExec:["[b]","[/b]"]},italic:{txtExec:["[i]","[/i]"]},underline:{txtExec:["[u]","[/u]"]},strike:{txtExec:["[s]","[/s]"]},subscript:{txtExec:["[sub]","[/sub]"]},superscript:{txtExec:["[sup]","[/sup]"]},left:{txtExec:["[left]","[/left]"]},center:{txtExec:["[center]","[/center]"]},right:{txtExec:["[right]","[/right]"]},justify:{txtExec:["[justify]","[/justify]"]},font:{txtExec:function(a){var b=this;c("font")._dropDown(b,a,function(a){b.insertText("[font="+a+"]","[/font]")})}},size:{txtExec:function(a){var b=this;c("size")._dropDown(b,a,function(a){b.insertText("[size="+a+"]","[/size]")})}},color:{txtExec:function(a){var b=this;c("color")._dropDown(b,a,function(a){b.insertText("[color="+a+"]","[/color]")})}},bulletlist:{txtExec:function(c,d){var e="";a.each(d.split(/\r?\n/),function(){e+=(e?"\n":"")+"[li]"+this+"[/li]"}),b.insertText("[ul]\n"+e+"\n[/ul]")}},orderedlist:{txtExec:function(c,d){var e="";a.each(d.split(/\r?\n/),function(){e+=(e?"\n":"")+"[li]"+this+"[/li]"}),a.sceditor.plugins.bbcode.bbcode.get(""),b.insertText("[ol]\n"+e+"\n[/ol]")}},table:{txtExec:["[table][tr][td]","[/td][/tr][/table]"]},horizontalrule:{txtExec:["[hr]"]},code:{txtExec:["[code]","[/code]"]},image:{txtExec:function(a,b){var c=prompt(this._("Enter the image URL:"),b);c&&this.insertText("[img]"+c+"[/img]")}},email:{txtExec:function(a,b){var c=b&&b.indexOf("@")>-1?null:b,d=prompt(this._("Enter the e-mail address:"),c?"":b),e=prompt(this._("Enter the displayed text:"),c||d)||d;d&&this.insertText("[email="+d+"]"+e+"[/email]")}},link:{txtExec:function(b,c){var d=/^[a-z]+:\/\//i.test(a.trim(c))?null:c,e=prompt(this._("Enter URL:"),d?"http://":a.trim(c)),f=prompt(this._("Enter the displayed text:"),d||e)||e;e&&this.insertText("[url="+e+"]"+f+"[/url]")}},quote:{txtExec:["[quote]","[/quote]"]},youtube:{txtExec:function(a){var b=this;c("youtube")._dropDown(b,a,function(a){b.insertText("[youtube]"+a+"[/youtube]")})}},rtl:{txtExec:["[rtl]","[/rtl]"]},ltr:{txtExec:["[ltr]","[/ltr]"]}};b.commands=a.extend(!0,{},d,b.commands)},b=function(){a.each(j.bbcodes,function(b){j.bbcodes[b].tags&&a.each(j.bbcodes[b].tags,function(a,c){var d=j.bbcodes[b].isInline===!1;k[a]=k[a]||{},k[a][d]=k[a][d]||{},k[a][d][b]=c}),j.bbcodes[b].styles&&a.each(j.bbcodes[b].styles,function(a,c){var d=j.bbcodes[b].isInline===!1;l[d]=l[d]||{},l[d][a]=l[d][a]||{},l[d][a][b]=c})})},d=function(b,c,d){var e,g,h=a.sceditor.dom.getStyle;return d=!!d,l[d]?(a.each(l[d],function(d,i){e=h(b[0],d),e&&h(b.parent()[0],d)!==e&&a.each(i,function(d,h){(!h||a.inArray(e.toString(),h)>-1)&&(g=j.bbcodes[d].format,c=a.isFunction(g)?g.call(j,b,c):f(g,c))})}),c):c},e=function(b,c,d){var e,h,i=b[0],l=i.nodeName.toLowerCase();d=!!d,k[l]&&k[l][d]&&a.each(k[l][d],function(d,g){(!g||(e=!1,a.each(g,function(c,d){return!b.attr(c)||d&&a.inArray(b.attr(c),d)<0?void 0:(e=!0,!1)}),e))&&(h=j.bbcodes[d].format,c=a.isFunction(h)?h.call(j,b,c):f(h,c))});var m=a.sceditor.dom.isInline;if(d&&(!m(i,!0)||"br"===l)){for(var n=i.parentNode,o=n.lastChild,p=i.previousSibling,q=m(n,!0);p&&(a(p).hasClass("sceditor-ignore")||1===p.nodeType&&m(p,!0)&&!p.firstChild);)p=p.previousSibling;for(;a(o).hasClass("sceditor-ignore");)o=o.previousSibling;(q||o!==i||"li"===l||"br"===l&&g)&&(c+="\n"),"br"!==l&&p&&"br"!==p.nodeName.toLowerCase()&&m(p,!0)&&(c="\n"+c)}return c},j.signalToSource=function(b,d){var e,f,g=new a.sceditor.BBCodeParser(j.opts.parserOptions);return d||("string"==typeof b?(e=a("
    ").css("visibility","hidden").appendTo(c.body).html(b),d=e):d=a(b)),d&&d.jquery?(a.sceditor.dom.removeWhiteSpace(d[0]),f=j.elementToBbcode(d),e&&e.remove(),f=g.toBBCode(f,!0),j.opts.bbcodeTrim&&(f=a.trim(f)),f):""},j.elementToBbcode=function(b){return function c(b,f){var h="";return a.sceditor.dom.traverse(b,function(b){var i=a(b),j="",k=b.nodeType,l=b.nodeName.toLowerCase(),n=m[l],o=b.firstChild,p=!0;if("object"==typeof f&&(p=a.inArray(l,f)>-1,i.is("img")&&i.data("sceditor-emoticon")&&(p=!0),p||(n=f)),3===k||1===k)if(1===k){if(i.hasClass("sceditor-ignore"))return;if(i.hasClass("sceditor-nlf")&&(!o||!g&&1===b.childNodes.length&&/br/i.test(o.nodeName)))return;"iframe"!==l&&(j=c(b,n)),p?("code"!==l&&(j=d(i,j),j=e(i,j),j=d(i,j,!0)),h+=e(i,j,!0)):h+=j}else!b.wholeText||b.previousSibling&&3===b.previousSibling.nodeType?b.wholeText||(h+=b.nodeValue):h+=0===i.parents("code").length?b.wholeText.replace(/ +/g," "):b.wholeText},!1,!0),h}(b[0])},j.signalToWysiwyg=function(b,c){var d=new a.sceditor.BBCodeParser(j.opts.parserOptions),e=d.toHTML(j.opts.bbcodeTrim?a.trim(b):b);return c?i(e):e},i=function(b){var d,e,f,h=a("
    ").hide().appendTo(c.body),i=h[0];return f=function(b,d){if(!a.sceditor.dom.hasStyling(b)){if(g||1!==b.childNodes.length||!a(b.firstChild).is("br"))for(;e=b.firstChild;)i.insertBefore(e,b);if(d){var f=i.lastChild;b!==f&&a(f).is("div")&&b.nextSibling===f&&i.insertBefore(c.createElement("br"),b)}i.removeChild(b)}},i.innerHTML=b.replace(/<\/div>\n/g,"
    "),(d=i.firstChild)&&a(d).is("div")&&f(d,!0),(d=i.lastChild)&&a(d).is("div")&&f(d),i=i.innerHTML,h.remove(),i}},a.sceditor.plugins.bbcode.stripQuotes=function(a){return a?a.replace(/\\(.)/g,"$1").replace(/^(["'])(.*?)\1$/,"$2"):a},a.sceditor.plugins.bbcode.formatString=function(){var a,b=arguments;return b[0].replace(/\{(\d+)\}/g,function(c,d){return b[d-0+1]!==a?b[d-0+1]:"{"+d+"}"})},a.sceditor.plugins.bbcode.formatBBCodeString=function(a,b){return a.replace(/\{(!?[^}]+)\}/g,function(a,c){var e,f=!0;return"!"===c[0]&&(f=!1,c=c.substring(1)),"0"===c[0]&&(f=!1),b[c]===e?a:f?d(b[c],!0):b[c]})};var h=a.sceditor.plugins.bbcode.normaliseColour=function(a){var b,c;return c=function(a){return a=parseInt(a,10),isNaN(a)?"00":(a=Math.max(0,Math.min(a,255)).toString(16),a.length<2?"0"+a:a)},a=a||"#000",(b=a.match(/rgb\((\d{1,3}),\s*?(\d{1,3}),\s*?(\d{1,3})\)/i))?"#"+c(b[1])+c(b[2]-0)+c(b[3]-0):(b=a.match(/#([0-f])([0-f])([0-f])\s*?$/i))?"#"+b[1]+b[1]+b[2]+b[2]+b[3]+b[3]:a};a.sceditor.plugins.bbcode.bbcodes={b:{tags:{b:null,strong:null},styles:{"font-weight":["bold","bolder","401","700","800","900"]},format:"[b]{0}[/b]",html:"{0}"},i:{tags:{i:null,em:null},styles:{"font-style":["italic","oblique"]},format:"[i]{0}[/i]",html:"{0}"},u:{tags:{u:null},styles:{"text-decoration":["underline"]},format:"[u]{0}[/u]",html:"{0}"},s:{tags:{s:null,strike:null},styles:{"text-decoration":["line-through"]},format:"[s]{0}[/s]",html:"{0}"},sub:{tags:{sub:null},format:"[sub]{0}[/sub]",html:"{0}"},sup:{tags:{sup:null},format:"[sup]{0}[/sup]",html:"{0}"},font:{tags:{font:{face:null}},styles:{"font-family":null},quoteType:a.sceditor.BBCodeParser.QuoteType.never,format:function(a,b){var c;return"font"===a[0].nodeName.toLowerCase()&&(c=a.attr("face"))||(c=a.css("font-family")),"[font="+this.stripQuotes(c)+"]"+b+"[/font]"},html:'{0}'},size:{tags:{font:{size:null}},styles:{"font-size":null},format:function(a,b){var c=a.attr("size"),d=2;return c||(c=a.css("fontSize")),c.indexOf("px")>-1?(c=c.replace("px","")-0,12>c&&(d=1),c>15&&(d=3),c>17&&(d=4),c>23&&(d=5),c>31&&(d=6),c>47&&(d=7)):d=c,"[size="+d+"]"+b+"[/size]"},html:'{!0}'},color:{tags:{font:{color:null}},styles:{color:null},quoteType:a.sceditor.BBCodeParser.QuoteType.never,format:function(a,b){var c,d=a[0];return"font"===d.nodeName.toLowerCase()&&(c=a.attr("color"))||(c=d.style.color||a.css("color")),"[color="+h(c)+"]"+b+"[/color]"},html:function(a,b,c){return''+c+""}},ul:{tags:{ul:null},breakStart:!0,isInline:!1,skipLastLineBreak:!0,format:"[ul]{0}[/ul]",html:"
      {0}
    "},list:{breakStart:!0,isInline:!1,skipLastLineBreak:!0,html:"
      {0}
    "},ol:{tags:{ol:null},breakStart:!0,isInline:!1,skipLastLineBreak:!0,format:"[ol]{0}[/ol]",html:"
      {0}
    "},li:{tags:{li:null},isInline:!1,closedBy:["/ul","/ol","/list","*","li"],format:"[li]{0}[/li]",html:"
  • {0}
  • "},"*":{isInline:!1,closedBy:["/ul","/ol","/list","*","li"],html:"
  • {0}
  • "},table:{tags:{table:null},isInline:!1,isHtmlInline:!0,skipLastLineBreak:!0,format:"[table]{0}[/table]",html:"
    {0}
    "},tr:{tags:{tr:null},isInline:!1,skipLastLineBreak:!0,format:"[tr]{0}[/tr]",html:"{0}"},th:{tags:{th:null},allowsEmpty:!0,isInline:!1,format:"[th]{0}[/th]",html:"{0}"},td:{tags:{td:null},allowsEmpty:!0,isInline:!1,format:"[td]{0}[/td]",html:"{0}"},emoticon:{allowsEmpty:!0,tags:{img:{src:null,"data-sceditor-emoticon":null}},format:function(a,b){return a.data("sceditor-emoticon")+b},html:"{0}"},hr:{tags:{hr:null},allowsEmpty:!0,isSelfClosing:!0,isInline:!1,format:"[hr]{0}",html:"
    "},img:{allowsEmpty:!0,tags:{img:{src:null}},allowedChildren:["#"],quoteType:a.sceditor.BBCodeParser.QuoteType.never,format:function(a,b){var c,d,e="",f=a[0],g=function(a){return f.style?f.style[a]:null};return a.attr("data-sceditor-emoticon")?b:(c=a.attr("width")||g("width"),d=a.attr("height")||g("height"),(f.complete&&(c||d)||c&&d)&&(e="="+a.width()+"x"+a.height()),"[img"+e+"]"+a.attr("src")+"[/img]")},html:function(a,b,c){var f,g,h,i,j="";return b.width!==f&&(g=b.width),b.height!==f&&(h=b.height),b.defaultattr&&(i=b.defaultattr.split(/x/i),g=i[0],h=2===i.length?i[1]:i[0]),g!==f&&(j+=' width="'+d(g,!0)+'"'),h!==f&&(j+=' height="'+d(h,!0)+'"'),"'}},url:{allowsEmpty:!0,tags:{a:{href:null}},quoteType:a.sceditor.BBCodeParser.QuoteType.never,format:function(a,b){var c=a.attr("href");return"mailto:"===c.substr(0,7)?'[email="'+c.substr(7)+'"]'+b+"[/email]":"[url="+c+"]"+b+"[/url]"},html:function(a,b,c){return b.defaultattr=d(b.defaultattr,!0)||c,''+c+""}},email:{quoteType:a.sceditor.BBCodeParser.QuoteType.never,html:function(a,b,c){return''+c+""}},quote:{tags:{blockquote:null},isInline:!1,quoteType:a.sceditor.BBCodeParser.QuoteType.never,format:function(b,c){var d="",e=a(b),f=e.children("cite").first();return(1===f.length||e.data("author"))&&(d=f.text()||e.data("author"),e.data("author",d),f.remove(),c=this.elementToBbcode(a(b)),d="="+d,e.prepend(f)),"[quote"+d+"]"+c+"[/quote]"},html:function(a,b,c){return b.defaultattr&&(c=""+d(b.defaultattr)+""+c),"
    "+c+"
    "}},code:{tags:{code:null},isInline:!1,allowedChildren:["#","#newline"],format:"[code]{0}[/code]",html:"{0}"},left:{styles:{"text-align":["left","-webkit-left","-moz-left","-khtml-left"]},isInline:!1,format:"[left]{0}[/left]",html:'
    {0}
    '},center:{styles:{"text-align":["center","-webkit-center","-moz-center","-khtml-center"]},isInline:!1,format:"[center]{0}[/center]",html:'
    {0}
    '},right:{styles:{"text-align":["right","-webkit-right","-moz-right","-khtml-right"]},isInline:!1,format:"[right]{0}[/right]",html:'
    {0}
    '},justify:{styles:{"text-align":["justify","-webkit-justify","-moz-justify","-khtml-justify"]},isInline:!1,format:"[justify]{0}[/justify]",html:'
    {0}
    '},youtube:{allowsEmpty:!0,tags:{iframe:{"data-youtube-id":null}},format:function(a,b){return a=a.attr("data-youtube-id"),a?"[youtube]"+a+"[/youtube]":b},html:''},rtl:{styles:{direction:["rtl"]},format:"[rtl]{0}[/rtl]",html:'
    {0}
    '},ltr:{styles:{direction:["ltr"]},format:"[ltr]{0}[/ltr]",html:'
    {0}
    '},ignore:{}},a.sceditor.plugins.bbcode.bbcode={get:function(b){return a.sceditor.plugins.bbcode.bbcodes[b]||null},set:function(b,c){var d=a.sceditor.plugins.bbcode.bbcodes;return b&&c?(c=a.extend(d[b]||{},c),c.remove=function(){delete d[b]},d[b]=c,this):!1},rename:function(b,c){var d=a.sceditor.plugins.bbcode.bbcodes;return b in d?(d[c]=d[b],delete d[b],this):!1},remove:function(b){var c=a.sceditor.plugins.bbcode.bbcodes;return b in c&&delete c[b],this}},a.fn.sceditorBBCodePlugin=function(b){return b=b||{},a.isPlainObject(b)&&(b.plugins=(b.plugins?b.plugins:"")+"bbcode"),this.sceditor(b)}}(jQuery,window,document); \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_plugins/format.js b/Upload/jscripts/sceditor/editor_plugins/format.js new file mode 100644 index 0000000..2c22ad3 --- /dev/null +++ b/Upload/jscripts/sceditor/editor_plugins/format.js @@ -0,0 +1,2 @@ +/* SCEditor v1.4.5 | (C) 2011-2013, Sam Clarke | sceditor.com/license */ +!function(a){"use strict";a.sceditor.plugins.format=function(){var b,c,d=this,e={p:"Paragraph",h1:"Heading 1",h2:"Heading 2",h3:"Heading 3",h4:"Heading 4",h5:"Heading 5",h6:"Heading 6",address:"Address",pre:"Preformatted Text"};d.init=function(){var b=this.opts,d=b.paragraphformat;a.sceditor.plugins.bbcode&&b.plugins&&b.plugins.indexOf("bbcode")>-1||(d&&(d.tags&&(e=d.tags),d.excludeTags&&a.each(d.excludeTags,function(a,b){delete e[b]})),this.commands.format||(this.commands.format={exec:c,txtExec:c,tooltip:"Format Paragraph"}),b.toolbar===a.sceditor.defaultOptions.toolbar&&(b.toolbar=b.toolbar.replace(",color,",",color,format,")))},b=function(a,b){a.sourceMode()?a.insert("<"+b+">",""):a.execCommand("formatblock","<"+b+">")},c=function(c){var d=this,f=a("
    ");a.each(e,function(c,e){a(''+(e.name||e)+"").click(function(){return d.closeDropDown(!0),e.exec?e.exec(d):b(d,c),!1}).appendTo(f)}),d.createDropDown(c,"format",f)}}}(jQuery); \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_plugins/index.html b/Upload/jscripts/sceditor/editor_plugins/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/jscripts/sceditor/editor_plugins/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_plugins/xhtml.js b/Upload/jscripts/sceditor/editor_plugins/xhtml.js new file mode 100644 index 0000000..1aa1c02 --- /dev/null +++ b/Upload/jscripts/sceditor/editor_plugins/xhtml.js @@ -0,0 +1,2 @@ +/* SCEditor v1.4.5 | (C) 2011-2013, Sam Clarke | sceditor.com/license */ +!function(a){"use strict";a.sceditor.XHTMLSerializer=function(){var b,c,d,e,f,g,h,i,j,k,l=this,m={indentStr:" "},n=[],o=0;b=function(a){var b={"&":"&","<":"<",">":">",'"':"""};return a?a.replace(/[&<>"]/g,function(a){return b[a]||a}):""},c=function(a){return a.replace(/[\r\n]/,"").replace(/[^\S|\u00A0]+/g," ")},l.serialize=function(a,b){if(n=[],b)for(a=a.firstChild;a;)d(a),a=a.nextSibling;else d(a);return n.join("")},d=function(a,b){switch(a.nodeType){case 1:var c=a.nodeName.toLowerCase();"!"===c?h(a):f(a,b);break;case 3:i(a,b);break;case 4:g(a);break;case 8:h(a);break;case 9:case 11:e(a);break;case 2:case 5:case 6:case 7:case 10:case 12:}},e=function(a){var b;for(b=a.firstChild;b;)d(b),b=b.nextSibling},f=function(c,e){var f,g,h,i=c.nodeName.toLowerCase(),l=c.attributes.length,m=e||/pre(?:\-wrap)?$/i.test(a(c).css("whiteSpace")),n=!c.firstChild&&a.sceditor.XHTMLSerializer.emptyTags.indexOf("|"+i+"|")>-1;if(!a(c).hasClass("sceditor-ignore")){for(j("<"+i,!e&&k(c));l--;)g=c.attributes[l],(!a.sceditor.ie||g.specified)&&(h=a.sceditor.ie<8&&/style/i.test(g.name)?c.style.cssText:g.value,j(" "+g.name.toLowerCase()+'="'+b(h)+'"',!1));for(j(n?" />":">",!1),"iframe"!==i&&(f=c.firstChild);f;)o++,d(f,m),f=f.nextSibling,o--;n||j("",!m&&k(c)&&c.firstChild&&k(c.firstChild))}},g=function(a){j("")},h=function(a){j("")},i=function(a,d){var e=a.nodeValue;d||(e=c(e)),e&&j(b(e),!d&&k(a))},j=function(a,b){var c=o;if(b!==!1)for(n.length&&n.push("\n");c--;)n.push(m.indentStr);n.push(a)},k=function(b){var c=b.previousSibling;return 1!==b.nodeType&&c?!a.sceditor.dom.isInline(c):c||a.sceditor.dom.isInline(b.parentNode)?!a.sceditor.dom.isInline(b):!0}},a.sceditor.XHTMLSerializer.emptyTags="|area|base|basefont|br|col|frame|hr|img|input|isindex|link|meta|param|command|embed|keygen|source|track|wbr|",a.sceditor.plugins.xhtml=function(){var b,c,d,e,f,g,h,i=this,j={},k={};i.init=function(){a.isEmptyObject(a.sceditor.plugins.xhtml.converters||{})||a.each(a.sceditor.plugins.xhtml.converters,function(b,c){a.each(c.tags,function(a){j[a]||(j[a]=[]),j[a].push(c)})}),b(this)},b=function(b){var c={bold:{txtExec:["",""]},italic:{txtExec:["",""]},underline:{txtExec:['',""]},strike:{txtExec:['',""]},subscript:{txtExec:["",""]},superscript:{txtExec:["",""]},left:{txtExec:['
    ',"
    "]},center:{txtExec:['
    ',"
    "]},right:{txtExec:['
    ',"
    "]},justify:{txtExec:['
    ',"
    "]},font:{txtExec:function(b){var c=this;a.sceditor.command.get("font")._dropDown(c,b,function(a){c.insertText('',"")})}},size:{txtExec:function(b){var c=this;a.sceditor.command.get("size")._dropDown(c,b,function(a){c.insertText('',"")})}},color:{txtExec:function(b){var c=this;a.sceditor.command.get("color")._dropDown(c,b,function(a){c.insertText('',"")})}},bulletlist:{txtExec:["
    • ","
    "]},orderedlist:{txtExec:["
    1. ","
    "]},table:{txtExec:["
    ","
    "]},horizontalrule:{txtExec:["
    "]},code:{txtExec:["",""]},image:{txtExec:function(a,b){var c=prompt(this._("Enter the image URL:"),b);c&&this.insertText('')}},email:{txtExec:function(a,b){var c=b&&b.indexOf("@")>-1?null:b,d=prompt(this._("Enter the e-mail address:"),c?"":b),e=prompt(this._("Enter the displayed text:"),c||d)||d;d&&this.insertText(''+e+"")}},link:{txtExec:function(a,b){var c=b&&b.indexOf("http://")>-1?null:b,d=prompt(this._("Enter URL:"),c?"http://":b),e=prompt(this._("Enter the displayed text:"),c||d)||d;d&&this.insertText(''+e+"")}},quote:{txtExec:["
    ","
    "]},youtube:{txtExec:function(b){var c=this;a.sceditor.command.get("youtube")._dropDown(c,b,function(a){c.insertText('')})}},rtl:{txtExec:['
    ',"
    "]},ltr:{txtExec:['
    ',"
    "]}};b.commands=a.extend(!0,{},c,b.commands)},i.signalToSource=function(b,d){return d=d.jquery?d[0]:d,c(d),f(d),h(d),(new a.sceditor.XHTMLSerializer).serialize(d,!0)},i.signalToWysiwyg=function(a){return a},i.convertTagTo=a.sceditor.dom.convertElement,d=function(b,c,d){j[b]&&a.each(j[b],function(e,f){f.tags[b]?a.each(f.tags[b],function(b,e){d.getAttributeNode&&(b=d.getAttributeNode(b),!b||a.sceditor.ie<8&&!b.specified||e&&a.inArray(b.value,e)<0||f.conv.call(i,d,c))}):f.conv&&f.conv.call(i,d,c)})},c=function(b){a.sceditor.dom.traverse(b,function(b){var c=a(b),e=b.nodeName.toLowerCase();d("*",c,b),d(e,c,b)},!0)},e=function(b,c){var d=b.childNodes,f=b.nodeName.toLowerCase(),g=b.nodeValue,h=d.length;if(c&&"br"===f)return!0;if(a.sceditor.XHTMLSerializer.emptyTags.indexOf("|"+f+"|")>-1)return!1;if(g&&/\S|\u00A0/.test(g))return!1;for(;h--;)if(!e(d[h],!b.previousSibling&&!b.nextSibling))return!1;return!0},f=function(b){a.sceditor.dom.traverse(b,function(b){var c,d=b.nodeName.toLowerCase(),f="iframe"!==d&&e(b),g=b.parentNode,h=b.nodeType,i=a.sceditor.plugins.xhtml.allowedTags,j=a.sceditor.plugins.xhtml.disallowedTags;if(3!==h&&(4===h?d="!cdata":("!"===d||8===h)&&(d="!comment"),f?c=!0:i&&i.length?c=a.inArray(d,i)<0:j&&j.length&&(c=a.inArray(d,j)>-1),c)){for(;!f&&b.lastChild;)g.insertBefore(b.lastChild,b.nextSibling);g.removeChild(b)}},!0)},g=function(b,c){var d={};return b&&a.extend(d,b),c?(a.each(c,function(b,c){a.isArray(c)?d[b]=a.merge(d[b]||[],c):d[b]||(d[b]=null)}),d):d},h=function(b){var c,d,e,f,h,i,j=a.sceditor.plugins.xhtml.allowedAttribs,l=j&&!a.isEmptyObject(j),m=a.sceditor.plugins.xhtml.disallowedAttribs,n=m&&!a.isEmptyObject(m);k={},a.sceditor.dom.traverse(b,function(b){if(b.attributes&&(c=b.nodeName.toLowerCase(),f=b.attributes.length))for(k[c]||(k[c]=l?g(j["*"],j[c]):g(m["*"],m[c]));f--;)d=b.attributes[f],e=d.name,h=k[c][e],i=!1,l?i=null!==h&&(!a.isArray(h)||a.inArray(d.value,h)<0):n&&(i=null===h||a.isArray(h)&&a.inArray(d.value,h)>-1),i&&b.removeAttribute(e)})}},a.sceditor.plugins.xhtml.converters=[{tags:{"*":{width:null}},conv:function(a,b){b.css("width",b.attr("width")).removeAttr("width")}},{tags:{"*":{height:null}},conv:function(a,b){b.css("height",b.attr("height")).removeAttr("height")}},{tags:{li:{value:null}},conv:function(b,c){a.sceditor.ie<8?b.removeAttribute("value"):c.removeAttr("value")}},{tags:{"*":{text:null}},conv:function(a,b){b.css("color",b.attr("text")).removeAttr("text")}},{tags:{"*":{color:null}},conv:function(a,b){b.css("color",b.attr("color")).removeAttr("color")}},{tags:{"*":{face:null}},conv:function(a,b){b.css("fontFamily",b.attr("face")).removeAttr("face")}},{tags:{"*":{align:null}},conv:function(a,b){b.css("textAlign",b.attr("align")).removeAttr("align")}},{tags:{"*":{border:null}},conv:function(a,b){b.css("borderWidth",b.attr("border")).removeAttr("border")}},{tags:{applet:{name:null},img:{name:null},layer:{name:null},map:{name:null},object:{name:null},param:{name:null}},conv:function(a,b){b.attr("id")||b.attr("id",b.attr("name")),b.removeAttr("name")}},{tags:{"*":{vspace:null}},conv:function(a,b){b.css("marginTop",b.attr("vspace")-0).css("marginBottom",b.attr("vspace")-0).removeAttr("vspace")}},{tags:{"*":{hspace:null}},conv:function(a,b){b.css("marginLeft",b.attr("hspace")-0).css("marginRight",b.attr("hspace")-0).removeAttr("hspace")}},{tags:{hr:{noshade:null}},conv:function(a,b){b.css("borderStyle","solid").removeAttr("noshade")}},{tags:{"*":{nowrap:null}},conv:function(a,b){b.css("white-space","nowrap").removeAttr("nowrap")}},{tags:{big:null},conv:function(b){a(this.convertTagTo(b,"span")).css("fontSize","larger")}},{tags:{small:null},conv:function(b){a(this.convertTagTo(b,"span")).css("fontSize","smaller")}},{tags:{b:null},conv:function(b){a(this.convertTagTo(b,"strong"))}},{tags:{u:null},conv:function(b){a(this.convertTagTo(b,"span")).css("textDecoration","underline")}},{tags:{i:null},conv:function(b){a(this.convertTagTo(b,"em"))}},{tags:{s:null,strike:null},conv:function(b){a(this.convertTagTo(b,"span")).css("textDecoration","line-through")}},{tags:{dir:null},conv:function(a){this.convertTagTo(a,"ul")}},{tags:{center:null},conv:function(b){a(this.convertTagTo(b,"div")).css("textAlign","center")}},{tags:{font:{size:null}},conv:function(b,c){var d=c.css("fontSize"),e=d;a.sceditor.ie<9&&(e=10,d>1&&(e=13),d>2&&(e=16),d>3&&(e=18),d>4&&(e=24),d>5&&(e=32),d>6&&(e=48)),c.css("fontSize",e).removeAttr("size")}},{tags:{font:null},conv:function(a){this.convertTagTo(a,"span")}},{tags:{"*":{type:["_moz"]}},conv:function(a,b){b.removeAttr("type")}},{tags:{"*":{_moz_dirty:null}},conv:function(a,b){b.removeAttr("_moz_dirty")}},{tags:{"*":{_moz_editor_bogus_node:null}},conv:function(a,b){b.remove()}}],a.sceditor.plugins.xhtml.allowedAttribs={},a.sceditor.plugins.xhtml.disallowedAttribs={},a.sceditor.plugins.xhtml.allowedTags=[],a.sceditor.plugins.xhtml.disallowedTags=[]}(jQuery); \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_themes/buttons.css b/Upload/jscripts/sceditor/editor_themes/buttons.css new file mode 100644 index 0000000..2667f0b --- /dev/null +++ b/Upload/jscripts/sceditor/editor_themes/buttons.css @@ -0,0 +1,752 @@ +/** + * Buttons theme + * + * Copyright (C) 2013, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + * Icons by Mark James (http://www.famfamfam.com/lab/icons/silk/) + * Licensed under the Creative Commons CC-BY license (http://creativecommons.org/licenses/by/3.0/) + */ +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +@font-face { + font-family: 'Monocons'; + src: url('monocons/monocons.eot'); + src: url('monocons/monocons.eot?#iefix') format('embedded-opentype'), url('monocons/monocons.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} +.sceditor-button div:before, +div.sceditor-grip { + font-family: 'Monocons'; + font-size: 16px; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.sceditor-button-youtube div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e000'); +} +.sceditor-button-unlink div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e001'); +} +.sceditor-button-underline div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e002'); +} +.sceditor-button-time div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e003'); +} +.sceditor-button-table div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e004'); +} +.sceditor-button-superscript div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e005'); +} +.sceditor-button-subscript div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e006'); +} +.sceditor-button-strike div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e007'); +} +.sceditor-button-source div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e008'); +} +.sceditor-button-size div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e009'); +} +.sceditor-button-rtl div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e00a'); +} +.sceditor-button-right div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e00b'); +} +.sceditor-button-removeformat div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e00c'); +} +.sceditor-button-quote div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e00d'); +} +.sceditor-button-print div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e00e'); +} +.sceditor-button-pastetext div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e00f'); +} +.sceditor-button-paste div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e010'); +} +.sceditor-button-orderedlist div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e011'); +} +.sceditor-button-maximize div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e012'); +} +.sceditor-button-ltr div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e013'); +} +.sceditor-button-link div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e014'); +} +.sceditor-button-left div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e015'); +} +.sceditor-button-justify div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e016'); +} +.sceditor-button-italic div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e017'); +} +.sceditor-button-image div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e018'); +} +.sceditor-button-horizontalrule div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e019'); +} +.sceditor-button-format div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e01c'); +} +.sceditor-button-font div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e01d'); +} +.sceditor-button-emoticon div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e01e'); +} +.sceditor-button-email div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e01f'); +} +.sceditor-button-bold div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e020'); +} +.sceditor-button-date div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e021'); +} +.sceditor-button-cut div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e022'); +} +.sceditor-button-copy div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e023'); +} +.sceditor-button-color div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e024'); +} +.sceditor-button-code div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e025'); +} +.sceditor-button-center div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e026'); +} +.sceditor-button-bulletlist div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e027'); +} +div.sceditor-grip { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e01b'); +} +.rtl div.sceditor-grip { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e01a'); +} +.sceditor-button-youtube div:before { + content: "\e000"; +} +.sceditor-button-unlink div:before { + content: "\e001"; +} +.sceditor-button-underline div:before { + content: "\e002"; +} +.sceditor-button-time div:before { + content: "\e003"; +} +.sceditor-button-table div:before { + content: "\e004"; +} +.sceditor-button-superscript div:before { + content: "\e005"; +} +.sceditor-button-subscript div:before { + content: "\e006"; +} +.sceditor-button-strike div:before { + content: "\e007"; +} +.sceditor-button-source div:before { + content: "\e008"; +} +.sceditor-button-size div:before { + content: "\e009"; +} +.sceditor-button-rtl div:before { + content: "\e00a"; +} +.sceditor-button-right div:before { + content: "\e00b"; +} +.sceditor-button-removeformat div:before { + content: "\e00c"; +} +.sceditor-button-quote div:before { + content: "\e00d"; +} +.sceditor-button-print div:before { + content: "\e00e"; +} +.sceditor-button-pastetext div:before { + content: "\e00f"; +} +.sceditor-button-paste div:before { + content: "\e010"; +} +.sceditor-button-orderedlist div:before { + content: "\e011"; +} +.sceditor-button-maximize div:before { + content: "\e012"; +} +.sceditor-button-ltr div:before { + content: "\e013"; +} +.sceditor-button-link div:before { + content: "\e014"; +} +.sceditor-button-left div:before { + content: "\e015"; +} +.sceditor-button-justify div:before { + content: "\e016"; +} +.sceditor-button-italic div:before { + content: "\e017"; +} +.sceditor-button-image div:before { + content: "\e018"; +} +.sceditor-button-horizontalrule div:before { + content: "\e019"; +} +.sceditor-button-format div:before { + content: "\e01c"; +} +.sceditor-button-font div:before { + content: "\e01d"; +} +.sceditor-button-emoticon div:before { + content: "\e01e"; +} +.sceditor-button-email div:before { + content: "\e01f"; +} +.sceditor-button-bold div:before { + content: "\e020"; +} +.sceditor-button-date div:before { + content: "\e021"; +} +.sceditor-button-cut div:before { + content: "\e022"; +} +.sceditor-button-copy div:before { + content: "\e023"; +} +.sceditor-button-color div:before { + content: "\e024"; +} +.sceditor-button-code div:before { + content: "\e025"; +} +.sceditor-button-center div:before { + content: "\e026"; +} +.sceditor-button-bulletlist div:before { + content: "\e027"; +} +div.sceditor-grip:before { + content: "\e01b"; +} +.rtl div.sceditor-grip:before { + content: "\e01a"; +} +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +/*--------------------------------------------------- + LESS Elements 0.7 + --------------------------------------------------- + A set of useful LESS mixins + More info at: http://lesselements.com + ---------------------------------------------------*/ +.sceditor-container { + position: relative; + background: #fff; + border: 1px solid #d9d9d9; + font-size: 13px; + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + color: #222; + line-height: 1; + font-weight: bold; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 100% !important; +} +.sceditor-container, +.sceditor-container div, +div.sceditor-dropdown, +div.sceditor-dropdown div { + padding: 0; + margin: 0; + z-index: 3; +} +.sceditor-container iframe, +.sceditor-container textarea { + line-height: 1; + border: 0; + outline: none; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 13px; + color: #111; + padding: 0; + margin: 5px; + resize: none; + background: #fff; + display: block; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 99% !important; +} +div.sceditor-resize-cover { + position: absolute; + top: 0; + left: 0; + background: #000; + width: 100%; + height: 100%; + z-index: 10; + opacity: 0.3; +} +.ie6 div.sceditor-resize-cover, +.ie7 div.sceditor-resize-cover, +.ie8 div.sceditor-resize-cover { + background: #efefef; +} +.sceditor-container.ie6 { + overflow: hidden; +} +div.sceditor-grip { + overflow: hidden; + width: 10px; + height: 10px; + cursor: pointer; + position: absolute; + bottom: 0; + right: 0; + z-index: 3; +} +.sceditor-maximize { + position: fixed; + top: 0; + left: 0; + height: 100% !important; + width: 100% !important; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + z-index: 2000; +} +html.sceditor-maximize, +body.sceditor-maximize { + height: 100%; + width: 100%; + padding: 0; + margin: 0; + overflow: hidden; +} +.ie6.sceditor-maximize { + position: absolute; +} +.sceditor-maximize div.sceditor-grip { + display: none; +} +.sceditor-maximize div.sceditor-toolbar { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +/** + * Dropdown styleing + */ +div.sceditor-dropdown { + position: absolute; + border: 1px solid #ccc; + background: #fff; + color: #333; + z-index: 4000; + padding: 10px; + line-height: 1; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); +} +div.sceditor-dropdown a, +div.sceditor-dropdown a:link { + color: #333; +} +div.sceditor-dropdown form { + margin: 0; +} +div.sceditor-dropdown label { + display: block; + font-weight: bold; + color: #3c3c3c; + padding: 4px 0; +} +div.sceditor-dropdown input, +div.sceditor-dropdown textarea { + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + outline: 0; + padding: 4px; + border: 1px solid #ccc; + border-top-color: #888; + margin: 0 0 .75em; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-dropdown textarea { + padding: 6px; +} +div.sceditor-dropdown input:focus, +div.sceditor-dropdown textarea:focus { + border-color: #aaa; + border-top-color: #666; + -webkit-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); +} +div.sceditor-dropdown .button { + font-weight: bold; + color: #444; + padding: 6px 12px; + background: #ececec; + border: solid 1px #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + cursor: pointer; + margin: .3em 0 0; +} +div.sceditor-dropdown .button:hover { + background: #f3f3f3; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); +} +div.sceditor-font-picker, +div.sceditor-fontsize-picker, +div.sceditor-format { + padding: 6px 0; +} +div.sceditor-emoticons, +div.sceditor-more-emoticons, +div.sceditor-color-picker { + padding: 0; +} +.sceditor-pastetext textarea { + border: 1px solid #bbb; + width: 20em; +} +.sceditor-emoticons img, +.sceditor-more-emoticons img { + padding: 0; + cursor: pointer; + margin: 2px; +} +.sceditor-more { + border-top: 1px solid #bbb; + display: block; + text-align: center; + cursor: pointer; + font-weight: bold; + padding: 6px 0; +} +.sceditor-dropdown a:hover { + background: #eee; +} +.sceditor-fontsize-option, +.sceditor-font-option, +.sceditor-format a { + display: block; + padding: 7px 10px; + cursor: pointer; + text-decoration: none; + color: #222; +} +.sceditor-fontsize-option { + padding: 7px 13px; +} +.sceditor-color-column { + float: left; +} +.sceditor-color-option { + display: block; + border: 1px solid #fff; + height: 10px; + width: 10px; + overflow: hidden; +} +.sceditor-color-option:hover { + border: 1px solid #333; +} +/** + * Toolbar styleing + */ +div.sceditor-toolbar { + overflow: hidden; + padding: 3px 5px 2px; + background: #f7f7f7; + border-bottom: 1px solid #c0c0c0; + line-height: 0; + text-align: left; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-group { + display: inline-block; + background: #ddd; + margin: 1px 5px 1px 0; + padding: 1px; + border-bottom: 1px solid #aaa; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.ie6 div.sceditor-group, +.ie7 div.sceditor-group { + display: inline; + zoom: 1; +} +.sceditor-button { + float: left; + cursor: pointer; + padding: 3px 5px; + width: 16px; + height: 20px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + /* Needed for Safari 5? */ + + text-indent: -9999px; +} +.ie .sceditor-button { + text-indent: 0; +} +.ie6 .sceditor-button, +.ie7 .sceditor-button { + float: none !important; + display: inline; + zoom: 1; +} +.ie6 .sceditor-button { + padding: 0; +} +.ie6 .sceditor-button div { + margin: 5px; +} +.ie7 .sceditor-button div { + margin: 5px 0; +} +.sceditor-button:hover, +.sceditor-button:active, +.sceditor-button.active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); +} +.sceditor-button:active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); +} +.sceditor-button.disabled:hover { + background: inherit; + cursor: default; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.sceditor-button, +.sceditor-button div { + display: block; +} +.sceditor-button div { + margin: 2px 0; + padding: 0; + overflow: hidden; + line-height: 0; + font-size: 0; + color: transparent; +} +.sceditor-button.disabled div { + filter: alpha(opacity=30); + opacity: 0.3; +} +.text .sceditor-button, +.text .sceditor-button div, +.sceditor-button.text, +.sceditor-button.text div, +.text-icon .sceditor-button, +.text-icon .sceditor-button div, +.sceditor-button.text-icon, +.sceditor-button.text-icon div { + width: auto; + overflow: visible; + line-height: 16px; + font-size: 1em; + color: inherit; + text-indent: 0; +} +.text .sceditor-button div, +.sceditor-button.text div { + padding: 0 2px; + background: none; +} +.text-icon .sceditor-button div, +.sceditor-button.text-icon div { + padding: 0 2px 0 20px; +} +.rtl div.sceditor-toolbar { + text-align: right; +} +.rtl .sceditor-button { + float: right; +} +.rtl div.sceditor-grip { + right: auto; + left: 0; +} +.ie7 .sceditor-button div, +.ie6 .sceditor-button div { + font-family: 'Monocons'; + overflow: visible; + font-size: 16px; + line-height: 1; + text-indent: 0; +} +div.sceditor-grip { + height: 16px; + width: 16px; +} +.sceditor-button div:before, +div.sceditor-grip:before { + text-indent: 0; + line-height: 17px; + width: 16px; + height: 16px; + display: block; + color: #333; + text-shadow: 0 1px #fff; +} +.sceditor-container { + border-color: #111; +} +div.sceditor-toolbar { + color: #fff; + background: #2b2b2b; + border-color: #111; +} +div.sceditor-group { + margin: 2px 5px 2px 0; + border: 0; + background: #777777; + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzc3Nzc3NyIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjQwJSIgc3RvcC1jb2xvcj0iIzU1NTU1NSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiM0NDQ0NDQiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); + background: -moz-linear-gradient(top, #777777 0%, #555555 40%, #444444 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #777777), color-stop(40%, #555555), color-stop(100%, #444444)); + background: -webkit-linear-gradient(top, #777777 0%, #555555 40%, #444444 100%); + background: -o-linear-gradient(top, #777777 0%, #555555 40%, #444444 100%); + background: -ms-linear-gradient(top, #777777 0%, #555555 40%, #444444 100%); + background: linear-gradient(to bottom, #777777 0%, #555555 40%, #444444 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#777777', endColorstr='#444444', GradientType=0); +} +.sceditor-button div:before, +div.sceditor-grip:before { + color: #ddd; + text-shadow: 0 1px #000; +} +.sceditor-container.sourceMode { + background: #1f1f1f; +} +.sceditor-container textarea { + color: #fff; + background: #1f1f1f; +} + +/* Additional buttons (for MyBB) */ +.sceditor-button-video div { + + background-image: url(video.png); + +} +.sceditor-button-php div { + + background-image: url(php.png); + +} \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_themes/default.css b/Upload/jscripts/sceditor/editor_themes/default.css new file mode 100644 index 0000000..143c6ac --- /dev/null +++ b/Upload/jscripts/sceditor/editor_themes/default.css @@ -0,0 +1,559 @@ +/*! SCEditor | (C) 2011-2013, Sam Clarke | sceditor.com/license */ +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +div.sceditor-grip, +.sceditor-button div { + background-image: url('famfamfam.png'); + background-repeat: no-repeat; + width: 16px; + height: 16px; +} +.sceditor-button-youtube div { + background-position: 0px 0px; +} +.sceditor-button-link div { + background-position: 0px -16px; +} +.sceditor-button-unlink div { + background-position: 0px -32px; +} +.sceditor-button-underline div { + background-position: 0px -48px; +} +.sceditor-button-time div { + background-position: 0px -64px; +} +.sceditor-button-table div { + background-position: 0px -80px; +} +.sceditor-button-superscript div { + background-position: 0px -96px; +} +.sceditor-button-subscript div { + background-position: 0px -112px; +} +.sceditor-button-strike div { + background-position: 0px -128px; +} +.sceditor-button-source div { + background-position: 0px -144px; +} +.sceditor-button-size div { + background-position: 0px -160px; +} +.sceditor-button-rtl div { + background-position: 0px -176px; +} +.sceditor-button-right div { + background-position: 0px -192px; +} +.sceditor-button-removeformat div { + background-position: 0px -208px; +} +.sceditor-button-quote div { + background-position: 0px -224px; +} +.sceditor-button-print div { + background-position: 0px -240px; +} +.sceditor-button-pastetext div { + background-position: 0px -256px; +} +.sceditor-button-paste div { + background-position: 0px -272px; +} +.sceditor-button-orderedlist div { + background-position: 0px -288px; +} +.sceditor-button-maximize div { + background-position: 0px -304px; +} +.sceditor-button-ltr div { + background-position: 0px -320px; +} +.sceditor-button-left div { + background-position: 0px -336px; +} +.sceditor-button-justify div { + background-position: 0px -352px; +} +.sceditor-button-italic div { + background-position: 0px -368px; +} +.sceditor-button-image div { + background-position: 0px -384px; +} +.sceditor-button-horizontalrule div { + background-position: 0px -400px; +} +.sceditor-button-format div { + background-position: 0px -416px; +} +.sceditor-button-font div { + background-position: 0px -432px; +} +.sceditor-button-emoticon div { + background-position: 0px -448px; +} +.sceditor-button-email div { + background-position: 0px -464px; +} +.sceditor-button-date div { + background-position: 0px -480px; +} +.sceditor-button-cut div { + background-position: 0px -496px; +} +.sceditor-button-copy div { + background-position: 0px -512px; +} +.sceditor-button-color div { + background-position: 0px -528px; +} +.sceditor-button-code div { + background-position: 0px -544px; +} +.sceditor-button-center div { + background-position: 0px -560px; +} +.sceditor-button-bulletlist div { + background-position: 0px -576px; +} +.sceditor-button-bold div { + background-position: 0px -592px; +} +div.sceditor-grip { + background-position: 0px -608px; + width: 10px; + height: 10px; +} +.rtl div.sceditor-grip { + background-position: 0px -618px; + width: 10px; + height: 10px; +} +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +/*--------------------------------------------------- + LESS Elements 0.7 + --------------------------------------------------- + A set of useful LESS mixins + More info at: http://lesselements.com + ---------------------------------------------------*/ +.sceditor-container { + position: relative; + background: #fff; + border: 1px solid #d9d9d9; + font-size: 13px; + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + color: #222; + line-height: 1; + font-weight: bold; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 100% !important; +} +.sceditor-container, +.sceditor-container div, +div.sceditor-dropdown, +div.sceditor-dropdown div { + padding: 0; + margin: 0; + z-index: 3; +} +.sceditor-container iframe, +.sceditor-container textarea { + line-height: 1; + border: 0; + outline: none; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 13px; + color: #111; + padding: 0; + margin: 5px; + resize: none; + background: #fff; + display: block; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 99% !important; +} +div.sceditor-resize-cover { + position: absolute; + top: 0; + left: 0; + background: #000; + width: 100%; + height: 100%; + z-index: 10; + opacity: 0.3; +} +.ie6 div.sceditor-resize-cover, +.ie7 div.sceditor-resize-cover, +.ie8 div.sceditor-resize-cover { + background: #efefef; +} +.sceditor-container.ie6 { + overflow: hidden; +} +div.sceditor-grip { + overflow: hidden; + width: 10px; + height: 10px; + cursor: pointer; + position: absolute; + bottom: 0; + right: 0; + z-index: 3; +} +.sceditor-maximize { + position: fixed; + top: 0; + left: 0; + height: 100% !important; + width: 100% !important; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + z-index: 2000; +} +html.sceditor-maximize, +body.sceditor-maximize { + height: 100%; + width: 100%; + padding: 0; + margin: 0; + overflow: hidden; +} +.ie6.sceditor-maximize { + position: absolute; +} +.sceditor-maximize div.sceditor-grip { + display: none; +} +.sceditor-maximize div.sceditor-toolbar { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +/** + * Dropdown styleing + */ +div.sceditor-dropdown { + position: absolute; + border: 1px solid #ccc; + background: #fff; + color: #333; + z-index: 4000; + padding: 10px; + line-height: 1; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); +} +div.sceditor-dropdown a, +div.sceditor-dropdown a:link { + color: #333; +} +div.sceditor-dropdown form { + margin: 0; +} +div.sceditor-dropdown label { + display: block; + font-weight: bold; + color: #3c3c3c; + padding: 4px 0; +} +div.sceditor-dropdown input, +div.sceditor-dropdown textarea { + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + outline: 0; + padding: 4px; + border: 1px solid #ccc; + border-top-color: #888; + margin: 0 0 .75em; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-dropdown textarea { + padding: 6px; +} +div.sceditor-dropdown input:focus, +div.sceditor-dropdown textarea:focus { + border-color: #aaa; + border-top-color: #666; + -webkit-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); +} +div.sceditor-dropdown .button { + font-weight: bold; + color: #444; + padding: 6px 12px; + background: #ececec; + border: solid 1px #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + cursor: pointer; + margin: .3em 0 0; +} +div.sceditor-dropdown .button:hover { + background: #f3f3f3; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); +} +div.sceditor-font-picker, +div.sceditor-fontsize-picker, +div.sceditor-format { + padding: 6px 0; +} +div.sceditor-emoticons, +div.sceditor-more-emoticons, +div.sceditor-color-picker { + padding: 0; +} +.sceditor-pastetext textarea { + border: 1px solid #bbb; + width: 20em; +} +.sceditor-emoticons img, +.sceditor-more-emoticons img { + padding: 0; + cursor: pointer; + margin: 2px; +} +.sceditor-more { + border-top: 1px solid #bbb; + display: block; + text-align: center; + cursor: pointer; + font-weight: bold; + padding: 6px 0; +} +.sceditor-dropdown a:hover { + background: #eee; +} +.sceditor-fontsize-option, +.sceditor-font-option, +.sceditor-format a { + display: block; + padding: 7px 10px; + cursor: pointer; + text-decoration: none; + color: #222; +} +.sceditor-fontsize-option { + padding: 7px 13px; +} +.sceditor-color-column { + float: left; +} +.sceditor-color-option { + display: block; + border: 1px solid #fff; + height: 10px; + width: 10px; + overflow: hidden; +} +.sceditor-color-option:hover { + border: 1px solid #333; +} +/** + * Toolbar styleing + */ +div.sceditor-toolbar { + overflow: hidden; + padding: 3px 5px 2px; + background: #f7f7f7; + border-bottom: 1px solid #c0c0c0; + line-height: 0; + text-align: left; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-group { + display: inline-block; + background: #ddd; + margin: 1px 5px 1px 0; + padding: 1px; + border-bottom: 1px solid #aaa; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.ie6 div.sceditor-group, +.ie7 div.sceditor-group { + display: inline; + zoom: 1; +} +.sceditor-button { + float: left; + cursor: pointer; + padding: 3px 5px; + width: 16px; + height: 20px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + /* Needed for Safari 5? */ + + text-indent: -9999px; +} +.ie .sceditor-button { + text-indent: 0; +} +.ie6 .sceditor-button, +.ie7 .sceditor-button { + float: none !important; + display: inline; + zoom: 1; +} +.ie6 .sceditor-button { + padding: 0; +} +.ie6 .sceditor-button div { + margin: 5px; +} +.ie7 .sceditor-button div { + margin: 5px 0; +} +.sceditor-button:hover, +.sceditor-button:active, +.sceditor-button.active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); +} +.sceditor-button:active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); +} +.sceditor-button.disabled:hover { + background: inherit; + cursor: default; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.sceditor-button, +.sceditor-button div { + display: block; +} +.sceditor-button div { + margin: 2px 0; + padding: 0; + overflow: hidden; + line-height: 0; + font-size: 0; + color: transparent; +} +.sceditor-button.disabled div { + filter: alpha(opacity=30); + opacity: 0.3; +} +.text .sceditor-button, +.text .sceditor-button div, +.sceditor-button.text, +.sceditor-button.text div, +.text-icon .sceditor-button, +.text-icon .sceditor-button div, +.sceditor-button.text-icon, +.sceditor-button.text-icon div { + width: auto; + overflow: visible; + line-height: 16px; + font-size: 1em; + color: inherit; + text-indent: 0; +} +.text .sceditor-button div, +.sceditor-button.text div { + padding: 0 2px; + background: none; +} +.text-icon .sceditor-button div, +.sceditor-button.text-icon div { + padding: 0 2px 0 20px; +} +.rtl div.sceditor-toolbar { + text-align: right; +} +.rtl .sceditor-button { + float: right; +} +.rtl div.sceditor-grip { + right: auto; + left: 0; +} + +/* Additional buttons (for MyBB) */ +.sceditor-button-video div { + + background-image: url(video.png); + +} +.sceditor-button-php div { + + background-image: url(php.png); + +} \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/alien.png b/Upload/jscripts/sceditor/editor_themes/emoticons/alien.png new file mode 100644 index 0000000000000000000000000000000000000000..5ec8e23e3f91bfd5a40b81347d1eb99b7207090f GIT binary patch literal 962 zcmV;z13mnSP)>xk zAa0SCmTnCR31I-q2@4A|u(Gl;04-n;5D;LHm6c_XmzQUF{rYv#*RNlNp|1V}GXNlf zkPQ?8;$9OIlLS9MKL$QNKCmIo%*-g5iHV7UlarG{NlA&}`}gn0Z{EBS2kJWn#NR-M z00a;d)G#g}&QMWNiE?ssVqjxqgKK7FWCUXn8zcsjHG=^l zfM5oi2nq@|dwY9>T?I1;BL<-cgVcZwW@l$-u(q~l;N|6Q2AKg;0}wzk1EbB%%)mB- zG-zvUGiYgPVNVu7LqU;cYHA7&TaX?#H8rpqAOawOKn5}caR4YxK#Gwg37etFVj$On z^ng+U5cq-20|+3Hfh<7hi-E!ilr%u#+O=y~4M1j}J9iFDgY-bdR|4cXfB*s+_~+NJ zU$;Mg{K)X<&mWvFLkC7iMqv8)@81mHzI|f=rpwzv?q7fa0vY%hh?iWxe3{|r&z}ru z&z>bZn{D5|9jxc!Lr|t+SPpV9KmfraWi`l~FJHa{D}Z?i8KCF+-Me>#(jmjUckdV; zJa_;SS_vWm0tjZ{ZJ@V9ckSB6@ZrM;h95tEpco1=3>Lm1uxHO624F5>`1I)$!eUobc112A z00IcTw0Q@_ZNNbO3k>igS65dCQ0_qnixw?nIC=6U!`ruS`+(d|AbyK14-i1O%0odQ z&J+?7YISgM0B18$@&LIE literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/angel.png b/Upload/jscripts/sceditor/editor_themes/emoticons/angel.png new file mode 100644 index 0000000000000000000000000000000000000000..718ecb45ddd40dca6ee144a561b00b62ddc5de52 GIT binary patch literal 1254 zcmV&+k8Hl?CMOlx4I4kylX8;Hw zunU2P*#W6NJNLS;(xw!{b7pooj3v7}%M7-F*+b0QGwU4Lt}_01!YhFWc|j z?abotya%SS9;l!RS2zI;sB{lG+y-I;9l;6I2l5@*K!5;(8F#ms=%2Z&vPSOco=1`zKCT6TZMA{zztmuUcLX@_2KPrkN^J|@?hQt zg&{xy!3_i%4#c1sUgB=gryUwB!ob17#K6c54LqQM|Ni`E`1|cI!?*Xp8P;xl&#>?O z_p3mu7$Cj~QUWp%Ab^mQjVcQZ(JK%r6~<^st91Q5(XeHn4qL^o#v29L<640}$$hieA0UHl(m zi1}u`VqoEBVsJF(Vi4zJN&yP%f#d)J2@G_9SXT1!D*v=&q48Rlt#EcA@QsA`j z3?cvm2k=tX#WjT9sa{R625(jYxR%<%6YTn#_~!MuF`&8y!G|9%4%`~@la z4|gquMlu*=DKI_$`}G%yf$8$cKZbW7!3I7A5dZ-MGjR8%tKY$i_TSI{P+O4$+D(_e;PK>GBfKd_>V0U&^223~mf?(c%Vhd(p?`tS>=@HfM@*&+p;8<8UdGq_&c&DQ1Jy2K#bI`Mgam00OExM;j8Hz Q0ssI207*qoM6N<$g3B%|tN;K2 literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/angry.png b/Upload/jscripts/sceditor/editor_themes/emoticons/angry.png new file mode 100644 index 0000000000000000000000000000000000000000..98b6c08394c2f27864417a673c8aefc15e4babb7 GIT binary patch literal 1037 zcmV+o1oHcdP)eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ihK|__3K~9Q|;s4+N3=bcEx43@uhsB|DUu$2z|JwyrHyMbZAZrE) zAV!dvp)OP+vam4j%uf~l|P2($+n%pi-I{{CZN0$RWg z#1X!N4C*qh+OxNQ+WzMsgFR6HEs!Aq0mK9~j2nn6!h8h93{AKhm^qk%8kr!5flOok z&%g*&2@+#wXJ%mGVrF3FV`0$O;$rYI;gkR>Dg|OLkU;2Jk1Q5(XB@rQJsAdFk0U8eXGLUcydV-q3pqBA- zfx?BiO))AOawOU@qK! z>FRfIqW$;tKh)O$h#-I(3K9b+@Spz}{(k?<@aNkfFn#mcACRiOAOawOU@AcdS49&0B_Th>EGRp<0kI}j{5lZtf<^$=0u~^E7^z(a00bBSZo-gaZzB2&00000NkvXX Hu0mjfOv1ZR literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/blink.png b/Upload/jscripts/sceditor/editor_themes/emoticons/blink.png new file mode 100644 index 0000000000000000000000000000000000000000..ea4841dd48a091d8de92f7cd7b375fbae357d5cd GIT binary patch literal 1066 zcmV+_1l9YAP)eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*epV$Otlz0c0`LUq%Kd zpcpsMk_caZ26Y)$?b%yDZwK0A57d7PWC%b2F+mOE2I7h^AAT`I6K)1(4n_vI;O7jk z0nZp*{GS3%{?EV&R0%SSnVpG&g^QVim5-T0UyFmm$Am)ysJ9e|xj+U11Q5)H`ZD4y ziEhq(3{0$y46Z@X81|fg4|lqYsUX9i4N?p)fzRM#+vbZfuy8XmI2v;@9KZ1^<>jY; zbAiGq00Ic+LO)w`ZUz>1pvyv@qZkGPAihfg#1a_xN_+#foQZ*zgNeah8SE}!5CITC zFaurnG&vyQg$00J2r?8%qr@l^1Zzrx4Ri((009IuP)S6H2^8{J4TKqn?sACw{|x+G zV23Dz2!H@$fhV6oK&gNK74ee?SWMf(U>B zf`#EmV0L2o`SCZypD#c~KY_OY2IY=_5byl|4>1TR_V>qMph15bet-VM@cYwWhF_om zGMs+&7i7j}5CITCFas|VBun7U}6JiJtm01 zH}&&^z54UbFQDuGf(^cM?>EEtTYq1H^g_*G00~f{g>hPi@yvf9{po@^X)&@;tL>vkc%&D1uQ5#xdE{zRQx&+?}A1E k)&dqFfEcM=1povX0F*|GwPn`XY5)KL07*qoM6N<$g0#oX)c^nh literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/blush.png b/Upload/jscripts/sceditor/editor_themes/emoticons/blush.png new file mode 100644 index 0000000000000000000000000000000000000000..8242f09b30792bc30a9cac7db82916c97a2a6595 GIT binary patch literal 1120 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 literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/cool.png b/Upload/jscripts/sceditor/editor_themes/emoticons/cool.png new file mode 100644 index 0000000000000000000000000000000000000000..6d1612a47a1c2c60d744e4a5c201e2118c2d043e GIT binary patch literal 1062 zcmV+>1ljwEP)eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*epV$Otlz0c0`LUq%Kd zpcpsMk_caZ26Y)$?b%yDZwK0A57d7PWC%b2F+mOE2I7h^AAT`I6K)1(4v$GH>fb+x-D|{w5x|HDD5RXU2Pg+lLjV3V{Qdrq;n({= z4FCTC<^Lhn00a=sh4(hTot5GW`1d zm*MoIzu-6m5dZ-M3&RV~-u+#$_wd&QS6eQyW@Zj11|}9pXn6i-aF2fn52tl4+`#br z&G7rfABMx%e=)rH@_#-w`!N6n5X``@K-{tZ=yz`s9!6164q)K|8py^7kDyKcykM{X z`TCdP=bK+(*Il{yn_>H{zo5k10X2gGAb^nb@-1MVbeq2Y+Y*O|zqS1=I2ky&f!U7* z8jOEI-u({_v+qE|wq5+qaQNY0SmAIRW(Yt4AsYw^`U^npap2nT+^diNlvygXFsMo} zGe`?Efen1}`Y*%n7k?Q}Jo?A*=G%X)#TP&TAs1iR3RqBfasy&bsQ7gt-UW>StOYDU g05MX#3IGT&07(d$9!?lHNdN!<07*qoM6N<$g59>${{R30 literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/credits.txt b/Upload/jscripts/sceditor/editor_themes/emoticons/credits.txt new file mode 100644 index 0000000..96b3e7a --- /dev/null +++ b/Upload/jscripts/sceditor/editor_themes/emoticons/credits.txt @@ -0,0 +1,9 @@ +Presenting, Nomicons: The Full Monty :o + +Credits: +Oscar Gruno, aka Nominell v. 2.0 -> oscargruno@mac.com +Andy Fedosjeenko, aka Nightwolf -> bobo@animevanguard.com + +Copyright (C) 2001-Infinity, Oscar Gruno & Andy Fedosjeenko + +You can redistribute these files as much as you like, as long as you keep this file with them and give us the proper credit. You may even rape them if you please, just give us credit for our work. \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/cwy.png b/Upload/jscripts/sceditor/editor_themes/emoticons/cwy.png new file mode 100644 index 0000000000000000000000000000000000000000..48f65f273ad7c0dab899754beb1af731e9693d53 GIT binary patch literal 1011 zcmVeJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ihK|__3K~9Q|;s4+N3=bcEx43@uhsB|DUu$2z|JwyrHyMbZAZrE) zAY=m>fmk1im$=*WX@>@jFa#t$Lw5wj<{9D)jut!&Yqz~G+jsuEH&7@Bh%W*$IP3rd z2-!eY78b^x`N`s9hQ{0s9#Kyj_MCnXmT)l@L}724EzS_(E6AWO!>T=d>!VSA_WpiW!=q8io!);y$S_8CdyP81%Kc7<^1PC4j=EK+FY_2M8dT zf%-Dytch;U0t_CJs4fFxbT&xdH{%rp3pW#kqcInQI3H6AP*@Kn2M|Co1O05xc^FvO z8A(baOsq@{tQ<@X=E|%ft}loH2q2h&u6mlB42)3o*1UmWYyeq~kqLwu88oH920DWX zfB=F;ijs&BGccYYiG0f4uMp8GkQBj^Bg60q%7)2-HG^;zu*5d{Q33=Oy7L=2c&8*hyVy6n1LG) zo%_b{^W$%ZKVN`~fErvvpE0$+D(_e;PK>G9} zuz{OF1V8}6ynNx=yT1$e9{!x*YRkjmll6&V+iVdACKe_Jm$2ukS#P2s(6B!YLDioa z7A3JT9KQaG;l-E#^P$;~0U&@FLB$uev{47@Kb-2$BdV{(!N9`B%)rFP1Wp=YU;l%6 z_0QM8P}luoxN`3o!=iJ)UI9bM7L@fsr42v;A?M{=Knb_$+rKPvc=$`(&w`7A1DF#S zSs3A721NiU%)SG?y6xgmhQkm4UWFD8w_%0=1Q4=;pcuFS#2yE({mQ-i=uerYG7E#M z1Pg<-AQRZYC$Il9+u$69;=1Q4>9u@$hO?BoW-no#lUK)eeY0ay!I hfB<5ob`<~+U;vmlZB(noE>Hjf002ovPDHLkV1khUyAc2Y literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/devil.png b/Upload/jscripts/sceditor/editor_themes/emoticons/devil.png new file mode 100644 index 0000000000000000000000000000000000000000..399d86e94dfa909b2fe1bab907fafe030efc7bb6 GIT binary patch literal 1133 zcmV-z1d{uSP)`Z@{)b2M{AJML_{Si} z`j6rNKL&=|KbQnw{QM^`2$U~4@PoD8gv}esgohJA05O962egs#zcfQA!)u1-`Zqt+ z47gv1z{vRNK zU|v&YeabMoRPdLYngcHbr>Fpf#}{S>W_}(h=4J5w!^yxR%Fm#z&%lt#_lF_p_b+9j zHQPaYK?VQ>5EIZf+zfmS6=7k&#VYvu7?}Hc7?_ed81{JaGq^nb%)r3H%;5UuE11um z#?8PygP$Q#K!8Cn=O2Tw+#d;`8KpooxBvo(AzYEes@R|X|Bv%*|Nq_<|L<%f@c;i~ z`TzefEByc8s{rBmDFXS5U~v%t*JY0XUk)++e>I)qf1Voq|8PDI3xEJ(Vvu0)v$Orf zz|6tU;1>RqVbAIJ3@(8m85jf^85mp{8TOi$ObqM{u6i2(7#NvYP|}4Icw6)`fn_`SoFXM|7!T>n7^DFOr#3pfb?)5-sTe;IbK zP`zMCqAAr0+pacj}0}wzU7u|pJiV-OIi@`Pc z3(!j+;F=H_5}q-E2K{F6i2BdqnT_a_6x`;TDT9s&dq$VIy^USl$ll=%T;iHp z1B=@yFuec)gkliXFis$)3&c4<9NTi>2RNzJIdFia7X$GWAifMV#5Fo$+QK`=^7{=o700000NkvXXu0mjfu59s} literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/dizzy.png b/Upload/jscripts/sceditor/editor_themes/emoticons/dizzy.png new file mode 100644 index 0000000000000000000000000000000000000000..6505635d723e26e3829e6fd98993702ff6b2d560 GIT binary patch literal 1056 zcmV+*1mF9KP)eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*epV$Otlz0c0`LUq%Kd zpcpsMk_caZ26Y)$?b%yDZwK0A57d7PWC%b2!3^XE;)*aIelbH6ZU$y{Mh4fQXKna3g-jyH-G>F+Z^t|VO1Q?^Z)y0wf}z~ zX#RIL5%`Y`u0>mL~Z{qc|C-N%0*GaiBnfB=FSxck!8AHYQWm*L;fzi?Y!f?qPY zguFx;`tLtDx%~V25A5YX-~IsUzYI5@{Q;S=7eoLA5X``h!0g2E^W$%ZKVN`~fQGt+ zzGB$DQiNg8Dp4>Sl=WP~UNg8xz5yEam*My4KMcP={bl&|`7guiM<8!8Yz7ek0R#)f z3(wyDU9k7?*92EvF0kfpvjxG~3>2O_7YZ@BM!aFzHd6rX#b59LF#P)Po8k9|KMaSj z|6+LY<^OzW_G17DAeez)fw*J+(eK_OJdC2C9KgcG#K6SH2sRJ|HuduY4FdY$E68EEtTYq1H^g_*G008;csm}3r+?OZYBms7D!xxT>baQ ze{h(62O75R;%|n-5C6gnhubhi00IcvKv2+M0Ah~=*M8?-ee|cy5|{&2C72nc1)0DG zK6(9@;r5Ha3@0A_V|erJKi1+4Ab^mIFKh)YC_A|Uu_jdfIuP%IMgZ0V79fBasa*vC a1Q-Aae7n@jxSMVO0000eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*epV$Otlz0c0`LUq%Kd zpcpsMk_caZ26Y)$?b%yDZwK0A57d7PWC%b2F+mOE2I7h^AAT`I6K)1(4n_vI;O7jk z0ncFmU||5LCFUHlPZAVZninHX5OnHU_6IT^(Hm{Ndd=z$CZ2q2h& zezxY^3@q%7U{`>Ei>V-(1{(@>DYBSX;v1mlObo0XObq7A;E?kL5dZ-MGtgB}lLHc7 zBmht_fUu?%*g$6x0T4hi1C>OCm_Q-VuxFhl+!Zia?O7**A+~d|C|ErxJovf54p9UV z00G1TPdc~m2de$^AB-9PA#xi)0Kp8r|K`|KB|6ia%KmUPU_~+XnApMu&=CeN_GxmZAfB=FSxDlA07=C{I z&G6?7P!Z73f4?D`VFrV;9!Tu(kH0{J{xbaj{Di{`Ssy9!|xA&7!F_m#qi?G z|M}4D#{dvOFay5=amV_j-@Qe67)3!jU_&P``>_GD9up&jd;B|wP5r!Jum1V^7i=KN zbyx2FX4rn~?<)VE*wBXe*uU+4qW@4d-c(uGD~0%P?cb2kQQVD8~Eh)UxwQ+{xY0+^pD}q zxBpm+FMt3-b|JO`7L=XbfLIeMejSK+K_dWb0Sgd7jMT0I00ImE5xeJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ihK|__3K~9Q|;s4+N3=bcEx43@uhsB|DUu$2z|JwyrHyMbZAZrE) zAV!dvp)OP+vam4j%uf~l|P2($+n%pi-I{{CZN0$RWg z#1X!N4C*qh+OxNQ+WzMsgFR6HEs!Aq0mK9~j2nn6!h8h93{AKhm^qk%8kr!5flOok z&%g*&2@+#wXJ%mGVrF3FV`0$O;$rYI;gkR>Dg|OLkU;z^+Gtkf0oQHu0s0bEja6=&e z#Wa+K32ZqlFr3YmSwT8{K?Fbm!3=cO)8u3T`H&H28nPiMdhKYAccpt=^CQ-ETBe?ScS{rNA$?@xajegWyzkH7|Q z1`z-O1T*l$vv+?N>^=OM;n#;>K!reqzXA>Z26D+CCVD-d_AKl;sEgojB~UyB2r8<^Oji5wacAg})U`WNcDKMYsy z{bJaD>-Q^=UZ@!i00D%Ymu~@s&TabkFH0OA{?hid;9}qa<^)C-M!1(j5dd=Occ53d zUHr*#_~Bnz;cy#f2tWX_pe8hi3qb5~;M%X;tB?MaSt_$Is7kOfNDDH74Se$YFT?E@ ze;7_Y`pfX<+kdRZ7eD|Z7hl*4SWtFy17c06_;n!O1&si#1uQ@SF;cq<00=Muw1A|1 TOL?|v00000NkvXXu0mjfQS7Kh literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/getlost.png b/Upload/jscripts/sceditor/editor_themes/emoticons/getlost.png new file mode 100644 index 0000000000000000000000000000000000000000..ff27c444294d5b6a12ae061901a00f545abb61db GIT binary patch literal 1026 zcmV+d1pWJoP)eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*epV$Otlz0c0`LUq%Kd zpcpsMk_caZ26Y)$?b%yDZwK0A57d7PWC%b2F+mOE2I7h^AAT`I6K)1(4vy#0qp3 z6C>CVsMEj{7{d%^g&NGw#NcSm$so?hlme910~rJmKrk=+*_v}Ru&^_N!^|b%DM~Eu zSue@p68IcNY{z0zputQGtQ<@X=E^J#o6i681qz=42q2h&u6mjrU@tN#-@N+G@b5Py zy@3_{M~;yHaMv&ZEd&|z@7F&t{`=z}!@H0FKxRAy5dZ-MGjR8%t3QB=_AkS~pMMdy z!VG~K3Ub+Bpg})@27Uj>@aNkfa9G}a_6KCfUJwBgKrjP00<#mt&yT+u{(J!{0vZZ& z?LWA|psWWH`}^ZB(4fBzzd!$B`2FcG!>`YO8BRX}d5d8)hyVy6n1L6bz5Bah@8Pcu zzdrm1D*VIX7WJCJHT(_OB_LOTFvv2nA@BbHF;LxyKMaSj|6+LY<^OzW_G17DAXub) z1>%nNN56ZE@Gy#ka=?a8VD@8UWN?pv3s$hHpBL=aKVLzv`wKSs%DvwV+i(4S1=0&O zg8?9buoeyuTCCcB7Mu(mz?{Iy0u9E$An*PMyYxHIux%HAGaP>S7o%_h2p|@;)O!Jl zJq}#^oqP4spE65e4p5a~W{?(S0vq_`^eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*epV$Otlz0c0`LUq%Kd zpcpsMk_caZ26Y)$?b%yDZwK0A57d7PWC%b2F+mOE2I7h^AAT`I6K)1(4n_vI;O7jk z0ncFmU|$8^f>9e;H0c z0y|_ghyVy6n1L6bz5Bah@8PcuzdrnC*gTmZuc08h6(wv8zd!t8IDGvV!;3Hf=R>m} z13&=5!tg5)cdS49-CKl*Q52K|HgxjfG<10ZE5omMe;BUZ`^~WZ*56kky-+h400IbW z;ozXfs_kdN$-n{335+bz6a*}7{{Hw64zur{{xWR4_?zMI!@n4X13&;F7Y?AfzW~G@ z2d@3jz53`+nI$j>s7f$1NDDH74Se$YFT?E@e;H0Z`p59*+kdRZ7eD|ZyAWFe3(8Jz vK&%NBzYfH^pb>zzfCUI3Mrv09009O7>fSn&_s_dF00000NkvXXu0mjf(SDt+ literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/happy.png b/Upload/jscripts/sceditor/editor_themes/emoticons/happy.png new file mode 100644 index 0000000000000000000000000000000000000000..1786b9777d3310c53197eea4aec7cbc9a1d443ab GIT binary patch literal 1062 zcmV+>1ljwEP)eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*epV$Otlz0c0`LUq%Kd zpcpsMk_caZ26Y)$?b%yDZwK0A57d7PWC%b2F+mOE2I7h^AAT`I6K)1(4vy#0qp3 z6C;C5z*7bn|ED0Qfn5l~E`iS&Ttl9N)qoA=W@2zO=424(V@d(4&;uC+5I`^k{cO#- z8CcjE!C?k6Y|jQMFm?%e1~wE#?^!Pi#1af{VJ{e%Sb)A@Wny6EU}7*=28Wz4hyVy6 zn1QZ(njBy+g5aJFl2DiZ2O9!%-kx<5aM$ixE5QH?4Nx$Eu%;B)KxYsE5J0dP_H5bnB0FDhA{ZKz+tTjA^-x21)hBV0Hyx@17Zen7-AR#GYFJ~{{4rj{qrA; z8U7*E00a=s%lF^B`pxj~Hzd7*6~J5za|zTn3_uG(hWz{W4~+l*_{Z?><3ErY4?zS# z0Kp90ed+2CV50rY@bBkegsm_`V1|NR_7`Z-PoP2H|1tde_6JD+Ww`n556FzYAOawO zU%^(6GfM5n*c=qn^g1v{oGW`1R8>sLP!?xLi46fmC7+k_$gIxi_Aj`mpy#E8l zKy@GfFdV-Ai{ZtW|MQ{Qj{zWnV3G0_h&$FF{q8No!zc>M0W4fh44e9S!4dQes1Xzq zAg})U3Ub|Fu)$aE{btyH>+dU&UZ@!i00D%Ymu~^{q}%lE-~cGglr%v=q~`V$AN3VbFV)7Q)UUw0jd(r z4AO#3U<04L{>yOt#b1UKkNz>d`Su@c@dXe-$i)}70v42=+<;gUDt;Y^cR?cnYXJ)o gK#bI`0ssOG0A>29+KBE?CIA2c07*qoM6N<$f@g%$GXMYp literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/heart.png b/Upload/jscripts/sceditor/editor_themes/emoticons/heart.png new file mode 100644 index 0000000000000000000000000000000000000000..0049a53365c1231a720bca2c9cb7774226afdac1 GIT binary patch literal 852 zcmV-a1FQUrP)le|cn=W& z1!8j`4gg|(AifR6%YpbP5Px0p77`Z#0mKN46rh1TKq_5@m!T(GiGe|ppPAwAhrbN# z9x^ao{m3u_DEC{Pmm$|dl7T^)n}OlcM+SzqPZ=1V|76Gm%FP2B_!VRhKmZ{d=%T>G zu)D#Ai-Ca~h(W@?|1dE8{Ke3A;u`}qFmTFk`572kSs569{9<7E@QLB|dj^J{y9^93 ze=)cK4crSd2Oxlu!!R;f5lHg#GB9v*GB9ufF)z^3g8U4T>I@7*96&iP4v09I=3wAr zXJByPhvp!RlkY>0iGg27?V}fEWgp`}N@mSji`#-3LB__0ESG0uVsR2JX7~ zm0`k+n?QwcfEwQeRelEQ`t}`yKLb<6`;QFY-~C{C2TU@rKQl0_0tV^h-wbU)y?bGX z00a(O87_2}ForD=A17skAKYv1eyanj0(_g{4BoP{Rzrf)IH4q?xu;u0N zP%oJ8d&{tF22krOU;=&v41pytz=nZbA(av6 zfZIR8fnNs1Z*XY>2p|>$g$GDu!}T8wyP!$_I6lKb03d)^h$xYs0TazSDEl8F#Q*`s eNbM>BAix0hsq$Da^udP!0000eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ihK|__3K~9Q|;s4+N3=bcEx43@uhsB|DUu$2z|JwyrHyMbZAZrE) zAV!dvp)OP+vam4j%uf~l|P2($+n%pi-I{{CZN0$RWg z#1X!N4C*qh+OxNQ+WzMsgFR6HEs!Aq0mK9~j2nn6!h8h93{AKhm^qk%8kr!5flOok z&%g*&2@+#wXJ%mGVrF3FV`0$O;$rYI;gkR>Dg|OLkU;>SJdP0-~KUh zul$LU(OGAHW%vcmdLaD!!*7Pe*MBj*`0{@~H2X0C1Q5)?uRz?f{^+;Y=g$LO`sNqI zuXjLAA3*pI*buPd37^1nKi~WY%U`+oi(&h%->*P=p=K}u1Q6E3!9j~n+s}fFfdiNm z7+Iis`7a~_Kw7DHW0000eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*epV$Otlz0c0`LUq%Kd zpcpsMk_caZ26Y)$?b%yDZwK0A57d7PWC%b2F+mOE2I7h^AAT`I6K)1(4n_vI;O7jk z0ncFmU|n00IbR;QcqRejCUDV~&Xx=>L!xL}jxLUAzo`fBa*3_wgTy`w&C`1Q09?cVD{t z1DI(4GW`4bm*{-^=i48Kzu*5d+HI?}ELDzcT##@S9=tWPTKld)^9yF-k#D!p89X!yksj z*MBj*`0{@~H2X0C1Q5)?uRz?f{^d;NRwAlHK00000 LNkvXXu0mjfT&}7# literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/ninja.png b/Upload/jscripts/sceditor/editor_themes/emoticons/ninja.png new file mode 100644 index 0000000000000000000000000000000000000000..5d562b30b2df4f015914288671c46af124b30056 GIT binary patch literal 878 zcmV-!1CjiRP)He@E8z0|5ev2}!*wP|;2u9Ubl8 zzkh=Tn3$L_FbfL{10y3N!>?bz7*teLw1HyVL3&|^00a=sKyDze0J==<`}gl)jUY|v z03-&I1Gx@_L24Bg6eNIBr9jLDQUee`Faz~PL_`un3P75ezg&Q0WB?Om{dNg#Ajoi# z9)5oQ6ri*oNDV*$!3^{h7Z(Q`#`5(d!=BUc;TUAV{>5*>G_p9`_sa}>``>`|2nq^< z%8bLI&_>P6*48Pw0V)*~( zA4>892q2h&_u1Ik4F3K8$H2r2Gz4fU10w^HE1-t2kz!x~TKezLe}+F_|1kXf1x%Me z{(+Mc5Ih7C009K^@@`PzI;IOV{QLPIY%543+_3*pHc;&UU!Z|M|1tdi{+Hp;w?7Q- zT@v6J2ZFsI0w923ImH^7)sAp;bHmdZ$O81V2o4r#ZUN;a7zQQsPoF+n19QqTfB=HI z@WQ)y?-sDLv%?kr`}YqkMm7j!Fc%jW$gug)?8g8QKrjQp0&&Ov`}beN3$l}M3A72Hka|i0Z z4KoBFfRGIY#Q-R;c|3UVpzHJJ&kVqr2Ztvpj6fI^n;=*H`0)eeGEnj50o4Of3IG9w ztvp07U_sf*4Tv?N;@5$A7Z7j8RlouS5F@p#0Du4k0Qugg#T{6*n*aa+07*qoM6N<$ Eg7wj72><{9 literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/pinch.png b/Upload/jscripts/sceditor/editor_themes/emoticons/pinch.png new file mode 100644 index 0000000000000000000000000000000000000000..deb78c6103d89a67fd23514d53e3a8c8d3f3ff0a GIT binary patch literal 1054 zcmV+(1mXLMP)eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*epV$Otlz0c0`LUq%Kd zpcpsMk_caZ26Y)$?b%yDZwK0A57d7PWC%b2F+mOE2I7h^AAT`I6K)1(4vy#0qp3 z6C;C5z*7dO)4&uM0}XZ!c@9&w2@C0T4hi16}nrIlx|I z1jh};fIaIa!G?hNE`dP9)=7Y+!0Ld?K*0dQno?i`ok0XZ0Kp7Y5)op8y9De#G($kN zOVA5cHUA-D!OsN_Yef(N5I{`um3--wgkLL(&^a!Jf6^s4juJX3r`yup$3`{R88_KmIYi`}hxJ#zPPR z5I`^kcVD{t1DI(4GW`4b7hx;Z5V)cLKo$ZG`Uy1X`#*+1-~IsUzYI5@{Q;S=7eoLA z5X``h!0g2E^W$%ZKVN`~fQCX``wwm~DC>d5{{Hw2H0UqG@6Uf2et-JQ@aywmhSQHg z-eTAcA^-viX5fWq@BS{>d-yBEuMfY03jZ*;MZE@RGmuL_t^i?>Wne?z{{dp4x(|OC z4qyMp@Z!t=`Oxgg01!a1toId&JJuil?k&Q@C<@8}8#;NwhJzA0IL?7C1$p()SCH%e zf(^cM?>EEtTYq1H^g_*G008;csm}3r+?OU`}9Ufd=DWkaz!s zUHTnp*tUzm84f@E3o9IM!wdlkAY=nUL4N^=Jq}#^oqP4spE65e4p5a~W{?(S0vq_` z^&bB`2YX_ literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/pouty.png b/Upload/jscripts/sceditor/editor_themes/emoticons/pouty.png new file mode 100644 index 0000000000000000000000000000000000000000..696fbde2cfbabbacf3680d2309cc94fff8a44e66 GIT binary patch literal 1028 zcmV+f1pE7mP)eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*epV$Otlz0c0`LUq%Kd zpcpsMk_caZ26Y)$?b%yDZwK0A57d7PWC%b2F+mOE2I7h^AAT`I6K)1(4vy#0qp3 z6C>CV7yqXqr-5Av!Y+Z&AO^ES4d!NIa5Uy*5a(k`0jkgg83YhOFa!N;&AAy^*cstr z#sE)E|DlHdM{+ID`z%0Ture{QaxgKND}zJM7eoLA5X?YVJxva<7a75EgJi&e1`Iw} z9mo?*5UeQ$HqaSF00a;$Qj|o5m{45;)VXJ!1QMTtVb5A|lpuh}{b%6k0*AFChyVy6 z7I^ac1C;vr4~Q8cVF>pzQci-p_W!^C5Ve2)gE7NDgc^VVf_eG=n^(UX{{4oeH?RVj zYhf;dx`qL0A;^$_zy5*o-yi=N-hKQBGUFkL00Aws&pZx)uu@^)D1Q5)?jlk^0@blwuhCg3`ihzbfT>B4h zFevMR#Qy&H3pD62!|%_37=C~H%kb;-Uxw3eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ihK|__3K~9Q|;s4+N3=bcEx43@uhsB|DUu$2z|JwyrHyMbZAZrE) zAV!dvp)OZq5P> zOsq@{u0fB0hRHz;`_BNy2!nU6k_Ni;6$1-56N95M7lSw-QwmUp9>^eo0D>9lXKT*G zz{1W54zoQQ+~MhX4Qm1Mxqwtst;xoixIwP}lBRBL!CT{~wSG(gVZ{Kt2or z1Q5*2_ustw&G7FxP{Ci20@QFrxP}2N_aB%Z|NZ(4#K3g<;~&Gjk6;5If(U>Bf*H8` z($(+aMEmdOf2gf!;RwPY!$1lA=RbzO-~TfF`Su4)-+cB5q-rmS00bgG+SML2{Saj~!D_{uO z0+rkX$ literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/shocked.png b/Upload/jscripts/sceditor/editor_themes/emoticons/shocked.png new file mode 100644 index 0000000000000000000000000000000000000000..1a8878699bc27953cd429d54b18ff5ae0bff908d GIT binary patch literal 1032 zcmV+j1o!)iP)eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0ELOhaSh$%O9E~{{#QB&~fGYGr1_1;R%s@X|b8ZF} zc1C!ZF~C#Pf2g7VkzD(qfr*6?XgL!DD+d#UxiUE9d_e?20Kp7&)zjo)U}OXu2#y;h z1O78$@WJYU%0R9KVNEHpfzBWTAb?mRa}w0G|Ns4msQvRFj2ZqR)Bpq!%**%Ry!y@X z?>8j9ffc}93v&t7H4H!tL5BSM^$(2y{`kl6?&Cj@84p1OKmfs9xck!89|n?AtPD)R zNMU4SfP_ohP4ee?U@uK?Fbm!Cbfzn4K7Y ze*Dew=L=BL&%aRD{=>+Ze}DW18uXXp_vb$hzd!wD`1ScO!|6vLZ!v5J5dZ-MGw{N* zcYhb`J^Yp7*N5Lgg?||SeEkE?X5h#;_W_JS0Bp$nKR^sr_u&u2;p@K`UVQmKADaCb z00Ic+<*z{8vHs|HZxJ3wQBV$G;bLN7VuM7Ei;)1_g+Jf?0=n)m*x)Poelu*p^%oQ- z9Z)kE00IbW;ozXfs_kdN$-n{335+bzWC$#6{{Hw64zuq-!?s=g&2aePUyQ;5Ab^ky z2T(L#0Ah~=*M8?-ee|cy5|{&2C72nc1)0DGK6(9@;r5Ha3@0A_V|erJKi1+4Ab^lv zh^>GHWhXZv)`W^*2jX4O2*6sv0t65vwW|Pt00RI%bBWCrqy#$v0000!c% literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/sick.png b/Upload/jscripts/sceditor/editor_themes/emoticons/sick.png new file mode 100644 index 0000000000000000000000000000000000000000..7003b695ca4a958c77912de6a7143d6a20abf568 GIT binary patch literal 1041 zcmV+s1n&EZP)He@E8ze(7%pfB<3y zxe(1j86eIT5MnOVHfCm!Q)Xfikz``{^ZP%;vqyg!9^d`PaQpIqhR>h=b^+B*2I42k z1_A^SvVn|1tPjLXjIG$T9lTi?xVV@Z7?~hJ^8X(r!_VLU7=C>J$MEj$UxpKVe>2>< z`tK@GDh7xzf|P&^1PCA&B$uhOFf;A+jb;|&cMo!Fzn8r_h1YH zFm`{?U$7c3PG$xkZYBm5eIT2MDFvuR52OwtfM5ptX&Esyumcq`104V}3>yH6PYebc z%F4*V22{_<$;2Qg`xhkT3nBml2xg$Gk~%N~fQB(LGQu^hxCnwVIvX5=z{p}@VPs$h zVqpoekTZw?2q2h&O1uIHgGx8CplC)0Ao1djEGS}ZoM1{3L;wU3Oos6f(AEDz7?g8> zt^^s13;YGfI4BwY`SYLQHxL738Jg-C7ytqY=ED2$-~46x1(f{z7o0-CpxX~MmO*@w z97xS?U_$@(^FPDSAO9G>eg7`}b`$MF6I*qFT_0w92325!7{`7guAkN+4xfBg%z^*=DH{R3+T z+cx7LmW{bfB=FSc;VCge+$kZ`_1s--EW4EpZ+j> z0ovXh_?IDj1tWuX+<%6wWlRhcL;iu~Kx*E-{loD7!(WC+w;6#x`#&F={TKiO2stmS zGchq9HgRASRn}x-;N}LUGbV6)0|7{w0mJL-f3V9weEiGs^!`7FM^{;1{rmsl7L@fs zc^M#pkfZVzFt*%I?fbvv<>NovT4oFkT)>eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ihK|__3K~9Q|;s4+N3=bcEx43@uhsB|DUu$2z|JwyrHyMbZAZrE) zAV!dvp)OP+vam4j%uf~l|P2($+n%pi-I{{CZN0$RWg z#1X!N4C*qh+OxNQ+WzMsgFR6HEs!Aq0mK9~j2nn6!h8h93{AKhm^qk%8kr!5flOok z&%g*&2@>;&e#YRF`jUZ_kA*>Bi;Ka>gi`{js1%5~Kn4K>5X?Y*8FAJ`H)jC`CRQe} zW{@Eer!hb=#Na*aWWgGk*%=vFxS1Fnjky@a`Iu6GLV6%^fB=Gd+0WLThk*sC2oz>6 z0go_ZYR`IEsB0m7CKe{J<*dMPHdkh4*mVAu17#Nut88oH9208mvfMTwZFTfgpfBwtx`_o^BUqJfwBd~#+K?Fbm!MuFo*}K0B_8$J6;A+bQ)XV}* z+)Uu4!N~L<9%djfZk{LzH0%$~cG#Dbd8 z7%l*@$AN3Va<4x6Q)a2m!k{X_!XPck1UB%=>%R=QU;JS>@#rtZn{WTI7GD4Xgj{@K zD_}v{$qk4#q2kwpco#GRuokcY0mMk{DgYqB0PtvgjlFgXO8@`>07*qoM6N<$f?%P? AJpcdz literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/silly.png b/Upload/jscripts/sceditor/editor_themes/emoticons/silly.png new file mode 100644 index 0000000000000000000000000000000000000000..9f351a98a273e678a0b34d2c4dd897747b4a1d35 GIT binary patch literal 1025 zcmV+c1pfPpP)eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*fyx@C?QIJC=$wa04xg z@a1PvmtobOz4h~Upgs0Lsaqg24)UM1}0`Euwi@N3Nq~B zF@Rto+avlV0}B^311ldhgT59AgO3S^1W<1&5OaYH0tg_Of%-DyEQxN;d<;yij0}uS zj0`RTPr(u{!tWVezFdG{AR7cghBC7=F|cqmF*q7?GKljrr2vKXKym;91oN_=tvNRX z3p*n?%s__i*&qd#`VU43@E;sOt|2cOHcb{}VC7(9Fjr<_*mVAvFHrIXKmfs9=&Gm5 z!NAA}G!O{)Y>))%`wzu1LlJzCx}8fzfj(gXV@)ZryPQD;Kmfs9s3ao9gwTZ5Wef

    fuUj1hH_ZyPlKnhR{JN+KTFc9A({w>45U%+(v;~&GjkN-fz4?zS# z0Kr_i`_k1P29i>&z~lmSAsZ81BQike|M~WZ;qUjq3^$+s0de<&2!H^Bxo{&eJ2CwH z_?zL+7oeh_e~Bsxet-JQ@aywmhSQJ0>NkT3fB=HI@WQiqe;4dM{58SVmJ6ILw#^n~ za4{7`gxP#l{)!SdhF|agFdV-Ai{ZtW|MQ{Qj{zWnkn^%S3lqcPRCg{>P!3?>Vq#!o zV}wW0e_*)&`}vRI&)2^Uzk#j-x$ern-wcb+{eA_^dbXgf2g=I;0fd~FZviFTrf>hY z#Npv@Z9fZ61`c3OU}S-&AfT)N{`e0Lv+qE|wq5+qaQNY0SmAIRW(Yt4v7lrDpw~e; z>%g_&xmO?kDYFFT096TQ25CViuz^or|7E!S;xEIANBH}7O(&T#7ONb03g5sn*n2awla*&00000NkvXXu0mjfLt(@d literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/sleeping.png b/Upload/jscripts/sceditor/editor_themes/emoticons/sleeping.png new file mode 100644 index 0000000000000000000000000000000000000000..2d58002aaf5082a8d3a35aaea7be68dd1217ba7d GIT binary patch literal 1132 zcmV-y1e5!TP)a73PKo2V9)9Ij0_|KfB<3u8HkRZO$7d96DI}(1P}|l1t6EgT!!vyVq6Rm zKt#EW6c+;o5F?0)aO7lo^MwN=3`KZ;FoMKEG%>-qV*hsrfB<4a){L$IW(kZY#$bQ| zV!$WLWHHv z-jbI=LzR<3PKu4;|KI-%4XK&%hM zOWf`Gv_peM7&thX7#NwMsR3x3O{kK4d00a;d)G%%!t_brH6f-p8W?<%E25Mx27zQ$p@jnA2P$fu=nVp$| zg^QVim5+r%UyF;u$AnV?sHhZ(xj+U11Q5(XeHn4qL^o#v1}0V}ux5}U5T`LfF_OWo zj6j1K8CbZP7#xkc7{vLQQh+M-Kn4K>5X?Y7TXP-;7N8{>=9Mg~nOR)$UIe>wxDssREBW}uRY5HrLD;5_jkVi3%`3{WwkK~N@C zEkpr77dZVZf(U>BVu2?gU{wA82h8CA{()_U>->*Wl0Yc1Iv@?w1H=qKJumQq;qdie3@^U?pAXG`3;+QHi@P08Lr&>#jyR>?^htbP%{_+ z0tjp2;Go5(?PtNozyZt&j4X_BFM}cg+4Mz$dT>eUghvCGdzYK4_{l{8-0R#}T3$YcjpzP!Z y#F|j?>p;8<8UYvuEXaib0mKNa=&1z&0t^5JLq3WGn3`|^0000eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*epV$Otlz0c0`LUq%Kd zpcpsMk_caZ26Y)$?b%yDZwK0A57d7PWC%b2F+mOE2I7h^AAT`I6K)1(4vy z#0qp36C>CVFaV{3{|pceG8?D^qy}s-Hxq-SF(-pKA5#iYN)IFt5I`^k{cO#-8CcjE z;bF!APfh=!hW-jQrGJ0?V|e!w%zg+W00IbR;OOE`ULp)- zKr-|nD1rZD`1kW4gIDT%hBXbG41d4>Ww`n556FzYAOawOUS^ z?A_l5dk=q2aJA(EYu+|nkij+l4b~E6T?;qEFJSij{oxP8;p@K`UVQmKADaCb00IbR z;8!5-Sby}pw+IiTC@2T8a4|7#>gRR|1#Wu@t5Jmqkjx< zzWv8qd;tUya`A<&fCXhIHz3x8ieCrfUC;=?TEGGX5F@p#0Du4k0JjQ)u$q7~2><{9 M07*qoM6N<$f}6#>H2?qr literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/tongue.png b/Upload/jscripts/sceditor/editor_themes/emoticons/tongue.png new file mode 100644 index 0000000000000000000000000000000000000000..dd1ac78857f6fcb477daf22be5deb795bfed366f GIT binary patch literal 1046 zcmV+x1nK*UP)eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*epV$Otlz0c0`LUq%Kd zpcpsMk_caZ26Y)$?b%yDZwK0A57d7PWC%b2!3^XE;)*aIelbH6ZU$y{Mh4fQXKna3g-jyH-G?w8K^HK&XVZn%*VjQ3NZ|1 z2m{2oV7zC86om1Qfx#u{Im5R3A`C3tObm|3oD9cr{7QNG>EB$Sf)fA%!~`|a&(@rq zfd%L?P?&)=Lk)uZ7mC55&aiupI0F+4(EF@R46GbX4CcyUclm+{fB=FS=&Gm50S+%l zaNM97g2o4{11e)=f?!Q4uz}7X0w923URDwjVnS$w`4v6Q!{lJD{|{mCbAcSepa>!W z0*DEoeEtBX{`~`ok4xZlgkk^DTnnT@>fB>rGx+9wVEF$B6s`!H0Rjl-!uxMt{Wg%{ zV`kX35*R+rpn!jYH;ZkXEy(ce{U3(!FMlz-`}hwe^bkY<1Q5)?-IuQZFp!jD1slf5 z#>B8^wHP?5yM(-A*kc(EH^}AqN`@Wtg&2N+{>$*^+aHF%-~Te)eD((R<+n7@+fkDHjxjjLcB4Or42vnvnp|pua!^|1kXi^q1im(BRXL{(@vSg9v~C zf`#FQXYc+l*n9XZ!>@P0!G?n{$PkcW8#=gwa=*a% z*SkLqSML30*naEpE0A8O84Lgcgtc&R&|=m0v*2Xl0OkZn7HA3rmNtKX{0E2Gcc53d zUHr{(_~BoS!T}(FkP8P;fL#D$j|10!=U#pEr_2(V15_oL8Kec7zy>~f{g>hPi@yvf z9{po@^X)&@;tL>vkX?wafCXhIHz3x8ieCrfUC;=?TEGGX5F@p#0Du4k08VLyyb|7+ QM*si-07*qoM6N<$f+!-}CIA2c literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/unsure.png b/Upload/jscripts/sceditor/editor_themes/emoticons/unsure.png new file mode 100644 index 0000000000000000000000000000000000000000..50ee79e581b56eb1627f3996da00ff878e9824f7 GIT binary patch literal 1012 zcmVeJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ihK|__3K~9Q|;s4+N3=bcEx43@uhsB|DUu$2z|JwyrHyMbZAZrE) zAV!dvp)OP+vam4j%uf~kHH=&bqgd95I{^&!?=OCBFsln%+Q3JftiCDY}lUD@4*;k z7>w-^{fvQyiBi;Ka>gi`{jw-kuEKn4K>5X?Y*8FAJ`H)jC`CRQc}*PusW z&Da3UP-b>U1{Q8621jEq25~;76rhwINFE@7U|#mKHRoYq0V;xp83?$T3ZfW>%x7X@ z0$a`s3}CW@KVy(3D~Y2|0rZ zfB=FSs3al;bQ&m;1JR!KGI(9LXN@#eEhtm`XW-`oJ3|pf00a;VJox~l>i@t0K>QDE z>z;KoV8sl`83~%JKx+Q~1JWQpK+FK-!vH`4!CZL%&8y!G|9%4%`~@la4|grxC9o_C zvJ{ve|NZ(4#K3g<;~&Gjk6;7A=?Wl#UgHK4i{np1#ce}6y>`u+JY z!|zXj8GZrj(~rOgZUzwm0R%Jf!n1dO7wkR!nc>%mUqFSw8Qh{?09_1n$saIwjd;P} z7X6aJBk?uEFJRUK;ol#AGaSDDi{ZtW|MQ{Qj{zWnV3G0_h&$FF{pKyg!z8M&#lf(l zlOL%06+Eyv^$UQ#`seFkhM#YMhJE_OaOK`FhV8e0gA{c@&0qisAgqOhgBF{%p9L2K z2QVivvM|EE42l3yn0*I&b=$?C42K{7#V8yA0tmTq0L8!sAoe(L?N{#AM}NvJm01{6 zC0H1w1)0DGK6(9@;r5F^3@0A_Wq9-LKi1+4Ab^lvh^>GHWhXZv)`W^*2jX4O2*6sv i0t65vwW|Pt00RK97@Z>n5Tua+0000=h literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/w00t.png b/Upload/jscripts/sceditor/editor_themes/emoticons/w00t.png new file mode 100644 index 0000000000000000000000000000000000000000..06e63e5462df740d3e8b1ce36eacee96baa31da9 GIT binary patch literal 873 zcmV-v1D5=WP)tnrU%mg^1ynZ~h@T*91_&Tz13|Xv1Mw1|7qs7eVPLrO z;5)<4mBL_2kb(KxpP))v8NzJY%J!ZA?hWL`0P#hT5|9i)03jQw%EH39^Th{tu|22X z!v$ST1sV2ikY{iSc*uY*UK`1$J$vh??SK9;*aL-bfy4m~?m&R}fI1JazU=`myRfK_& ziIG853T&V=hyVy6SfnV42r&cW=|97sb+Ra$_pFlv$KRfHsFv+qEY9%j;~#M3@^gWc zp(2O?2q2h&jQ@dA_5a_0ApQq21d>?5mcR{PBLxu!s{8vLsQwQGGXV9#06+l247~s5 z)o%kCJ{AU#nCB!F2Fr^%8Qy&a8~6}J00a;$40m6;`kmqLx4$HpE`PuOWw`kad-yZMx;8$d4O^7N z!f^QdFNPOi{?CVIKL&sRf*JS~h&$FF{r39&`ELws>QU3=p0|QvjBePKd%qaA-}?Ou zq!(%i13&;Vf=X;?0Shl29JJW9{Vcc`;wJsT>ay8UObpvD{$x1(@b6XR!U0sk0t67U zfhfh7C=XMar7{bHsssyzv>+3>w0ZLSFT?E@e;7_Y`pfX<+kcGW3uGWb0AVu_xqt;_ zCpRG0goeJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ihK|__3K~9Q|;s4+N3=bcEx43@uhsB|DUu$2z|JwyrHyMbZAZrE) zAV!dvp)OP+vam4j%uf~l|P2($+n%pi;TG#-K#zB?kp z5aBDxpf1CzJ$vh??SK9;*aL-cf#d)JhzV*KHxO5Z`3Q;`ns75Pb1*aTXgy-!R)5IA zrS<^m_WulwK$YKa$TNJsD#svX^MZkukA*>Bi;Ka>gi`{jw-kuEKn4K>5X?Y*8FAJ` zH)jC`CRQeh=3DX%-=24XG024sycrA({25@mFPCK)nAsT_Sh$%O9F4gc#QB&~fGYGr z1_1;R%*%eZ<~$56Kt-@HW01NC@h&KE9_unN@?}BTK(8}C)L~#^VFFvu3Jhm+Wmbkw z=YRSFrB46^5X^cK}pdJ_i2q2h&_ustwZ6E`TIVM(+w}B4-Fcskv5P`9{9}0c5o{nhO#uWD%*(qkUHuMDwEuqohuZodVHnJNAj3cj{O3Q0zu*5d z{Q33=Oy7L=2c&8*hyVy6n1LG)o%_b{^W$%ZKVN`~fExb&272c&%wT9v0gC<@@o8j>FUkoq4{GSiaehdHs1PjBjK-{tZ=r?Z>9wt$JEe-}2E@lQM zHb^4pvc3;i^m&gQ(4xOk*ZpC*a_<+z_FKPSf%HPnU;qdptc8Pv7Mr%81s4McFefmw zFv7hIiU5#HzXQFx?cz^{!w>&r6b=9Z#DbQ3F95N}fos2VuRi)yW~t1=pen(_AT7uQ zHt@;ozYMou{9!op=r6;YZ~w6tUjPAw>_Th>EGRp<0kI}j{5lZtf<^$=0u~^E7^z(a b00bBSPz9vdl>iM&00000NkvXXu0mjfXWqf& literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/whistling.png b/Upload/jscripts/sceditor/editor_themes/emoticons/whistling.png new file mode 100644 index 0000000000000000000000000000000000000000..ead61c092a93cfeea97e065fc28938f384119ba9 GIT binary patch literal 1126 zcmV-s1eyDZP)eJD-dfy#cu%dZXn(Q#Fv5iJ1&D)?ElUH5I`(g z#ASduS3-oP%-)ihK|__3K~9Q|;s4+N3=bcEx43@uhsB|DUu$2z|JwyrHyMbZz%;)3 z!hswNi~s?|2nrUc%Nc=KABdN@+w*CM28%Foa4<12GDB2?4FC7%Kf~W|e;K~L|IM&= z+k1w6=f7VCO2q*2MUWC?OZJ?8&j=7e$Szl9VPV{vpDZqBXw1#P#LmRv7W^12v1fxk z1IQ6ffB!Lf#XSRyt?LqEP?urVp1t+c_CNm^?14hJ(1QRVfS8~(HxO5Z`3Q;`ns75P zb1=gV1_76VhYXBBm2M&M5MT%@d&i)!#l_%b!YKjdmI5&s$i>J(0}wzk!}VpvSrgry z1sIrEnHXGy9x(vD1vd!9cJap)3#t9U;AqUnAkN2>0u<6icR4@+!Ggul)|`idg`E)| z#xMiW0lF9~FkZ}+Ss6B+|LH5j^MeuOau5xY0|+3P%U$&}IT;ukA+fq=gDiuKsURX) zfb2c%WH7`wPZa?M7bAnF6e~!`8AQMg1_6Kog1KBtLk)>53tVfg%r_!2@pUq!x{erqx}EB|3Lf?>>7xn(h$plmI8&r za$A;20DT9P|H}Y0_%Fjxp#1yCU>AX`;05B(Fv9@?2o@~&-@N+G@b5R!0$_4u`1c>- zi~kTd*ivA)v9hx;uyV06u<^1ounDp=a7lAANE`4oC`ht$!-56|00IbR`0h(rzk@T# zKcG`UzJOc60JQ*U6G#r^YDUKYaJ+8&7l!!S_Y8?1yr6(jLpB^BfMAAiJaq0G!_SYu z8UB3v!|?a#KQvze5iocD`TmFD&)44!e}NcApSk!0Y&SOx*de0Gh64l;EX*%Fd-r$2 z-ou|0Ty1%PhOz)N5)%Ux3o!dLL0tdq2hgRz{xSUi@|S^;73g|UJpBI8P#43&@CWGQ zwFka}l&wZK93X&ThJ$1})*t=mEyBYjs;|Ytz{17Mz{JJ`&Y2+a2j~+HIuKr>;dHdHYpwMz;!vO*axoo)w3~IOO+rKPvc=$`(&w`7AgBxf#3nL_0 zfCl~k26Q>lm9O9YVOVhd2gA!R|9=DZodV*yK)elzUm_b05J1R=gZzI1h&>Km`;~k3 z(VsF)Wflfi2^I!vK_;-_PhS6Jxc%Y}!-+?K8Qy&Rk5S~J1AqWRE^@I|7QR622E>|B s@#{dm3y3!pQ&|865F;(CIe-8I0Ijs0`ewHRWB>pF07*qoM6N<$g2%`E>Hq)$ literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/wink.png b/Upload/jscripts/sceditor/editor_themes/emoticons/wink.png new file mode 100644 index 0000000000000000000000000000000000000000..817ab1abce6082e79549493c49ec98c4695a7cce GIT binary patch literal 1045 zcmV+w1nT>VP)eJD-dfy#cu%dZXn(Q#Fv5iJF=z~`@b^)1P}`r zOJsmJS3-oP%-)ilK|_^;K~9Q|;s4+N3=bdvw77oryTze%-)mpJ|JwyrHyMbZAZrE) zAV!dvp)OaC97eR_ZE(8c5WEZNkurTh-PZkj~H0EJoVh7s5%*epV$Otlz0c0`LUq%Kd zpcpsMk_caZ26Y)$?b%yDZwK0A57d7PWC%b2F+mOE2I7h^AAT`I6K)1(4vy#0qp3 z6C>CVsMEj{7z4#zL!N`xfDPtmVsJF(WDw_LN&(91feZo&Aee!Ew&vUnEbNT%Fmv&L z2EhT(poT&X2ARtQ^gavF7pzPStQ<@X=E~rZ^92zA0R#&}S3OM*uooG@ar2*H&w5Fu z;6)e)HV~u^YpS zOhaIT|0R%H}_ob^pfQj}m!;VEF3@#xr5r#4# z8Tt>Dz<~z+1RC`HAH$z-e}ME~hMUj+fXvtnA^-viX5dC(c4GMX@i)VtFMk+zEEHyN z34I0D3^N#%^*}!O`{OUrpuY^iKmTF){pl~mug`xOPCxn!GGjA{00^+&&Zi|{atf^q;07Zby#eqL}Q{{__eALvq$SO0tkx$ZC6;4AljGi<;0 z_Z3Jl)C>lI07A~ow}5%lZTj|aOB^2l*7mdDWZ(ei1V$EUF#ZL3_dnRB-+_j0yZD>o z@Wa2b!r?Z|5P$$;K~2337l7E~z_s7GS0DW;vjpYzzfCUI3Mrv09009O7T%Mu1bk1<$ P00000NkvXXu0mjfYCFXX literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/emoticons/wub.png b/Upload/jscripts/sceditor/editor_themes/emoticons/wub.png new file mode 100644 index 0000000000000000000000000000000000000000..71423d112d725a6072405a51d919ca752040947b GIT binary patch literal 1159 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 Gp#K4sIo}=t literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/index.html b/Upload/jscripts/sceditor/editor_themes/index.html new file mode 100644 index 0000000..efd2f36 --- /dev/null +++ b/Upload/jscripts/sceditor/editor_themes/index.html @@ -0,0 +1,8 @@ + + + + + +  + + \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_themes/modern.css b/Upload/jscripts/sceditor/editor_themes/modern.css new file mode 100644 index 0000000..cd6da2a --- /dev/null +++ b/Upload/jscripts/sceditor/editor_themes/modern.css @@ -0,0 +1,650 @@ +/** + * Modern theme + * + * Copyright (C) 2012, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + * Icons by Mark James (http://www.famfamfam.com/lab/icons/silk/) + * Licensed under the Creative Commons CC-BY license (http://creativecommons.org/licenses/by/3.0/) + */ +/*! SCEditor | (C) 2011-2013, Sam Clarke | sceditor.com/license */ +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +div.sceditor-grip, +.sceditor-button div { + background-image: url('famfamfam.png'); + background-repeat: no-repeat; + width: 16px; + height: 16px; +} +.sceditor-button-youtube div { + background-position: 0px 0px; +} +.sceditor-button-link div { + background-position: 0px -16px; +} +.sceditor-button-unlink div { + background-position: 0px -32px; +} +.sceditor-button-underline div { + background-position: 0px -48px; +} +.sceditor-button-time div { + background-position: 0px -64px; +} +.sceditor-button-table div { + background-position: 0px -80px; +} +.sceditor-button-superscript div { + background-position: 0px -96px; +} +.sceditor-button-subscript div { + background-position: 0px -112px; +} +.sceditor-button-strike div { + background-position: 0px -128px; +} +.sceditor-button-source div { + background-position: 0px -144px; +} +.sceditor-button-size div { + background-position: 0px -160px; +} +.sceditor-button-rtl div { + background-position: 0px -176px; +} +.sceditor-button-right div { + background-position: 0px -192px; +} +.sceditor-button-removeformat div { + background-position: 0px -208px; +} +.sceditor-button-quote div { + background-position: 0px -224px; +} +.sceditor-button-print div { + background-position: 0px -240px; +} +.sceditor-button-pastetext div { + background-position: 0px -256px; +} +.sceditor-button-paste div { + background-position: 0px -272px; +} +.sceditor-button-orderedlist div { + background-position: 0px -288px; +} +.sceditor-button-maximize div { + background-position: 0px -304px; +} +.sceditor-button-ltr div { + background-position: 0px -320px; +} +.sceditor-button-left div { + background-position: 0px -336px; +} +.sceditor-button-justify div { + background-position: 0px -352px; +} +.sceditor-button-italic div { + background-position: 0px -368px; +} +.sceditor-button-image div { + background-position: 0px -384px; +} +.sceditor-button-horizontalrule div { + background-position: 0px -400px; +} +.sceditor-button-format div { + background-position: 0px -416px; +} +.sceditor-button-font div { + background-position: 0px -432px; +} +.sceditor-button-emoticon div { + background-position: 0px -448px; +} +.sceditor-button-email div { + background-position: 0px -464px; +} +.sceditor-button-date div { + background-position: 0px -480px; +} +.sceditor-button-cut div { + background-position: 0px -496px; +} +.sceditor-button-copy div { + background-position: 0px -512px; +} +.sceditor-button-color div { + background-position: 0px -528px; +} +.sceditor-button-code div { + background-position: 0px -544px; +} +.sceditor-button-center div { + background-position: 0px -560px; +} +.sceditor-button-bulletlist div { + background-position: 0px -576px; +} +.sceditor-button-bold div { + background-position: 0px -592px; +} +div.sceditor-grip { + background-position: 0px -608px; + width: 10px; + height: 10px; +} +.rtl div.sceditor-grip { + background-position: 0px -618px; + width: 10px; + height: 10px; +} +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +/*--------------------------------------------------- + LESS Elements 0.7 + --------------------------------------------------- + A set of useful LESS mixins + More info at: http://lesselements.com + ---------------------------------------------------*/ +.sceditor-container { + position: relative; + background: #fff; + border: 1px solid #d9d9d9; + font-size: 13px; + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + color: #222; + line-height: 1; + font-weight: bold; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 100% !important; +} +.sceditor-container, +.sceditor-container div, +div.sceditor-dropdown, +div.sceditor-dropdown div { + padding: 0; + margin: 0; + z-index: 3; +} +.sceditor-container iframe, +.sceditor-container textarea { + line-height: 1; + border: 0; + outline: none; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 13px; + color: #111; + padding: 0; + margin: 5px; + resize: none; + background: #fff; + display: block; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 99% !important; +} +div.sceditor-resize-cover { + position: absolute; + top: 0; + left: 0; + background: #000; + width: 100%; + height: 100%; + z-index: 10; + opacity: 0.3; +} +.ie6 div.sceditor-resize-cover, +.ie7 div.sceditor-resize-cover, +.ie8 div.sceditor-resize-cover { + background: #efefef; +} +.sceditor-container.ie6 { + overflow: hidden; +} +div.sceditor-grip { + overflow: hidden; + width: 10px; + height: 10px; + cursor: pointer; + position: absolute; + bottom: 0; + right: 0; + z-index: 3; +} +.sceditor-maximize { + position: fixed; + top: 0; + left: 0; + height: 100% !important; + width: 100% !important; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + z-index: 2000; +} +html.sceditor-maximize, +body.sceditor-maximize { + height: 100%; + width: 100%; + padding: 0; + margin: 0; + overflow: hidden; +} +.ie6.sceditor-maximize { + position: absolute; +} +.sceditor-maximize div.sceditor-grip { + display: none; +} +.sceditor-maximize div.sceditor-toolbar { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +/** + * Dropdown styleing + */ +div.sceditor-dropdown { + position: absolute; + border: 1px solid #ccc; + background: #fff; + color: #333; + z-index: 4000; + padding: 10px; + line-height: 1; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); +} +div.sceditor-dropdown a, +div.sceditor-dropdown a:link { + color: #333; +} +div.sceditor-dropdown form { + margin: 0; +} +div.sceditor-dropdown label { + display: block; + font-weight: bold; + color: #3c3c3c; + padding: 4px 0; +} +div.sceditor-dropdown input, +div.sceditor-dropdown textarea { + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + outline: 0; + padding: 4px; + border: 1px solid #ccc; + border-top-color: #888; + margin: 0 0 .75em; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-dropdown textarea { + padding: 6px; +} +div.sceditor-dropdown input:focus, +div.sceditor-dropdown textarea:focus { + border-color: #aaa; + border-top-color: #666; + -webkit-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); +} +div.sceditor-dropdown .button { + font-weight: bold; + color: #444; + padding: 6px 12px; + background: #ececec; + border: solid 1px #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + cursor: pointer; + margin: .3em 0 0; +} +div.sceditor-dropdown .button:hover { + background: #f3f3f3; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); +} +div.sceditor-font-picker, +div.sceditor-fontsize-picker, +div.sceditor-format { + padding: 6px 0; +} +div.sceditor-emoticons, +div.sceditor-more-emoticons, +div.sceditor-color-picker { + padding: 0; +} +.sceditor-pastetext textarea { + border: 1px solid #bbb; + width: 20em; +} +.sceditor-emoticons img, +.sceditor-more-emoticons img { + padding: 0; + cursor: pointer; + margin: 2px; +} +.sceditor-more { + border-top: 1px solid #bbb; + display: block; + text-align: center; + cursor: pointer; + font-weight: bold; + padding: 6px 0; +} +.sceditor-dropdown a:hover { + background: #eee; +} +.sceditor-fontsize-option, +.sceditor-font-option, +.sceditor-format a { + display: block; + padding: 7px 10px; + cursor: pointer; + text-decoration: none; + color: #222; +} +.sceditor-fontsize-option { + padding: 7px 13px; +} +.sceditor-color-column { + float: left; +} +.sceditor-color-option { + display: block; + border: 1px solid #fff; + height: 10px; + width: 10px; + overflow: hidden; +} +.sceditor-color-option:hover { + border: 1px solid #333; +} +/** + * Toolbar styleing + */ +div.sceditor-toolbar { + overflow: hidden; + padding: 3px 5px 2px; + background: #f7f7f7; + border-bottom: 1px solid #c0c0c0; + line-height: 0; + text-align: left; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-group { + display: inline-block; + background: #ddd; + margin: 1px 5px 1px 0; + padding: 1px; + border-bottom: 1px solid #aaa; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.ie6 div.sceditor-group, +.ie7 div.sceditor-group { + display: inline; + zoom: 1; +} +.sceditor-button { + float: left; + cursor: pointer; + padding: 3px 5px; + width: 16px; + height: 20px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + /* Needed for Safari 5? */ + + text-indent: -9999px; +} +.ie .sceditor-button { + text-indent: 0; +} +.ie6 .sceditor-button, +.ie7 .sceditor-button { + float: none !important; + display: inline; + zoom: 1; +} +.ie6 .sceditor-button { + padding: 0; +} +.ie6 .sceditor-button div { + margin: 5px; +} +.ie7 .sceditor-button div { + margin: 5px 0; +} +.sceditor-button:hover, +.sceditor-button:active, +.sceditor-button.active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); +} +.sceditor-button:active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); +} +.sceditor-button.disabled:hover { + background: inherit; + cursor: default; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.sceditor-button, +.sceditor-button div { + display: block; +} +.sceditor-button div { + margin: 2px 0; + padding: 0; + overflow: hidden; + line-height: 0; + font-size: 0; + color: transparent; +} +.sceditor-button.disabled div { + filter: alpha(opacity=30); + opacity: 0.3; +} +.text .sceditor-button, +.text .sceditor-button div, +.sceditor-button.text, +.sceditor-button.text div, +.text-icon .sceditor-button, +.text-icon .sceditor-button div, +.sceditor-button.text-icon, +.sceditor-button.text-icon div { + width: auto; + overflow: visible; + line-height: 16px; + font-size: 1em; + color: inherit; + text-indent: 0; +} +.text .sceditor-button div, +.sceditor-button.text div { + padding: 0 2px; + background: none; +} +.text-icon .sceditor-button div, +.sceditor-button.text-icon div { + padding: 0 2px 0 20px; +} +.rtl div.sceditor-toolbar { + text-align: right; +} +.rtl .sceditor-button { + float: right; +} +.rtl div.sceditor-grip { + right: auto; + left: 0; +} +.sceditor-container { + border: 1px solid #999; +} +.sceditor-container textarea { + font-family: Consolas, "Bitstream Vera Sans Mono", "Andale Mono", Monaco, "DejaVu Sans Mono", "Lucida Console", monospace; + background: #2e3436; + color: #fff; + margin: 0; + padding: 5px; +} +div.sceditor-toolbar { + background: #ccc; + background: -moz-linear-gradient(top, #cccccc 0%, #b2b2b2 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #cccccc), color-stop(100%, #b2b2b2)); + background: -webkit-linear-gradient(top, #cccccc 0%, #b2b2b2 100%); + background: -o-linear-gradient(top, #cccccc 0%, #b2b2b2 100%); + background: -ms-linear-gradient(top, #cccccc 0%, #b2b2b2 100%); + background: linear-gradient(to bottom, #cccccc 0%, #b2b2b2 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#cccccc', endColorstr='#b2b2b2', GradientType=0); +} +.ie9 div.sceditor-toolbar { + filter: none; + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2NjY2NjYyIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNiMmIyYjIiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); +} +div.sceditor-group { + display: inline; + background: transparent; + margin: 0; + padding: 0; + border: 0; +} +.sceditor-button { + padding: 4px; + margin: 2px 1px 2px 3px; + height: 16px; + -webkit-border-radius: 12px; + -moz-border-radius: 12px; + border-radius: 12px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.sceditor-button:hover, +.sceditor-button.active, +.sceditor-button.active:hover { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.sceditor-button:hover { + background: #fff; + background: rgba(255, 255, 255, 0.75); + margin: 1px 0 1px 2px; + border: 1px solid #eee; +} +.sceditor-button.disabled:hover { + margin: 2px 1px 2px 3px; + border: 0; +} +.sceditor-button.active { + background: #b1b1b1; + background: rgba(0, 0, 0, 0.1); + margin: 1px 0 1px 2px; + border: 1px solid #999; +} +.sceditor-button.active:hover { + background: #fff; + background: rgba(255, 255, 255, 0.25); +} +.sceditor-button:active, +.sceditor-button.active:active { + margin: 1px 0 1px 2px; + border: 1px solid #999; + -webkit-box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.5); + -moz-box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.5); + box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.5); +} +.sceditor-button div { + margin: 0; +} + +/* Additional buttons (for MyBB) */ +.sceditor-button-video div { + + background-image: url(video.png); + +} +.sceditor-button-php div { + + background-image: url(php.png); + +} \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_themes/monocons.css b/Upload/jscripts/sceditor/editor_themes/monocons.css new file mode 100644 index 0000000..752dcc4 --- /dev/null +++ b/Upload/jscripts/sceditor/editor_themes/monocons.css @@ -0,0 +1,716 @@ +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +@font-face { + font-family: 'Monocons'; + src: url('monocons/monocons.eot'); + src: url('monocons/monocons.eot?#iefix') format('embedded-opentype'), url('monocons/monocons.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} +.sceditor-button div:before, +div.sceditor-grip { + font-family: 'Monocons'; + font-size: 16px; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.sceditor-button-youtube div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e000'); +} +.sceditor-button-unlink div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e001'); +} +.sceditor-button-underline div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e002'); +} +.sceditor-button-time div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e003'); +} +.sceditor-button-table div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e004'); +} +.sceditor-button-superscript div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e005'); +} +.sceditor-button-subscript div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e006'); +} +.sceditor-button-strike div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e007'); +} +.sceditor-button-source div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e008'); +} +.sceditor-button-size div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e009'); +} +.sceditor-button-rtl div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e00a'); +} +.sceditor-button-right div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e00b'); +} +.sceditor-button-removeformat div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e00c'); +} +.sceditor-button-quote div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e00d'); +} +.sceditor-button-print div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e00e'); +} +.sceditor-button-pastetext div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e00f'); +} +.sceditor-button-paste div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e010'); +} +.sceditor-button-orderedlist div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e011'); +} +.sceditor-button-maximize div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e012'); +} +.sceditor-button-ltr div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e013'); +} +.sceditor-button-link div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e014'); +} +.sceditor-button-left div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e015'); +} +.sceditor-button-justify div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e016'); +} +.sceditor-button-italic div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e017'); +} +.sceditor-button-image div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e018'); +} +.sceditor-button-horizontalrule div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e019'); +} +.sceditor-button-format div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e01c'); +} +.sceditor-button-font div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e01d'); +} +.sceditor-button-emoticon div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e01e'); +} +.sceditor-button-email div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e01f'); +} +.sceditor-button-bold div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e020'); +} +.sceditor-button-date div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e021'); +} +.sceditor-button-cut div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e022'); +} +.sceditor-button-copy div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e023'); +} +.sceditor-button-color div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e024'); +} +.sceditor-button-code div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e025'); +} +.sceditor-button-center div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e026'); +} +.sceditor-button-bulletlist div { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e027'); +} +div.sceditor-grip { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e01b'); +} +.rtl div.sceditor-grip { + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e01a'); +} +.sceditor-button-youtube div:before { + content: "\e000"; +} +.sceditor-button-unlink div:before { + content: "\e001"; +} +.sceditor-button-underline div:before { + content: "\e002"; +} +.sceditor-button-time div:before { + content: "\e003"; +} +.sceditor-button-table div:before { + content: "\e004"; +} +.sceditor-button-superscript div:before { + content: "\e005"; +} +.sceditor-button-subscript div:before { + content: "\e006"; +} +.sceditor-button-strike div:before { + content: "\e007"; +} +.sceditor-button-source div:before { + content: "\e008"; +} +.sceditor-button-size div:before { + content: "\e009"; +} +.sceditor-button-rtl div:before { + content: "\e00a"; +} +.sceditor-button-right div:before { + content: "\e00b"; +} +.sceditor-button-removeformat div:before { + content: "\e00c"; +} +.sceditor-button-quote div:before { + content: "\e00d"; +} +.sceditor-button-print div:before { + content: "\e00e"; +} +.sceditor-button-pastetext div:before { + content: "\e00f"; +} +.sceditor-button-paste div:before { + content: "\e010"; +} +.sceditor-button-orderedlist div:before { + content: "\e011"; +} +.sceditor-button-maximize div:before { + content: "\e012"; +} +.sceditor-button-ltr div:before { + content: "\e013"; +} +.sceditor-button-link div:before { + content: "\e014"; +} +.sceditor-button-left div:before { + content: "\e015"; +} +.sceditor-button-justify div:before { + content: "\e016"; +} +.sceditor-button-italic div:before { + content: "\e017"; +} +.sceditor-button-image div:before { + content: "\e018"; +} +.sceditor-button-horizontalrule div:before { + content: "\e019"; +} +.sceditor-button-format div:before { + content: "\e01c"; +} +.sceditor-button-font div:before { + content: "\e01d"; +} +.sceditor-button-emoticon div:before { + content: "\e01e"; +} +.sceditor-button-email div:before { + content: "\e01f"; +} +.sceditor-button-bold div:before { + content: "\e020"; +} +.sceditor-button-date div:before { + content: "\e021"; +} +.sceditor-button-cut div:before { + content: "\e022"; +} +.sceditor-button-copy div:before { + content: "\e023"; +} +.sceditor-button-color div:before { + content: "\e024"; +} +.sceditor-button-code div:before { + content: "\e025"; +} +.sceditor-button-center div:before { + content: "\e026"; +} +.sceditor-button-bulletlist div:before { + content: "\e027"; +} +div.sceditor-grip:before { + content: "\e01b"; +} +.rtl div.sceditor-grip:before { + content: "\e01a"; +} +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +/*--------------------------------------------------- + LESS Elements 0.7 + --------------------------------------------------- + A set of useful LESS mixins + More info at: http://lesselements.com + ---------------------------------------------------*/ +.sceditor-container { + position: relative; + background: #fff; + border: 1px solid #d9d9d9; + font-size: 13px; + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + color: #222; + line-height: 1; + font-weight: bold; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 100% !important; +} +.sceditor-container, +.sceditor-container div, +div.sceditor-dropdown, +div.sceditor-dropdown div { + padding: 0; + margin: 0; + z-index: 3; +} +.sceditor-container iframe, +.sceditor-container textarea { + line-height: 1; + border: 0; + outline: none; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 13px; + color: #111; + padding: 0; + margin: 5px; + resize: none; + background: #fff; + display: block; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 99% !important; +} +div.sceditor-resize-cover { + position: absolute; + top: 0; + left: 0; + background: #000; + width: 100%; + height: 100%; + z-index: 10; + opacity: 0.3; +} +.ie6 div.sceditor-resize-cover, +.ie7 div.sceditor-resize-cover, +.ie8 div.sceditor-resize-cover { + background: #efefef; +} +.sceditor-container.ie6 { + overflow: hidden; +} +div.sceditor-grip { + overflow: hidden; + width: 10px; + height: 10px; + cursor: pointer; + position: absolute; + bottom: 0; + right: 0; + z-index: 3; +} +.sceditor-maximize { + position: fixed; + top: 0; + left: 0; + height: 100% !important; + width: 100% !important; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + z-index: 2000; +} +html.sceditor-maximize, +body.sceditor-maximize { + height: 100%; + width: 100%; + padding: 0; + margin: 0; + overflow: hidden; +} +.ie6.sceditor-maximize { + position: absolute; +} +.sceditor-maximize div.sceditor-grip { + display: none; +} +.sceditor-maximize div.sceditor-toolbar { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +/** + * Dropdown styleing + */ +div.sceditor-dropdown { + position: absolute; + border: 1px solid #ccc; + background: #fff; + color: #333; + z-index: 4000; + padding: 10px; + line-height: 1; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); +} +div.sceditor-dropdown a, +div.sceditor-dropdown a:link { + color: #333; +} +div.sceditor-dropdown form { + margin: 0; +} +div.sceditor-dropdown label { + display: block; + font-weight: bold; + color: #3c3c3c; + padding: 4px 0; +} +div.sceditor-dropdown input, +div.sceditor-dropdown textarea { + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + outline: 0; + padding: 4px; + border: 1px solid #ccc; + border-top-color: #888; + margin: 0 0 .75em; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-dropdown textarea { + padding: 6px; +} +div.sceditor-dropdown input:focus, +div.sceditor-dropdown textarea:focus { + border-color: #aaa; + border-top-color: #666; + -webkit-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); +} +div.sceditor-dropdown .button { + font-weight: bold; + color: #444; + padding: 6px 12px; + background: #ececec; + border: solid 1px #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + cursor: pointer; + margin: .3em 0 0; +} +div.sceditor-dropdown .button:hover { + background: #f3f3f3; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); +} +div.sceditor-font-picker, +div.sceditor-fontsize-picker, +div.sceditor-format { + padding: 6px 0; +} +div.sceditor-emoticons, +div.sceditor-more-emoticons, +div.sceditor-color-picker { + padding: 0; +} +.sceditor-pastetext textarea { + border: 1px solid #bbb; + width: 20em; +} +.sceditor-emoticons img, +.sceditor-more-emoticons img { + padding: 0; + cursor: pointer; + margin: 2px; +} +.sceditor-more { + border-top: 1px solid #bbb; + display: block; + text-align: center; + cursor: pointer; + font-weight: bold; + padding: 6px 0; +} +.sceditor-dropdown a:hover { + background: #eee; +} +.sceditor-fontsize-option, +.sceditor-font-option, +.sceditor-format a { + display: block; + padding: 7px 10px; + cursor: pointer; + text-decoration: none; + color: #222; +} +.sceditor-fontsize-option { + padding: 7px 13px; +} +.sceditor-color-column { + float: left; +} +.sceditor-color-option { + display: block; + border: 1px solid #fff; + height: 10px; + width: 10px; + overflow: hidden; +} +.sceditor-color-option:hover { + border: 1px solid #333; +} +/** + * Toolbar styleing + */ +div.sceditor-toolbar { + overflow: hidden; + padding: 3px 5px 2px; + background: #f7f7f7; + border-bottom: 1px solid #c0c0c0; + line-height: 0; + text-align: left; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-group { + display: inline-block; + background: #ddd; + margin: 1px 5px 1px 0; + padding: 1px; + border-bottom: 1px solid #aaa; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.ie6 div.sceditor-group, +.ie7 div.sceditor-group { + display: inline; + zoom: 1; +} +.sceditor-button { + float: left; + cursor: pointer; + padding: 3px 5px; + width: 16px; + height: 20px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + /* Needed for Safari 5? */ + + text-indent: -9999px; +} +.ie .sceditor-button { + text-indent: 0; +} +.ie6 .sceditor-button, +.ie7 .sceditor-button { + float: none !important; + display: inline; + zoom: 1; +} +.ie6 .sceditor-button { + padding: 0; +} +.ie6 .sceditor-button div { + margin: 5px; +} +.ie7 .sceditor-button div { + margin: 5px 0; +} +.sceditor-button:hover, +.sceditor-button:active, +.sceditor-button.active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); +} +.sceditor-button:active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); +} +.sceditor-button.disabled:hover { + background: inherit; + cursor: default; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.sceditor-button, +.sceditor-button div { + display: block; +} +.sceditor-button div { + margin: 2px 0; + padding: 0; + overflow: hidden; + line-height: 0; + font-size: 0; + color: transparent; +} +.sceditor-button.disabled div { + filter: alpha(opacity=30); + opacity: 0.3; +} +.text .sceditor-button, +.text .sceditor-button div, +.sceditor-button.text, +.sceditor-button.text div, +.text-icon .sceditor-button, +.text-icon .sceditor-button div, +.sceditor-button.text-icon, +.sceditor-button.text-icon div { + width: auto; + overflow: visible; + line-height: 16px; + font-size: 1em; + color: inherit; + text-indent: 0; +} +.text .sceditor-button div, +.sceditor-button.text div { + padding: 0 2px; + background: none; +} +.text-icon .sceditor-button div, +.sceditor-button.text-icon div { + padding: 0 2px 0 20px; +} +.rtl div.sceditor-toolbar { + text-align: right; +} +.rtl .sceditor-button { + float: right; +} +.rtl div.sceditor-grip { + right: auto; + left: 0; +} +.ie7 .sceditor-button div, +.ie6 .sceditor-button div { + font-family: 'Monocons'; + overflow: visible; + font-size: 16px; + line-height: 1; + text-indent: 0; +} +div.sceditor-grip { + height: 16px; + width: 16px; +} +.sceditor-button div:before, +div.sceditor-grip:before { + text-indent: 0; + line-height: 17px; + width: 16px; + height: 16px; + display: block; + color: #333; + text-shadow: 0 1px #fff; +} + +/* Additonal buttons (for MyBB) */ +.sceditor-button-video div { + + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e000'); + +} + +.sceditor-button-video div:before { + content: "\e000"; +} + +.sceditor-button-php div { + + *zoom: expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = '\e652'); +} + +.sceditor-button-php div:before { + content: "\e025"; +} \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_themes/monocons/monocons.eot b/Upload/jscripts/sceditor/editor_themes/monocons/monocons.eot new file mode 100644 index 0000000000000000000000000000000000000000..1db65477102f5e38d4de4d2b0b7618557c505593 GIT binary patch literal 8028 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 literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/monocons/monocons.ttf b/Upload/jscripts/sceditor/editor_themes/monocons/monocons.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d100abdf72a460aa813066000555d43240e47ded GIT binary patch literal 7860 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 aEObwBt`HleB`z_7y|Zxc`vPwKX8Ru)Dfl)3 literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/mybb.css b/Upload/jscripts/sceditor/editor_themes/mybb.css new file mode 100644 index 0000000..8d0401c --- /dev/null +++ b/Upload/jscripts/sceditor/editor_themes/mybb.css @@ -0,0 +1,585 @@ +html { + font-family: Tahoma, Verdana, Arial, Sans-Serif; + font-size: 0.9em; +} + +.sceditor-button div, div.sceditor-grip { + background-image: url(famfamfam.png); + width: 16px; + height: 16px; + background-repeat: no-repeat; +} +.sceditor-button-youtube div { + + background-position: 0px 0px; + +} +.sceditor-button-link div { + + background-position: 0px -16px; + +} +.sceditor-button-unlink div { + + background-position: 0px -32px; + +} +.sceditor-button-underline div { + + background-position: 0px -48px; + +} +.sceditor-button-time div { + + background-position: 0px -64px; + +} +.sceditor-button-table div { + + background-position: 0px -80px; + +} +.sceditor-button-superscript div { + + background-position: 0px -96px; + +} +.sceditor-button-subscript div { + + background-position: 0px -112px; + +} +.sceditor-button-strike div { + + background-position: 0px -128px; + +} +.sceditor-button-source div { + + background-position: 0px -144px; + +} +.sceditor-button-size div { + + background-position: 0px -160px; + +} +.sceditor-button-rtl div { + + background-position: 0px -176px; + +} +.sceditor-button-right div { + + background-position: 0px -192px; + +} +.sceditor-button-removeformat div { + + background-position: 0px -208px; + +} +.sceditor-button-quote div { + + background-position: 0px -224px; + +} +.sceditor-button-print div { + + background-position: 0px -240px; + +} +.sceditor-button-pastetext div { + + background-position: 0px -256px; + +} +.sceditor-button-paste div { + + background-position: 0px -272px; + +} +.sceditor-button-orderedlist div { + + background-position: 0px -288px; + +} +.sceditor-button-maximize div { + + background-position: 0px -304px; + +} +.sceditor-button-ltr div { + + background-position: 0px -320px; + +} +.sceditor-button-left div { + + background-position: 0px -336px; + +} +.sceditor-button-justify div { + + background-position: 0px -352px; + +} +.sceditor-button-italic div { + + background-position: 0px -368px; + +} +.sceditor-button-image div { + + background-position: 0px -384px; + +} +.sceditor-button-horizontalrule div { + + background-position: 0px -400px; + +} +.sceditor-button-format div { + + background-position: 0px -416px; + +} +.sceditor-button-font div { + + background-position: 0px -432px; + +} +.sceditor-button-emoticon div { + + background-position: 0px -448px; + +} +.sceditor-emoticons img { + cursor: pointer; +} +.sceditor-button-email div { + + background-position: 0px -464px; + +} +.sceditor-button-date div { + + background-position: 0px -480px; + +} +.sceditor-button-cut div { + + background-position: 0px -496px; + +} +.sceditor-button-copy div { + + background-position: 0px -512px; + +} +.sceditor-button-color div { + + background-position: 0px -528px; + +} +.sceditor-button-code div { + + background-position: 0px -544px; + +} +.sceditor-button-center div { + + background-position: 0px -560px; + +} +.sceditor-button-bulletlist div { + + background-position: 0px -576px; + +} +.sceditor-button-bold div { + + background-position: 0px -592px; + +} +div.sceditor-grip { + + background-position: 0px -608px; + + width: 10px; + + height: 10px; + +} +.rtl div.sceditor-grip { + + background-position: 0px -618px; + + width: 10px; + + height: 10px; + +} +.sceditor-container { + position: relative; + background: #fff; + border: 1px solid #d9d9d9; + padding: 0 4px; + font-size: 13px; + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + color: #222; + line-height: 1; + font-weight: bold; + z-index: 1001; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 100% !important; +} +.sceditor-container, .sceditor-container div, div.sceditor-dropdown, div.sceditor-dropdown div { + padding: 0; + margin: 0; + z-index: 3; +} +.sceditor-container iframe, .sceditor-container textarea { + border: 0; + outline: 0; + font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; + font-size: 13px; + color: #111; + padding: 4px; + margin: 5px; + resize: none; + background: #fff; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 99% !important; +} +div.sceditor-resize-cover { + position: absolute; + top: 0; + left: 0; + background: #000; + width: 100%; + height: 100%; + z-index: 2; + opacity: .3; +} +.ie6 div.sceditor-resize-cover, .ie7 div.sceditor-resize-cover, .ie8 div.sceditor-resize-cover { + background: #efefef; +} +.sceditor-container.ie6 { + overflow: hidden; +} +div.sceditor-grip { + overflow: hidden; + width: 10px; + height: 10px; + cursor: pointer; + position: absolute; + bottom: 0; + right: 0; + z-index: 3; +} +.sceditor-maximize { + position: fixed; + top: 0; + left: 0; + height: 100%!important; + width: 100%!important; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +html.sceditor-maximize, body.sceditor-maximize { + height: 100%; + width: 100%; + padding: 0; + margin: 0; + overflow: hidden; +} +.ie6.sceditor-maximize { + position: absolute; +} +.sceditor-maximize div.sceditor-grip { + display: none; +} +.sceditor-maximize div.sceditor-toolbar { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-dropdown { + position: absolute; + border: 1px solid #ccc; + background: #fff; + color: #333; + z-index: 6; + padding: 10px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); +} +div.sceditor-dropdown a, div.sceditor-dropdown a:link { + color: #333; +} +div.sceditor-dropdown form { + margin: 0; +} +div.sceditor-dropdown label { + display: block; + font-weight: bold; + color: #3c3c3c; + padding: 4px 0; +} +div.sceditor-dropdown input, div.sceditor-dropdown textarea { + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + outline: 0; + padding: 4px; + border: 1px solid #ccc; + border-top-color: #888; + margin: 0 0 .75em; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-dropdown textarea { + padding: 6px; +} +div.sceditor-dropdown input:focus, div.sceditor-dropdown textarea:focus { + border-color: #aaa; + border-top-color: #666; + -webkit-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); +} +div.sceditor-dropdown .button { + font-weight: bold; + color: #444; + padding: 6px 12px; + background: #ececec; + border: solid 1px #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + cursor: pointer; + margin: .3em 0 0; +} +div.sceditor-dropdown .button:hover { + background: #f3f3f3; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); +} +div.sceditor-font-picker, div.sceditor-fontsize-picker { + padding: 6px 0; +} +div.sceditor-insertemoticon, div.sceditor-color-picker { + padding: 0; +} +.sceditor-pastetext textarea { + border: 1px solid #bbb; + width: 20em; +} +.sceditor-insertemoticon img, .sceditor-more-emoticons img { + cursor: pointer; + margin: 2px; +} +.sceditor-more { + border-top: 1px solid #bbb; + display: block; + text-align: center; + cursor: pointer; + font-weight: bold; + padding: 6px 0; +} +.sceditor-more:hover { + background: #eee; +} +.sceditor-fontsize-option, .sceditor-font-option { + display: block; + padding: 4px 10px; + cursor: pointer; + text-decoration: none; + color: #222; +} +.sceditor-fontsize-option { + padding: 4px 13px; +} +.sceditor-fontsize-option:hover, .sceditor-font-option:hover { + background: #eee; +} +.sceditor-color-column { + float: left; +} +.sceditor-color-option { + display: block; + border: 1px solid #fff; + height: 10px; + width: 10px; + overflow: hidden; +} +.sceditor-color-option:hover { + border: 1px solid #333; +} +div.sceditor-toolbar { + overflow: hidden; + padding: 2px 2px 1px; + background: #f7f7f7; + border-bottom: 1px solid #c0c0c0; + line-height: 0; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-group { + display: inline-block; + background: #eee; + margin: 1px 5px 1px 0; + padding: 1px; + border-bottom: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.ie6 div.sceditor-group, .ie7 div.sceditor-group { + display: inline; + zoom: 1; +} +.sceditor-button { + float: left; + cursor: pointer; + padding: 3px 5px; + width: 16px; + height: 20px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + border: 1px solid #eee; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.ie6 .sceditor-button, .ie7 .sceditor-button { + float: none!important; + display: inline; + zoom: 1; +} +.ie6 .sceditor-button { + padding: 0; +} +.ie6 .sceditor-button div { + margin: 5px; +} +.ie7 .sceditor-button div { + margin: 5px 0; +} +.sceditor-button:hover, .sceditor-button:active, .sceditor-button.active { + background: #fff; + /*-webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.3), inset -1px 0 rgba(0, 0, 0, 0.3), inset 0 -1px 0 rgba(0, 0, 0, 0.2); + -moz-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.3), inset -1px 0 rgba(0, 0, 0, 0.3), inset 0 -1px 0 rgba(0, 0, 0, 0.2); + box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.3), inset -1px 0 rgba(0, 0, 0, 0.3), inset 0 -1px 0 rgba(0, 0, 0, 0.2)*/border: 1px solid #ddd; +} +.sceditor-button:active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.3), inset -1px 0 rgba(0, 0, 0, 0.3), inset 0 -1px 0 rgba(0, 0, 0, 0.2), inset 0 0 8px rgba(0, 0, 0, 0.3); + -moz-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.3), inset -1px 0 rgba(0, 0, 0, 0.3), inset 0 -1px 0 rgba(0, 0, 0, 0.2), inset 0 0 8px rgba(0, 0, 0, 0.3); + box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.3), inset -1px 0 rgba(0, 0, 0, 0.3), inset 0 -1px 0 rgba(0, 0, 0, 0.2), inset 0 0 8px rgba(0, 0, 0, 0.3); +} +.sceditor-button.disabled:hover { + background: inherit; + cursor: default; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.sceditor-button, .sceditor-button div { + display: block; +} +.sceditor-button div { + margin: 2px 0; + padding: 0; + overflow: hidden; + line-height: 0; + font-size: 0; + color: transparent; +} +.sceditor-button.disabled div { + filter: alpha(opacity=30); + opacity: .3; +} +.text .sceditor-button, .text .sceditor-button div, .sceditor-button.text, .sceditor-button.text div, .text-icon .sceditor-button, .text-icon .sceditor-button div, .sceditor-button.text-icon, .sceditor-button.text-icon div { + width: auto; + overflow: visible; + line-height: 16px; + font-size: 1em; + color: inherit; +} +.text .sceditor-button div, .sceditor-button.text div { + padding: 0 2px; + background: 0; +} +.text-icon .sceditor-button div, .sceditor-button.text-icon div { + padding: 0 2px 0 20px; +} +.rtl .sceditor-button { + float: right; +} +.rtl div.sceditor-grip { + right: auto; + left: 0; +} +.sceditor-container { + padding: 0 4px; + overflow: hidden; +} +.sceditor-container .sceditor-toolbar, .sceditor-container iframe, .sceditor-container textarea { + margin: 0 -4px; +} + +/* Additional buttons (for MyBB) */ +.sceditor-button-video div { + + background-image: url(video.png); + +} +.sceditor-button-php div { + + background-image: url(php.png); + +} \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_themes/office-toolbar.css b/Upload/jscripts/sceditor/editor_themes/office-toolbar.css new file mode 100644 index 0000000..74266db --- /dev/null +++ b/Upload/jscripts/sceditor/editor_themes/office-toolbar.css @@ -0,0 +1,705 @@ +/** + * Copyright (C) 2012, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + * Icons by Mark James (http://www.famfamfam.com/lab/icons/silk/) + * Licensed under the Creative Commons CC-BY license (http://creativecommons.org/licenses/by/3.0/) + */ +/*! SCEditor | (C) 2011-2013, Sam Clarke | sceditor.com/license */ +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +div.sceditor-grip, +.sceditor-button div { + background-image: url('famfamfam.png'); + background-repeat: no-repeat; + width: 16px; + height: 16px; +} +.sceditor-button-youtube div { + background-position: 0px 0px; +} +.sceditor-button-link div { + background-position: 0px -16px; +} +.sceditor-button-unlink div { + background-position: 0px -32px; +} +.sceditor-button-underline div { + background-position: 0px -48px; +} +.sceditor-button-time div { + background-position: 0px -64px; +} +.sceditor-button-table div { + background-position: 0px -80px; +} +.sceditor-button-superscript div { + background-position: 0px -96px; +} +.sceditor-button-subscript div { + background-position: 0px -112px; +} +.sceditor-button-strike div { + background-position: 0px -128px; +} +.sceditor-button-source div { + background-position: 0px -144px; +} +.sceditor-button-size div { + background-position: 0px -160px; +} +.sceditor-button-rtl div { + background-position: 0px -176px; +} +.sceditor-button-right div { + background-position: 0px -192px; +} +.sceditor-button-removeformat div { + background-position: 0px -208px; +} +.sceditor-button-quote div { + background-position: 0px -224px; +} +.sceditor-button-print div { + background-position: 0px -240px; +} +.sceditor-button-pastetext div { + background-position: 0px -256px; +} +.sceditor-button-paste div { + background-position: 0px -272px; +} +.sceditor-button-orderedlist div { + background-position: 0px -288px; +} +.sceditor-button-maximize div { + background-position: 0px -304px; +} +.sceditor-button-ltr div { + background-position: 0px -320px; +} +.sceditor-button-left div { + background-position: 0px -336px; +} +.sceditor-button-justify div { + background-position: 0px -352px; +} +.sceditor-button-italic div { + background-position: 0px -368px; +} +.sceditor-button-image div { + background-position: 0px -384px; +} +.sceditor-button-horizontalrule div { + background-position: 0px -400px; +} +.sceditor-button-format div { + background-position: 0px -416px; +} +.sceditor-button-font div { + background-position: 0px -432px; +} +.sceditor-button-emoticon div { + background-position: 0px -448px; +} +.sceditor-button-email div { + background-position: 0px -464px; +} +.sceditor-button-date div { + background-position: 0px -480px; +} +.sceditor-button-cut div { + background-position: 0px -496px; +} +.sceditor-button-copy div { + background-position: 0px -512px; +} +.sceditor-button-color div { + background-position: 0px -528px; +} +.sceditor-button-code div { + background-position: 0px -544px; +} +.sceditor-button-center div { + background-position: 0px -560px; +} +.sceditor-button-bulletlist div { + background-position: 0px -576px; +} +.sceditor-button-bold div { + background-position: 0px -592px; +} +div.sceditor-grip { + background-position: 0px -608px; + width: 10px; + height: 10px; +} +.rtl div.sceditor-grip { + background-position: 0px -618px; + width: 10px; + height: 10px; +} +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +/*--------------------------------------------------- + LESS Elements 0.7 + --------------------------------------------------- + A set of useful LESS mixins + More info at: http://lesselements.com + ---------------------------------------------------*/ +.sceditor-container { + position: relative; + background: #fff; + border: 1px solid #d9d9d9; + font-size: 13px; + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + color: #222; + line-height: 1; + font-weight: bold; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 100% !important; +} +.sceditor-container, +.sceditor-container div, +div.sceditor-dropdown, +div.sceditor-dropdown div { + padding: 0; + margin: 0; + z-index: 3; +} +.sceditor-container iframe, +.sceditor-container textarea { + line-height: 1; + border: 0; + outline: none; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 13px; + color: #111; + padding: 0; + margin: 5px; + resize: none; + background: #fff; + display: block; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 99% !important; +} +div.sceditor-resize-cover { + position: absolute; + top: 0; + left: 0; + background: #000; + width: 100%; + height: 100%; + z-index: 10; + opacity: 0.3; +} +.ie6 div.sceditor-resize-cover, +.ie7 div.sceditor-resize-cover, +.ie8 div.sceditor-resize-cover { + background: #efefef; +} +.sceditor-container.ie6 { + overflow: hidden; +} +div.sceditor-grip { + overflow: hidden; + width: 10px; + height: 10px; + cursor: pointer; + position: absolute; + bottom: 0; + right: 0; + z-index: 3; +} +.sceditor-maximize { + position: fixed; + top: 0; + left: 0; + height: 100% !important; + width: 100% !important; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + z-index: 2000; +} +html.sceditor-maximize, +body.sceditor-maximize { + height: 100%; + width: 100%; + padding: 0; + margin: 0; + overflow: hidden; +} +.ie6.sceditor-maximize { + position: absolute; +} +.sceditor-maximize div.sceditor-grip { + display: none; +} +.sceditor-maximize div.sceditor-toolbar { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +/** + * Dropdown styleing + */ +div.sceditor-dropdown { + position: absolute; + border: 1px solid #ccc; + background: #fff; + color: #333; + z-index: 4000; + padding: 10px; + line-height: 1; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); +} +div.sceditor-dropdown a, +div.sceditor-dropdown a:link { + color: #333; +} +div.sceditor-dropdown form { + margin: 0; +} +div.sceditor-dropdown label { + display: block; + font-weight: bold; + color: #3c3c3c; + padding: 4px 0; +} +div.sceditor-dropdown input, +div.sceditor-dropdown textarea { + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + outline: 0; + padding: 4px; + border: 1px solid #ccc; + border-top-color: #888; + margin: 0 0 .75em; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-dropdown textarea { + padding: 6px; +} +div.sceditor-dropdown input:focus, +div.sceditor-dropdown textarea:focus { + border-color: #aaa; + border-top-color: #666; + -webkit-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); +} +div.sceditor-dropdown .button { + font-weight: bold; + color: #444; + padding: 6px 12px; + background: #ececec; + border: solid 1px #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + cursor: pointer; + margin: .3em 0 0; +} +div.sceditor-dropdown .button:hover { + background: #f3f3f3; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); +} +div.sceditor-font-picker, +div.sceditor-fontsize-picker, +div.sceditor-format { + padding: 6px 0; +} +div.sceditor-emoticons, +div.sceditor-more-emoticons, +div.sceditor-color-picker { + padding: 0; +} +.sceditor-pastetext textarea { + border: 1px solid #bbb; + width: 20em; +} +.sceditor-emoticons img, +.sceditor-more-emoticons img { + padding: 0; + cursor: pointer; + margin: 2px; +} +.sceditor-more { + border-top: 1px solid #bbb; + display: block; + text-align: center; + cursor: pointer; + font-weight: bold; + padding: 6px 0; +} +.sceditor-dropdown a:hover { + background: #eee; +} +.sceditor-fontsize-option, +.sceditor-font-option, +.sceditor-format a { + display: block; + padding: 7px 10px; + cursor: pointer; + text-decoration: none; + color: #222; +} +.sceditor-fontsize-option { + padding: 7px 13px; +} +.sceditor-color-column { + float: left; +} +.sceditor-color-option { + display: block; + border: 1px solid #fff; + height: 10px; + width: 10px; + overflow: hidden; +} +.sceditor-color-option:hover { + border: 1px solid #333; +} +/** + * Toolbar styleing + */ +div.sceditor-toolbar { + overflow: hidden; + padding: 3px 5px 2px; + background: #f7f7f7; + border-bottom: 1px solid #c0c0c0; + line-height: 0; + text-align: left; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-group { + display: inline-block; + background: #ddd; + margin: 1px 5px 1px 0; + padding: 1px; + border-bottom: 1px solid #aaa; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.ie6 div.sceditor-group, +.ie7 div.sceditor-group { + display: inline; + zoom: 1; +} +.sceditor-button { + float: left; + cursor: pointer; + padding: 3px 5px; + width: 16px; + height: 20px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + /* Needed for Safari 5? */ + + text-indent: -9999px; +} +.ie .sceditor-button { + text-indent: 0; +} +.ie6 .sceditor-button, +.ie7 .sceditor-button { + float: none !important; + display: inline; + zoom: 1; +} +.ie6 .sceditor-button { + padding: 0; +} +.ie6 .sceditor-button div { + margin: 5px; +} +.ie7 .sceditor-button div { + margin: 5px 0; +} +.sceditor-button:hover, +.sceditor-button:active, +.sceditor-button.active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); +} +.sceditor-button:active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); +} +.sceditor-button.disabled:hover { + background: inherit; + cursor: default; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.sceditor-button, +.sceditor-button div { + display: block; +} +.sceditor-button div { + margin: 2px 0; + padding: 0; + overflow: hidden; + line-height: 0; + font-size: 0; + color: transparent; +} +.sceditor-button.disabled div { + filter: alpha(opacity=30); + opacity: 0.3; +} +.text .sceditor-button, +.text .sceditor-button div, +.sceditor-button.text, +.sceditor-button.text div, +.text-icon .sceditor-button, +.text-icon .sceditor-button div, +.sceditor-button.text-icon, +.sceditor-button.text-icon div { + width: auto; + overflow: visible; + line-height: 16px; + font-size: 1em; + color: inherit; + text-indent: 0; +} +.text .sceditor-button div, +.sceditor-button.text div { + padding: 0 2px; + background: none; +} +.text-icon .sceditor-button div, +.sceditor-button.text-icon div { + padding: 0 2px 0 20px; +} +.rtl div.sceditor-toolbar { + text-align: right; +} +.rtl .sceditor-button { + float: right; +} +.rtl div.sceditor-grip { + right: auto; + left: 0; +} +.sceditor-container { + border: 1px solid #8db2e3; +} +.sceditor-container textarea { + font-family: Consolas, "Bitstream Vera Sans Mono", "Andale Mono", Monaco, "DejaVu Sans Mono", "Lucida Console", monospace; +} +div.sceditor-toolbar { + border-bottom: 1px solid #95a9c3; + background: #dee8f5; + background: -moz-linear-gradient(top, #dee8f5 0%, #c7d8ed 29%, #ccdcee 61%, #c0d8ef 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #dee8f5), color-stop(29%, #c7d8ed), color-stop(61%, #ccdcee), color-stop(100%, #c0d8ef)); + background: -webkit-linear-gradient(top, #dee8f5 0%, #c7d8ed 29%, #ccdcee 61%, #c0d8ef 100%); + background: -o-linear-gradient(top, #dee8f5 0%, #c7d8ed 29%, #ccdcee 61%, #c0d8ef 100%); + background: -ms-linear-gradient(top, #dee8f5 0%, #c7d8ed 29%, #ccdcee 61%, #c0d8ef 100%); + background: linear-gradient(to bottom, #dee8f5 0%, #c7d8ed 29%, #ccdcee 61%, #c0d8ef 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#dee8f5', endColorstr='#c0d8ef', GradientType=0); +} +.ie9 div.sceditor-toolbar { + filter: none; + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2RlZThmNSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjI5JSIgc3RvcC1jb2xvcj0iI2M3ZDhlZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjYxJSIgc3RvcC1jb2xvcj0iI2NjZGNlZSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNjMGQ4ZWYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); +} +div.sceditor-group { + border: 1px solid #7596bf; + background: transparent; + padding: 0; + background: #cadcf0; + background: -moz-linear-gradient(top, #cadcf0 24%, #bcd0e9 38%, #d0e1f7 99%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(24%, #cadcf0), color-stop(38%, #bcd0e9), color-stop(99%, #d0e1f7)); + background: -webkit-linear-gradient(top, #cadcf0 24%, #bcd0e9 38%, #d0e1f7 99%); + background: -o-linear-gradient(top, #cadcf0 24%, #bcd0e9 38%, #d0e1f7 99%); + background: -ms-linear-gradient(top, #cadcf0 24%, #bcd0e9 38%, #d0e1f7 99%); + background: linear-gradient(to bottom, #cadcf0 24%, #bcd0e9 38%, #d0e1f7 99%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#cadcf0', endColorstr='#d0e1f7', GradientType=0); +} +.ie9 div.sceditor-group { + filter: none; + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIyNCUiIHN0b3AtY29sb3I9IiNjYWRjZjAiIHN0b3Atb3BhY2l0eT0iMSIvPgogICAgPHN0b3Agb2Zmc2V0PSIzOCUiIHN0b3AtY29sb3I9IiNiY2QwZTkiIHN0b3Atb3BhY2l0eT0iMSIvPgogICAgPHN0b3Agb2Zmc2V0PSI5OSUiIHN0b3AtY29sb3I9IiNkMGUxZjciIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); +} +.sceditor-button { + height: 16px; + padding: 3px 4px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-shadow: inset 0 1px #d5e3f1, inset 0 -1px #e3edfb, inset 1px 0 #cddcef, inset -1px 0 #b8ceea; + -moz-box-shadow: inset 0 1px #d5e3f1, inset 0 -1px #e3edfb, inset 1px 0 #cddcef, inset -1px 0 #b8ceea; + box-shadow: inset 0 1px #d5e3f1, inset 0 -1px #e3edfb, inset 1px 0 #cddcef, inset -1px 0 #b8ceea; +} +.sceditor-button:first-child { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.sceditor-button:last-child { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.sceditor-button div { + margin: 0; +} +.ie9 .sceditor-button { + filter: none !important; +} +.sceditor-button.active { + background: #fbdbb5; + background: -moz-linear-gradient(top, #fbdbb5 11%, #feb456 29%, #fdeb9f 99%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(11%, #fbdbb5), color-stop(29%, #feb456), color-stop(99%, #fdeb9f)); + background: -webkit-linear-gradient(top, #fbdbb5 11%, #feb456 29%, #fdeb9f 99%); + background: -o-linear-gradient(top, #fbdbb5 11%, #feb456 29%, #fdeb9f 99%); + background: -ms-linear-gradient(top, #fbdbb5 11%, #feb456 29%, #fdeb9f 99%); + background: linear-gradient(top, #fbdbb5 11%, #feb456 29%, #fdeb9f 99%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbdbb5', endColorstr='#fdeb9f', GradientType=0); + -webkit-box-shadow: inset 0 1px #ebd1b4, inset 0 -1px #ffe47f, inset -1px 0 #b8ceea; + -moz-box-shadow: inset 0 1px #ebd1b4, inset 0 -1px #ffe47f, inset -1px 0 #b8ceea; + box-shadow: inset 0 1px #ebd1b4, inset 0 -1px #ffe47f, inset -1px 0 #b8ceea; +} +.ie9 .sceditor-button.active { + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIxMSUiIHN0b3AtY29sb3I9IiNmYmRiYjUiIHN0b3Atb3BhY2l0eT0iMSIvPgogICAgPHN0b3Agb2Zmc2V0PSIyOSUiIHN0b3AtY29sb3I9IiNmZWI0NTYiIHN0b3Atb3BhY2l0eT0iMSIvPgogICAgPHN0b3Agb2Zmc2V0PSI5OSUiIHN0b3AtY29sb3I9IiNmZGZkOWYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); +} +.sceditor-button:hover { + background: #fef7d5; + background: -moz-linear-gradient(top, #fef7d5 0%, #fae5a9 42%, #ffd048 42%, #ffe59f 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fef7d5), color-stop(42%, #fae5a9), color-stop(42%, #ffd048), color-stop(100%, #ffe59f)); + background: -webkit-linear-gradient(top, #fef7d5 0%, #fae5a9 42%, #ffd048 42%, #ffe59f 100%); + background: -o-linear-gradient(top, #fef7d5 0%, #fae5a9 42%, #ffd048 42%, #ffe59f 100%); + background: -ms-linear-gradient(top, #fef7d5 0%, #fae5a9 42%, #ffd048 42%, #ffe59f 100%); + background: linear-gradient(to bottom, #fef7d5 0%, #fae5a9 42%, #ffd048 42%, #ffe59f 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fef7d5', endColorstr='#ffe59f', GradientType=0); + -webkit-box-shadow: inset 0 1px #fffbe8, inset -1px 0 #ffefc4, inset 0 -1px #fff9cc; + -moz-box-shadow: inset 0 1px #fffbe8, inset -1px 0 #ffefc4, inset 0 -1px #fff9cc; + box-shadow: inset 0 1px #fffbe8, inset -1px 0 #ffefc4, inset 0 -1px #fff9cc; +} +.ie9 .sceditor-button:hover { + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZlZjdkNSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjQyJSIgc3RvcC1jb2xvcj0iI2ZhZTVhOSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjQyJSIgc3RvcC1jb2xvcj0iI2ZmZDA0OCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmU1OWYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); +} +.sceditor-button:active { + background: #e7a66d; + background: -moz-linear-gradient(top, #e7a66d 0%, #fcb16d 1%, #ff8d05 42%, #ffc450 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #e7a66d), color-stop(1%, #fcb16d), color-stop(42%, #ff8d05), color-stop(100%, #ffc450)); + background: -webkit-linear-gradient(top, #e7a66d 0%, #fcb16d 1%, #ff8d05 42%, #ffc450 100%); + background: -o-linear-gradient(top, #e7a66d 0%, #fcb16d 1%, #ff8d05 42%, #ffc450 100%); + background: -ms-linear-gradient(top, #e7a66d 0%, #fcb16d 1%, #ff8d05 42%, #ffc450 100%); + background: linear-gradient(to bottom, #e7a66d 0%, #fcb16d 1%, #ff8d05 42%, #ffc450 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e7a66d', endColorstr='#ffc450', GradientType=0); + -webkit-box-shadow: inset 0 1px 1px #7b6645, inset 0 -1px #d19c33; + -moz-box-shadow: inset 0 1px 1px #7b6645, inset 0 -1px #d19c33; + box-shadow: inset 0 1px 1px #7b6645, inset 0 -1px #d19c33; +} +.ie9 .sceditor-button:active { + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2U3YTY2ZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjElIiBzdG9wLWNvbG9yPSIjZmNiMTZkIiBzdG9wLW9wYWNpdHk9IjEiLz4KICAgIDxzdG9wIG9mZnNldD0iNDIlIiBzdG9wLWNvbG9yPSIjZmY4ZDA1IiBzdG9wLW9wYWNpdHk9IjEiLz4KICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2ZmYzQ1MCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgPC9saW5lYXJHcmFkaWVudD4KICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSJ1cmwoI2dyYWQtdWNnZy1nZW5lcmF0ZWQpIiAvPgo8L3N2Zz4=); +} +.sceditor-button.active:hover { + background: #dba368; + background: -moz-linear-gradient(top, #dba368 0%, #ffbd79 4%, #fea335 34%, #ffc64c 66%, #fee069 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #dba368), color-stop(4%, #ffbd79), color-stop(34%, #fea335), color-stop(66%, #ffc64c), color-stop(100%, #fee069)); + background: -webkit-linear-gradient(top, #dba368 0%, #ffbd79 4%, #fea335 34%, #ffc64c 66%, #fee069 100%); + background: -o-linear-gradient(top, #dba368 0%, #ffbd79 4%, #fea335 34%, #ffc64c 66%, #fee069 100%); + background: -ms-linear-gradient(top, #dba368 0%, #ffbd79 4%, #fea335 34%, #ffc64c 66%, #fee069 100%); + background: linear-gradient(to bottom, #dba368 0%, #ffbd79 4%, #fea335 34%, #ffc64c 66%, #fee069 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#dba368', endColorstr='#fee069', GradientType=0); + -webkit-box-shadow: inset 0 1px 1px #9e8255, inset 0 -1px #fcce6b; + -moz-box-shadow: inset 0 1px 1px #9e8255, inset 0 -1px #fcce6b; + box-shadow: inset 0 1px 1px #9e8255, inset 0 -1px #fcce6b; +} +.ie9 .sceditor-button.active:hover { + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2RiYTM2OCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjQlIiBzdG9wLWNvbG9yPSIjZmZiZDc5IiBzdG9wLW9wYWNpdHk9IjEiLz4KICAgIDxzdG9wIG9mZnNldD0iMzQlIiBzdG9wLWNvbG9yPSIjZmVhMzM1IiBzdG9wLW9wYWNpdHk9IjEiLz4KICAgIDxzdG9wIG9mZnNldD0iNjYlIiBzdG9wLWNvbG9yPSIjZmZjNjRjIiBzdG9wLW9wYWNpdHk9IjEiLz4KICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2ZlZTA2OSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgPC9saW5lYXJHcmFkaWVudD4KICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSJ1cmwoI2dyYWQtdWNnZy1nZW5lcmF0ZWQpIiAvPgo8L3N2Zz4=); +} + +/* Additional buttons (for MyBB) */ +.sceditor-button-video div { + + background-image: url(video.png); + +} +.sceditor-button-php div { + + background-image: url(php.png); + +} \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_themes/office.css b/Upload/jscripts/sceditor/editor_themes/office.css new file mode 100644 index 0000000..fcefc02 --- /dev/null +++ b/Upload/jscripts/sceditor/editor_themes/office.css @@ -0,0 +1,734 @@ +/** + * Copyright (C) 2012, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + * Icons by Mark James (http://www.famfamfam.com/lab/icons/silk/) + * Licensed under the Creative Commons CC-BY license (http://creativecommons.org/licenses/by/3.0/) + */ +/** + * Copyright (C) 2012, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + * Icons by Mark James (http://www.famfamfam.com/lab/icons/silk/) + * Licensed under the Creative Commons CC-BY license (http://creativecommons.org/licenses/by/3.0/) + */ +/*! SCEditor | (C) 2011-2013, Sam Clarke | sceditor.com/license */ +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +div.sceditor-grip, +.sceditor-button div { + background-image: url('famfamfam.png'); + background-repeat: no-repeat; + width: 16px; + height: 16px; +} +.sceditor-button-youtube div { + background-position: 0px 0px; +} +.sceditor-button-link div { + background-position: 0px -16px; +} +.sceditor-button-unlink div { + background-position: 0px -32px; +} +.sceditor-button-underline div { + background-position: 0px -48px; +} +.sceditor-button-time div { + background-position: 0px -64px; +} +.sceditor-button-table div { + background-position: 0px -80px; +} +.sceditor-button-superscript div { + background-position: 0px -96px; +} +.sceditor-button-subscript div { + background-position: 0px -112px; +} +.sceditor-button-strike div { + background-position: 0px -128px; +} +.sceditor-button-source div { + background-position: 0px -144px; +} +.sceditor-button-size div { + background-position: 0px -160px; +} +.sceditor-button-rtl div { + background-position: 0px -176px; +} +.sceditor-button-right div { + background-position: 0px -192px; +} +.sceditor-button-removeformat div { + background-position: 0px -208px; +} +.sceditor-button-quote div { + background-position: 0px -224px; +} +.sceditor-button-print div { + background-position: 0px -240px; +} +.sceditor-button-pastetext div { + background-position: 0px -256px; +} +.sceditor-button-paste div { + background-position: 0px -272px; +} +.sceditor-button-orderedlist div { + background-position: 0px -288px; +} +.sceditor-button-maximize div { + background-position: 0px -304px; +} +.sceditor-button-ltr div { + background-position: 0px -320px; +} +.sceditor-button-left div { + background-position: 0px -336px; +} +.sceditor-button-justify div { + background-position: 0px -352px; +} +.sceditor-button-italic div { + background-position: 0px -368px; +} +.sceditor-button-image div { + background-position: 0px -384px; +} +.sceditor-button-horizontalrule div { + background-position: 0px -400px; +} +.sceditor-button-format div { + background-position: 0px -416px; +} +.sceditor-button-font div { + background-position: 0px -432px; +} +.sceditor-button-emoticon div { + background-position: 0px -448px; +} +.sceditor-button-email div { + background-position: 0px -464px; +} +.sceditor-button-date div { + background-position: 0px -480px; +} +.sceditor-button-cut div { + background-position: 0px -496px; +} +.sceditor-button-copy div { + background-position: 0px -512px; +} +.sceditor-button-color div { + background-position: 0px -528px; +} +.sceditor-button-code div { + background-position: 0px -544px; +} +.sceditor-button-center div { + background-position: 0px -560px; +} +.sceditor-button-bulletlist div { + background-position: 0px -576px; +} +.sceditor-button-bold div { + background-position: 0px -592px; +} +div.sceditor-grip { + background-position: 0px -608px; + width: 10px; + height: 10px; +} +.rtl div.sceditor-grip { + background-position: 0px -618px; + width: 10px; + height: 10px; +} +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +/*--------------------------------------------------- + LESS Elements 0.7 + --------------------------------------------------- + A set of useful LESS mixins + More info at: http://lesselements.com + ---------------------------------------------------*/ +.sceditor-container { + position: relative; + background: #fff; + border: 1px solid #d9d9d9; + font-size: 13px; + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + color: #222; + line-height: 1; + font-weight: bold; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 100% !important; +} +.sceditor-container, +.sceditor-container div, +div.sceditor-dropdown, +div.sceditor-dropdown div { + padding: 0; + margin: 0; + z-index: 3; +} +.sceditor-container iframe, +.sceditor-container textarea { + line-height: 1; + border: 0; + outline: none; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 13px; + color: #111; + padding: 0; + margin: 5px; + resize: none; + background: #fff; + display: block; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 90% !important; +} +div.sceditor-resize-cover { + position: absolute; + top: 0; + left: 0; + background: #000; + width: 100%; + height: 100%; + z-index: 10; + opacity: 0.3; +} +.ie6 div.sceditor-resize-cover, +.ie7 div.sceditor-resize-cover, +.ie8 div.sceditor-resize-cover { + background: #efefef; +} +.sceditor-container.ie6 { + overflow: hidden; +} +div.sceditor-grip { + overflow: hidden; + width: 10px; + height: 10px; + cursor: pointer; + position: absolute; + bottom: 0; + right: 0; + z-index: 3; +} +.sceditor-maximize { + position: fixed; + top: 0; + left: 0; + height: 100% !important; + width: 100% !important; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + z-index: 2000; +} +html.sceditor-maximize, +body.sceditor-maximize { + height: 100%; + width: 100%; + padding: 0; + margin: 0; + overflow: hidden; +} +.ie6.sceditor-maximize { + position: absolute; +} +.sceditor-maximize div.sceditor-grip { + display: none; +} +.sceditor-maximize div.sceditor-toolbar { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +/** + * Dropdown styleing + */ +div.sceditor-dropdown { + position: absolute; + border: 1px solid #ccc; + background: #fff; + color: #333; + z-index: 4000; + padding: 10px; + line-height: 1; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); +} +div.sceditor-dropdown a, +div.sceditor-dropdown a:link { + color: #333; +} +div.sceditor-dropdown form { + margin: 0; +} +div.sceditor-dropdown label { + display: block; + font-weight: bold; + color: #3c3c3c; + padding: 4px 0; +} +div.sceditor-dropdown input, +div.sceditor-dropdown textarea { + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + outline: 0; + padding: 4px; + border: 1px solid #ccc; + border-top-color: #888; + margin: 0 0 .75em; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-dropdown textarea { + padding: 6px; +} +div.sceditor-dropdown input:focus, +div.sceditor-dropdown textarea:focus { + border-color: #aaa; + border-top-color: #666; + -webkit-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); +} +div.sceditor-dropdown .button { + font-weight: bold; + color: #444; + padding: 6px 12px; + background: #ececec; + border: solid 1px #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + cursor: pointer; + margin: .3em 0 0; +} +div.sceditor-dropdown .button:hover { + background: #f3f3f3; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); +} +div.sceditor-font-picker, +div.sceditor-fontsize-picker, +div.sceditor-format { + padding: 6px 0; +} +div.sceditor-emoticons, +div.sceditor-more-emoticons, +div.sceditor-color-picker { + padding: 0; +} +.sceditor-pastetext textarea { + border: 1px solid #bbb; + width: 20em; +} +.sceditor-emoticons img, +.sceditor-more-emoticons img { + padding: 0; + cursor: pointer; + margin: 2px; +} +.sceditor-more { + border-top: 1px solid #bbb; + display: block; + text-align: center; + cursor: pointer; + font-weight: bold; + padding: 6px 0; +} +.sceditor-dropdown a:hover { + background: #eee; +} +.sceditor-fontsize-option, +.sceditor-font-option, +.sceditor-format a { + display: block; + padding: 7px 10px; + cursor: pointer; + text-decoration: none; + color: #222; +} +.sceditor-fontsize-option { + padding: 7px 13px; +} +.sceditor-color-column { + float: left; +} +.sceditor-color-option { + display: block; + border: 1px solid #fff; + height: 10px; + width: 10px; + overflow: hidden; +} +.sceditor-color-option:hover { + border: 1px solid #333; +} +/** + * Toolbar styleing + */ +div.sceditor-toolbar { + overflow: hidden; + padding: 3px 5px 2px; + background: #f7f7f7; + border-bottom: 1px solid #c0c0c0; + line-height: 0; + text-align: left; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-group { + display: inline-block; + background: #ddd; + margin: 1px 5px 1px 0; + padding: 1px; + border-bottom: 1px solid #aaa; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.ie6 div.sceditor-group, +.ie7 div.sceditor-group { + display: inline; + zoom: 1; +} +.sceditor-button { + float: left; + cursor: pointer; + padding: 3px 5px; + width: 16px; + height: 20px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + /* Needed for Safari 5? */ + + text-indent: -9999px; +} +.ie .sceditor-button { + text-indent: 0; +} +.ie6 .sceditor-button, +.ie7 .sceditor-button { + float: none !important; + display: inline; + zoom: 1; +} +.ie6 .sceditor-button { + padding: 0; +} +.ie6 .sceditor-button div { + margin: 5px; +} +.ie7 .sceditor-button div { + margin: 5px 0; +} +.sceditor-button:hover, +.sceditor-button:active, +.sceditor-button.active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); +} +.sceditor-button:active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); +} +.sceditor-button.disabled:hover { + background: inherit; + cursor: default; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.sceditor-button, +.sceditor-button div { + display: block; +} +.sceditor-button div { + margin: 2px 0; + padding: 0; + overflow: hidden; + line-height: 0; + font-size: 0; + color: transparent; +} +.sceditor-button.disabled div { + filter: alpha(opacity=30); + opacity: 0.3; +} +.text .sceditor-button, +.text .sceditor-button div, +.sceditor-button.text, +.sceditor-button.text div, +.text-icon .sceditor-button, +.text-icon .sceditor-button div, +.sceditor-button.text-icon, +.sceditor-button.text-icon div { + width: auto; + overflow: visible; + line-height: 16px; + font-size: 1em; + color: inherit; + text-indent: 0; +} +.text .sceditor-button div, +.sceditor-button.text div { + padding: 0 2px; + background: none; +} +.text-icon .sceditor-button div, +.sceditor-button.text-icon div { + padding: 0 2px 0 20px; +} +.rtl div.sceditor-toolbar { + text-align: right; +} +.rtl .sceditor-button { + float: right; +} +.rtl div.sceditor-grip { + right: auto; + left: 0; +} +.sceditor-container { + border: 1px solid #8db2e3; +} +.sceditor-container textarea { + font-family: Consolas, "Bitstream Vera Sans Mono", "Andale Mono", Monaco, "DejaVu Sans Mono", "Lucida Console", monospace; +} +div.sceditor-toolbar { + border-bottom: 1px solid #95a9c3; + background: #dee8f5; + background: -moz-linear-gradient(top, #dee8f5 0%, #c7d8ed 29%, #ccdcee 61%, #c0d8ef 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #dee8f5), color-stop(29%, #c7d8ed), color-stop(61%, #ccdcee), color-stop(100%, #c0d8ef)); + background: -webkit-linear-gradient(top, #dee8f5 0%, #c7d8ed 29%, #ccdcee 61%, #c0d8ef 100%); + background: -o-linear-gradient(top, #dee8f5 0%, #c7d8ed 29%, #ccdcee 61%, #c0d8ef 100%); + background: -ms-linear-gradient(top, #dee8f5 0%, #c7d8ed 29%, #ccdcee 61%, #c0d8ef 100%); + background: linear-gradient(to bottom, #dee8f5 0%, #c7d8ed 29%, #ccdcee 61%, #c0d8ef 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#dee8f5', endColorstr='#c0d8ef', GradientType=0); +} +.ie9 div.sceditor-toolbar { + filter: none; + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2RlZThmNSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjI5JSIgc3RvcC1jb2xvcj0iI2M3ZDhlZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjYxJSIgc3RvcC1jb2xvcj0iI2NjZGNlZSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNjMGQ4ZWYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); +} +div.sceditor-group { + border: 1px solid #7596bf; + background: transparent; + padding: 0; + background: #cadcf0; + background: -moz-linear-gradient(top, #cadcf0 24%, #bcd0e9 38%, #d0e1f7 99%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(24%, #cadcf0), color-stop(38%, #bcd0e9), color-stop(99%, #d0e1f7)); + background: -webkit-linear-gradient(top, #cadcf0 24%, #bcd0e9 38%, #d0e1f7 99%); + background: -o-linear-gradient(top, #cadcf0 24%, #bcd0e9 38%, #d0e1f7 99%); + background: -ms-linear-gradient(top, #cadcf0 24%, #bcd0e9 38%, #d0e1f7 99%); + background: linear-gradient(to bottom, #cadcf0 24%, #bcd0e9 38%, #d0e1f7 99%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#cadcf0', endColorstr='#d0e1f7', GradientType=0); +} +.ie9 div.sceditor-group { + filter: none; + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIyNCUiIHN0b3AtY29sb3I9IiNjYWRjZjAiIHN0b3Atb3BhY2l0eT0iMSIvPgogICAgPHN0b3Agb2Zmc2V0PSIzOCUiIHN0b3AtY29sb3I9IiNiY2QwZTkiIHN0b3Atb3BhY2l0eT0iMSIvPgogICAgPHN0b3Agb2Zmc2V0PSI5OSUiIHN0b3AtY29sb3I9IiNkMGUxZjciIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); +} +.sceditor-button { + height: 16px; + padding: 3px 4px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-shadow: inset 0 1px #d5e3f1, inset 0 -1px #e3edfb, inset 1px 0 #cddcef, inset -1px 0 #b8ceea; + -moz-box-shadow: inset 0 1px #d5e3f1, inset 0 -1px #e3edfb, inset 1px 0 #cddcef, inset -1px 0 #b8ceea; + box-shadow: inset 0 1px #d5e3f1, inset 0 -1px #e3edfb, inset 1px 0 #cddcef, inset -1px 0 #b8ceea; +} +.sceditor-button:first-child { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.sceditor-button:last-child { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.sceditor-button div { + margin: 0; +} +.ie9 .sceditor-button { + filter: none !important; +} +.sceditor-button.active { + background: #fbdbb5; + background: -moz-linear-gradient(top, #fbdbb5 11%, #feb456 29%, #fdeb9f 99%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(11%, #fbdbb5), color-stop(29%, #feb456), color-stop(99%, #fdeb9f)); + background: -webkit-linear-gradient(top, #fbdbb5 11%, #feb456 29%, #fdeb9f 99%); + background: -o-linear-gradient(top, #fbdbb5 11%, #feb456 29%, #fdeb9f 99%); + background: -ms-linear-gradient(top, #fbdbb5 11%, #feb456 29%, #fdeb9f 99%); + background: linear-gradient(top, #fbdbb5 11%, #feb456 29%, #fdeb9f 99%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbdbb5', endColorstr='#fdeb9f', GradientType=0); + -webkit-box-shadow: inset 0 1px #ebd1b4, inset 0 -1px #ffe47f, inset -1px 0 #b8ceea; + -moz-box-shadow: inset 0 1px #ebd1b4, inset 0 -1px #ffe47f, inset -1px 0 #b8ceea; + box-shadow: inset 0 1px #ebd1b4, inset 0 -1px #ffe47f, inset -1px 0 #b8ceea; +} +.ie9 .sceditor-button.active { + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIxMSUiIHN0b3AtY29sb3I9IiNmYmRiYjUiIHN0b3Atb3BhY2l0eT0iMSIvPgogICAgPHN0b3Agb2Zmc2V0PSIyOSUiIHN0b3AtY29sb3I9IiNmZWI0NTYiIHN0b3Atb3BhY2l0eT0iMSIvPgogICAgPHN0b3Agb2Zmc2V0PSI5OSUiIHN0b3AtY29sb3I9IiNmZGZkOWYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); +} +.sceditor-button:hover { + background: #fef7d5; + background: -moz-linear-gradient(top, #fef7d5 0%, #fae5a9 42%, #ffd048 42%, #ffe59f 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fef7d5), color-stop(42%, #fae5a9), color-stop(42%, #ffd048), color-stop(100%, #ffe59f)); + background: -webkit-linear-gradient(top, #fef7d5 0%, #fae5a9 42%, #ffd048 42%, #ffe59f 100%); + background: -o-linear-gradient(top, #fef7d5 0%, #fae5a9 42%, #ffd048 42%, #ffe59f 100%); + background: -ms-linear-gradient(top, #fef7d5 0%, #fae5a9 42%, #ffd048 42%, #ffe59f 100%); + background: linear-gradient(to bottom, #fef7d5 0%, #fae5a9 42%, #ffd048 42%, #ffe59f 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fef7d5', endColorstr='#ffe59f', GradientType=0); + -webkit-box-shadow: inset 0 1px #fffbe8, inset -1px 0 #ffefc4, inset 0 -1px #fff9cc; + -moz-box-shadow: inset 0 1px #fffbe8, inset -1px 0 #ffefc4, inset 0 -1px #fff9cc; + box-shadow: inset 0 1px #fffbe8, inset -1px 0 #ffefc4, inset 0 -1px #fff9cc; +} +.ie9 .sceditor-button:hover { + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZlZjdkNSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjQyJSIgc3RvcC1jb2xvcj0iI2ZhZTVhOSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjQyJSIgc3RvcC1jb2xvcj0iI2ZmZDA0OCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmU1OWYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); +} +.sceditor-button:active { + background: #e7a66d; + background: -moz-linear-gradient(top, #e7a66d 0%, #fcb16d 1%, #ff8d05 42%, #ffc450 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #e7a66d), color-stop(1%, #fcb16d), color-stop(42%, #ff8d05), color-stop(100%, #ffc450)); + background: -webkit-linear-gradient(top, #e7a66d 0%, #fcb16d 1%, #ff8d05 42%, #ffc450 100%); + background: -o-linear-gradient(top, #e7a66d 0%, #fcb16d 1%, #ff8d05 42%, #ffc450 100%); + background: -ms-linear-gradient(top, #e7a66d 0%, #fcb16d 1%, #ff8d05 42%, #ffc450 100%); + background: linear-gradient(to bottom, #e7a66d 0%, #fcb16d 1%, #ff8d05 42%, #ffc450 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e7a66d', endColorstr='#ffc450', GradientType=0); + -webkit-box-shadow: inset 0 1px 1px #7b6645, inset 0 -1px #d19c33; + -moz-box-shadow: inset 0 1px 1px #7b6645, inset 0 -1px #d19c33; + box-shadow: inset 0 1px 1px #7b6645, inset 0 -1px #d19c33; +} +.ie9 .sceditor-button:active { + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2U3YTY2ZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjElIiBzdG9wLWNvbG9yPSIjZmNiMTZkIiBzdG9wLW9wYWNpdHk9IjEiLz4KICAgIDxzdG9wIG9mZnNldD0iNDIlIiBzdG9wLWNvbG9yPSIjZmY4ZDA1IiBzdG9wLW9wYWNpdHk9IjEiLz4KICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2ZmYzQ1MCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgPC9saW5lYXJHcmFkaWVudD4KICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSJ1cmwoI2dyYWQtdWNnZy1nZW5lcmF0ZWQpIiAvPgo8L3N2Zz4=); +} +.sceditor-button.active:hover { + background: #dba368; + background: -moz-linear-gradient(top, #dba368 0%, #ffbd79 4%, #fea335 34%, #ffc64c 66%, #fee069 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #dba368), color-stop(4%, #ffbd79), color-stop(34%, #fea335), color-stop(66%, #ffc64c), color-stop(100%, #fee069)); + background: -webkit-linear-gradient(top, #dba368 0%, #ffbd79 4%, #fea335 34%, #ffc64c 66%, #fee069 100%); + background: -o-linear-gradient(top, #dba368 0%, #ffbd79 4%, #fea335 34%, #ffc64c 66%, #fee069 100%); + background: -ms-linear-gradient(top, #dba368 0%, #ffbd79 4%, #fea335 34%, #ffc64c 66%, #fee069 100%); + background: linear-gradient(to bottom, #dba368 0%, #ffbd79 4%, #fea335 34%, #ffc64c 66%, #fee069 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#dba368', endColorstr='#fee069', GradientType=0); + -webkit-box-shadow: inset 0 1px 1px #9e8255, inset 0 -1px #fcce6b; + -moz-box-shadow: inset 0 1px 1px #9e8255, inset 0 -1px #fcce6b; + box-shadow: inset 0 1px 1px #9e8255, inset 0 -1px #fcce6b; +} +.ie9 .sceditor-button.active:hover { + background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2RiYTM2OCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjQlIiBzdG9wLWNvbG9yPSIjZmZiZDc5IiBzdG9wLW9wYWNpdHk9IjEiLz4KICAgIDxzdG9wIG9mZnNldD0iMzQlIiBzdG9wLWNvbG9yPSIjZmVhMzM1IiBzdG9wLW9wYWNpdHk9IjEiLz4KICAgIDxzdG9wIG9mZnNldD0iNjYlIiBzdG9wLWNvbG9yPSIjZmZjNjRjIiBzdG9wLW9wYWNpdHk9IjEiLz4KICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2ZlZTA2OSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgPC9saW5lYXJHcmFkaWVudD4KICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSJ1cmwoI2dyYWQtdWNnZy1nZW5lcmF0ZWQpIiAvPgo8L3N2Zz4=); +} +.sceditor-container { + background: #a3c2ea; + background: -moz-linear-gradient(top, #a3c2ea 0%, #6d92c1 39%, #577fb3 64%, #6591cc 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #a3c2ea), color-stop(39%, #6d92c1), color-stop(64%, #577fb3), color-stop(100%, #6591cc)); + background: -webkit-linear-gradient(top, #a3c2ea 0%, #6d92c1 39%, #577fb3 64%, #6591cc 100%); + background: -o-linear-gradient(top, #a3c2ea 0%, #6d92c1 39%, #577fb3 64%, #6591cc 100%); + background: -ms-linear-gradient(top, #a3c2ea 0%, #6d92c1 39%, #577fb3 64%, #6591cc 100%); + background: linear-gradient(top, #a3c2ea 0%, #6d92c1 39%, #577fb3 64%, #6591cc 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#a3c2ea', endColorstr='#6591cc', GradientType=0); +} +.sceditor-container iframe, +.sceditor-container textarea { + border: 1px solid #646464; + background: #fff; + margin: 7px 4.5%; + padding: 20px; + -webkit-box-shadow: 1px 1px 5px #293a52; + -moz-box-shadow: 1px 1px 5px #293a52; + box-shadow: 1px 1px 5px #293a52; +} + +/* Additional buttons (for MyBB) */ +.sceditor-button-video div { + + background-image: url(video.png); + +} +.sceditor-button-php div { + + background-image: url(php.png); + +} \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_themes/php.png b/Upload/jscripts/sceditor/editor_themes/php.png new file mode 100644 index 0000000000000000000000000000000000000000..7868a25945cd5e5cb7daaca9591927511ca65c0f GIT binary patch literal 538 zcmV+#0_FXQP)vYep8SaFV10Q$h+;hIUPX_=v5b}%>Tm<(&j1&5;I!55C)oN0s(P%ZB zP3Q#ahfpXKWF@S?jm4U#fv)QovMhrriclyNs6-G12#3R##4PSZ0VY(dRWJ;Lwuq{# zAW0Gwi$yA^R4RZ!;W+L`f&%x{=D^VK#BBWL4Ys{;*!A7Q;!=dN<&D8*GzGaF4`hV4 zDbY0{NrMX>ZqF=0((gR5-zL$kC*b)!fwu{Euru|XrG<$^n#@)7i_>rCmRxnDq>$Y%gJaCkRd|tE*a2x05Pe!I^e13o69#&RQZ36s0 zB=O|K2Yi(jsMqThn}9t?f5E-)L^naZ+db$&%M$!bCdm=jv7?t_lB?3&%Ltq(>ESw? c;MI421LCcoDG!2@;{X5v07*qoM6N<$f`UZt7XSbN literal 0 HcmV?d00001 diff --git a/Upload/jscripts/sceditor/editor_themes/square.css b/Upload/jscripts/sceditor/editor_themes/square.css new file mode 100644 index 0000000..37baec1 --- /dev/null +++ b/Upload/jscripts/sceditor/editor_themes/square.css @@ -0,0 +1,668 @@ +/** + * Square theme + * + * This theme is best suited to short toolbars that + * don't span multiple lines. + * + * Copyright (C) 2012, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + * Icons by Mark James (http://www.famfamfam.com/lab/icons/silk/) + * Licensed under the Creative Commons CC-BY license (http://creativecommons.org/licenses/by/3.0/) + */ +/*! SCEditor | (C) 2011-2013, Sam Clarke | sceditor.com/license */ +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +div.sceditor-grip, +.sceditor-button div { + background-image: url('famfamfam.png'); + background-repeat: no-repeat; + width: 16px; + height: 16px; +} +.sceditor-button-youtube div { + background-position: 0px 0px; +} +.sceditor-button-link div { + background-position: 0px -16px; +} +.sceditor-button-unlink div { + background-position: 0px -32px; +} +.sceditor-button-underline div { + background-position: 0px -48px; +} +.sceditor-button-time div { + background-position: 0px -64px; +} +.sceditor-button-table div { + background-position: 0px -80px; +} +.sceditor-button-superscript div { + background-position: 0px -96px; +} +.sceditor-button-subscript div { + background-position: 0px -112px; +} +.sceditor-button-strike div { + background-position: 0px -128px; +} +.sceditor-button-source div { + background-position: 0px -144px; +} +.sceditor-button-size div { + background-position: 0px -160px; +} +.sceditor-button-rtl div { + background-position: 0px -176px; +} +.sceditor-button-right div { + background-position: 0px -192px; +} +.sceditor-button-removeformat div { + background-position: 0px -208px; +} +.sceditor-button-quote div { + background-position: 0px -224px; +} +.sceditor-button-print div { + background-position: 0px -240px; +} +.sceditor-button-pastetext div { + background-position: 0px -256px; +} +.sceditor-button-paste div { + background-position: 0px -272px; +} +.sceditor-button-orderedlist div { + background-position: 0px -288px; +} +.sceditor-button-maximize div { + background-position: 0px -304px; +} +.sceditor-button-ltr div { + background-position: 0px -320px; +} +.sceditor-button-left div { + background-position: 0px -336px; +} +.sceditor-button-justify div { + background-position: 0px -352px; +} +.sceditor-button-italic div { + background-position: 0px -368px; +} +.sceditor-button-image div { + background-position: 0px -384px; +} +.sceditor-button-horizontalrule div { + background-position: 0px -400px; +} +.sceditor-button-format div { + background-position: 0px -416px; +} +.sceditor-button-font div { + background-position: 0px -432px; +} +.sceditor-button-emoticon div { + background-position: 0px -448px; +} +.sceditor-button-email div { + background-position: 0px -464px; +} +.sceditor-button-date div { + background-position: 0px -480px; +} +.sceditor-button-cut div { + background-position: 0px -496px; +} +.sceditor-button-copy div { + background-position: 0px -512px; +} +.sceditor-button-color div { + background-position: 0px -528px; +} +.sceditor-button-code div { + background-position: 0px -544px; +} +.sceditor-button-center div { + background-position: 0px -560px; +} +.sceditor-button-bulletlist div { + background-position: 0px -576px; +} +.sceditor-button-bold div { + background-position: 0px -592px; +} +div.sceditor-grip { + background-position: 0px -608px; + width: 10px; + height: 10px; +} +.rtl div.sceditor-grip { + background-position: 0px -618px; + width: 10px; + height: 10px; +} +/** + * SCEditor + * http://www.ssceditor.com/ + * + * Copyright (C) 2011-12, Sam Clarke (samclarke.com) + * + * SCEditor is licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + */ +/*--------------------------------------------------- + LESS Elements 0.7 + --------------------------------------------------- + A set of useful LESS mixins + More info at: http://lesselements.com + ---------------------------------------------------*/ +.sceditor-container { + position: relative; + background: #fff; + border: 1px solid #d9d9d9; + font-size: 13px; + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + color: #222; + line-height: 1; + font-weight: bold; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 100% !important; +} +.sceditor-container, +.sceditor-container div, +div.sceditor-dropdown, +div.sceditor-dropdown div { + padding: 0; + margin: 0; + z-index: 3; +} +.sceditor-container iframe, +.sceditor-container textarea { + line-height: 1; + border: 0; + outline: none; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 13px; + color: #111; + padding: 0; + margin: 5px; + resize: none; + background: #fff; + display: block; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 99% !important; +} +div.sceditor-resize-cover { + position: absolute; + top: 0; + left: 0; + background: #000; + width: 100%; + height: 100%; + z-index: 10; + opacity: 0.3; +} +.ie6 div.sceditor-resize-cover, +.ie7 div.sceditor-resize-cover, +.ie8 div.sceditor-resize-cover { + background: #efefef; +} +.sceditor-container.ie6 { + overflow: hidden; +} +div.sceditor-grip { + overflow: hidden; + width: 10px; + height: 10px; + cursor: pointer; + position: absolute; + bottom: 0; + right: 0; + z-index: 3; +} +.sceditor-maximize { + position: fixed; + top: 0; + left: 0; + height: 100% !important; + width: 100% !important; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + z-index: 2000; +} +html.sceditor-maximize, +body.sceditor-maximize { + height: 100%; + width: 100%; + padding: 0; + margin: 0; + overflow: hidden; +} +.ie6.sceditor-maximize { + position: absolute; +} +.sceditor-maximize div.sceditor-grip { + display: none; +} +.sceditor-maximize div.sceditor-toolbar { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +/** + * Dropdown styleing + */ +div.sceditor-dropdown { + position: absolute; + border: 1px solid #ccc; + background: #fff; + color: #333; + z-index: 4000; + padding: 10px; + line-height: 1; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); + box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2); +} +div.sceditor-dropdown a, +div.sceditor-dropdown a:link { + color: #333; +} +div.sceditor-dropdown form { + margin: 0; +} +div.sceditor-dropdown label { + display: block; + font-weight: bold; + color: #3c3c3c; + padding: 4px 0; +} +div.sceditor-dropdown input, +div.sceditor-dropdown textarea { + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + outline: 0; + padding: 4px; + border: 1px solid #ccc; + border-top-color: #888; + margin: 0 0 .75em; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-dropdown textarea { + padding: 6px; +} +div.sceditor-dropdown input:focus, +div.sceditor-dropdown textarea:focus { + border-color: #aaa; + border-top-color: #666; + -webkit-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1); +} +div.sceditor-dropdown .button { + font-weight: bold; + color: #444; + padding: 6px 12px; + background: #ececec; + border: solid 1px #ccc; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + cursor: pointer; + margin: .3em 0 0; +} +div.sceditor-dropdown .button:hover { + background: #f3f3f3; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); +} +div.sceditor-font-picker, +div.sceditor-fontsize-picker, +div.sceditor-format { + padding: 6px 0; +} +div.sceditor-emoticons, +div.sceditor-more-emoticons, +div.sceditor-color-picker { + padding: 0; +} +.sceditor-pastetext textarea { + border: 1px solid #bbb; + width: 20em; +} +.sceditor-emoticons img, +.sceditor-more-emoticons img { + padding: 0; + cursor: pointer; + margin: 2px; +} +.sceditor-more { + border-top: 1px solid #bbb; + display: block; + text-align: center; + cursor: pointer; + font-weight: bold; + padding: 6px 0; +} +.sceditor-dropdown a:hover { + background: #eee; +} +.sceditor-fontsize-option, +.sceditor-font-option, +.sceditor-format a { + display: block; + padding: 7px 10px; + cursor: pointer; + text-decoration: none; + color: #222; +} +.sceditor-fontsize-option { + padding: 7px 13px; +} +.sceditor-color-column { + float: left; +} +.sceditor-color-option { + display: block; + border: 1px solid #fff; + height: 10px; + width: 10px; + overflow: hidden; +} +.sceditor-color-option:hover { + border: 1px solid #333; +} +/** + * Toolbar styleing + */ +div.sceditor-toolbar { + overflow: hidden; + padding: 3px 5px 2px; + background: #f7f7f7; + border-bottom: 1px solid #c0c0c0; + line-height: 0; + text-align: left; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-group { + display: inline-block; + background: #ddd; + margin: 1px 5px 1px 0; + padding: 1px; + border-bottom: 1px solid #aaa; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.ie6 div.sceditor-group, +.ie7 div.sceditor-group { + display: inline; + zoom: 1; +} +.sceditor-button { + float: left; + cursor: pointer; + padding: 3px 5px; + width: 16px; + height: 20px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + /* Needed for Safari 5? */ + + text-indent: -9999px; +} +.ie .sceditor-button { + text-indent: 0; +} +.ie6 .sceditor-button, +.ie7 .sceditor-button { + float: none !important; + display: inline; + zoom: 1; +} +.ie6 .sceditor-button { + padding: 0; +} +.ie6 .sceditor-button div { + margin: 5px; +} +.ie7 .sceditor-button div { + margin: 5px 0; +} +.sceditor-button:hover, +.sceditor-button:active, +.sceditor-button.active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2); +} +.sceditor-button:active { + background: #fff; + -webkit-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + -moz-box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); + box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3); +} +.sceditor-button.disabled:hover { + background: inherit; + cursor: default; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.sceditor-button, +.sceditor-button div { + display: block; +} +.sceditor-button div { + margin: 2px 0; + padding: 0; + overflow: hidden; + line-height: 0; + font-size: 0; + color: transparent; +} +.sceditor-button.disabled div { + filter: alpha(opacity=30); + opacity: 0.3; +} +.text .sceditor-button, +.text .sceditor-button div, +.sceditor-button.text, +.sceditor-button.text div, +.text-icon .sceditor-button, +.text-icon .sceditor-button div, +.sceditor-button.text-icon, +.sceditor-button.text-icon div { + width: auto; + overflow: visible; + line-height: 16px; + font-size: 1em; + color: inherit; + text-indent: 0; +} +.text .sceditor-button div, +.sceditor-button.text div { + padding: 0 2px; + background: none; +} +.text-icon .sceditor-button div, +.sceditor-button.text-icon div { + padding: 0 2px 0 20px; +} +.rtl div.sceditor-toolbar { + text-align: right; +} +.rtl .sceditor-button { + float: right; +} +.rtl div.sceditor-grip { + right: auto; + left: 0; +} +.sceditor-container { + border: 1px solid #d6d6d6; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.sceditor-container textarea { + font-family: Consolas, "Bitstream Vera Sans Mono", "Andale Mono", Monaco, "DejaVu Sans Mono", "Lucida Console", monospace; + background: #2e3436; + color: #fff; + margin: 0; + padding: 5px; +} +div.sceditor-toolbar, +div.sceditor-group { + background: #f2f2f2; + background: -moz-linear-gradient(top, #f2f2f2 0%, #dddddd 89%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f2f2f2), color-stop(89%, #dddddd)); + background: -webkit-linear-gradient(top, #f2f2f2 0%, #dddddd 89%); + background: -o-linear-gradient(top, #f2f2f2 0%, #dddddd 89%); + background: -ms-linear-gradient(top, #f2f2f2 0%, #dddddd 89%); + background: linear-gradient(to bottom, #f2f2f2 0%, #dddddd 89%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f2f2f2', endColorstr='#dddddd', GradientType=0); +} +div.sceditor-toolbar { + padding: 0; + border-bottom: 1px solid #bbb; + -moz-background-size: 100% 32px; + -o-background-size: 100% 32px; + -webkit-background-size: 100% 32px; + background-size: 100% 32px; +} +div.sceditor-group { + margin: 0; + padding: 2px 4px; + border: 0; + border-right: 1px solid #ccc; + border-left: 1px solid #eaeaea; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +div.sceditor-group:last-child { + border-right: 0; +} +div.sceditor-group:first-child { + border-left: 0; +} +.sceditor-button { + height: 16px; + padding: 5px; + margin: 1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} +.sceditor-button div { + margin: 0; +} +.sceditor-button.active, +.sceditor-button:hover, +.sceditor-button:active, +.sceditor-button.active:hover { + margin: 0; + box-shadow: none; +} +.sceditor-button.active { + background: #f4f4f4; + border: 1px solid #ccc; +} +.sceditor-button:hover { + background: #fefefe; + border: 1px solid #ddd; +} +.sceditor-button.disabled:hover { + margin: 1px; + border: 0; +} +.sceditor-button:active { + background: #eee; + border: 1px solid #ccc; +} +.sceditor-button.active:hover { + background: #f8f8f8; + border: 1px solid #ddd; +} + +/* Additional buttons (for MyBB) */ +.sceditor-button-video div { + + background-image: url(video.png); + +} +.sceditor-button-php div { + + background-image: url(php.png); + +} \ No newline at end of file diff --git a/Upload/jscripts/sceditor/editor_themes/video.png b/Upload/jscripts/sceditor/editor_themes/video.png new file mode 100644 index 0000000000000000000000000000000000000000..cb7a33d3523c8266a5d9ce194257f5e484d4b042 GIT binary patch literal 632 zcmV-;0*C#HP)$uyZXsJJX+w~>6H=grLn{@fu_iSbd5g~(GBgvt zVUm^qX8kLZ85IDPTCLU*9E8GxP*+EHRV?6;W%(nSMV~Z)C)Xzo;LcL|aAkUMrn+#Y zyPytp9elvakbMVz2#GU78{7MBY!No&E!bi$7~M4*kmo)h5R1iPiOjM$--SKdhLCJw zE8fILxB>HC9Zw7r9%^GWP-d>k2Rw|*PPhfLM}g5UL$fMcQJ#0ps z*xmmOe@4OTZWYG&r!-KV`+OiMNm7~2Pa2J8L|Ix|8md&P?!Qonxj{Ym&m28y?HzgpW$yEVNH&|L)rOEB!xH<3)xhO{=>0<)XfQXz2jYyTkop0W ze}vb;5zNu68K%&87|8NVcb^8DbDs|+)9Ez*o{lwe1-(ow5O1$ip22*soHNUUo*GF2Sh@ZFkKMpihSS>;U3}sf>8G^-TezPDdVpY Stm*>*0000',toolbarButton:'

    ',emoticon:'{key}',fontOpt:'{font}',sizeOpt:'{size}',pastetext:'
    ',table:'
    ',image:'
    ',email:'
    ',link:'
    ',youtubeMenu:'
    ',youtube:''},e=function(b,c,e){var f=d[b];return a.each(c,function(a,b){f=f.replace(new RegExp("\\{"+a+"\\}","g"),b)}),e&&(f=a(f)),f};a.sceditor=function(d,f){var g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,$,_,ab,bb,cb,db,eb,fb,gb,hb,ib,jb=a.sceditor.ie,kb=jb&&11>jb,lb=this,mb=d.get?d.get(0):d,nb=a(mb),ob=[],pb=[],qb=[],rb=[],sb={},tb=[];lb.commands=a.extend(!0,{},f.commands||a.sceditor.commands),lb.opts=f=a.extend({},a.sceditor.defaultOptions,f),A=function(){nb.data("sceditor",lb),a.each(f,function(b,c){a.isPlainObject(c)&&(f[b]=a.extend(!0,{},c))}),f.locale&&"en"!==f.locale&&G(),g=a('
    ').insertAfter(nb).css("z-index",f.zIndex),jb&&g.addClass("ie ie"+jb),y=!!nb.attr("required"),nb.removeAttr("required"),F(),M(),H(),E(),K(),I(),J(),a.sceditor.isWysiwygSupported||lb.toggleSourceMode(),Z();var d=function(){a(b).unbind("load",d),f.autofocus&&cb(),f.autoExpand&&lb.expandToContent(),X(),t.call("ready")};a(b).load(d),c.readyState&&"complete"===c.readyState&&d()},F=function(){var b=f.plugins;b=b?b.toString().split(","):[],t=new a.sceditor.PluginManager(lb),a.each(b,function(b,c){t.register(a.trim(c))})},G=function(){var b;q=a.sceditor.locale[f.locale],q||(b=f.locale.split("-"),q=a.sceditor.locale[b[0]]),q&&q.dateFormat&&(f.dateFormat=q.dateFormat)},E=function(){var c,d;m=a("").hide(),i=a(''),f.spellcheck||m.attr("spellcheck","false"),"https:"===b.location.protocol&&i.attr("src","javascript:false"),g.append(i).append(m),j=i[0],n=m[0],lb.dimensions(f.width||nb.width(),f.height||nb.height()),c=N(),c.open(),c.write(e("html",{spellcheck:f.spellcheck?"":'spellcheck="false"',charset:f.charset,style:f.style})),c.close(),l=a(c),k=a(c.body),lb.readOnly(!!f.readOnly),jb&&l.find("html").addClass("ie ie"+jb),(a.sceditor.ios||jb)&&(k.height("100%"),jb||k.bind("touchend",lb.focus)),r=new a.sceditor.rangeHelper(j.contentWindow),lb.val(nb.hide().val()),d=nb.attr("tabindex"),m.attr("tabindex",d),i.attr("tabindex",d)},I=function(){f.autoUpdate&&(k.bind("blur",lb.updateOriginal),m.bind("blur",lb.updateOriginal)),null===f.rtl&&(f.rtl="rtl"===m.css("direction")),lb.rtl(!!f.rtl),f.autoExpand&&l.bind("keyup",lb.expandToContent),f.resizeEnabled&&L(),g.attr("id",f.id),lb.emoticons(f.emoticonsEnabled)},J=function(){a(c).click(W),a(mb.form).bind("reset",T).submit(lb.updateOriginal),a(b).bind("resize orientationChanged",X),k.keypress(S).keydown(Q).keydown(R).keyup(_).bind("blur",hb).keyup(ib).bind("paste",O).bind(jb?"selectionchange":"keyup focus blur contextmenu mouseup touchend click",ab).bind("keydown keyup keypress focus blur contextmenu",V),f.emoticonsCompat&&b.getSelection&&k.keyup(eb),m.bind("blur",hb).keyup(ib).bind("keydown keyup keypress focus blur contextmenu",V).keydown(Q),l.mousedown(U).bind("blur",hb).bind(jb?"selectionchange":"focus blur contextmenu mouseup click",ab).bind("beforedeactivate keyup",D).keyup(_).focus(function(){p=null}),g.bind("selectionchanged",bb).bind("selectionchanged",Z).bind("selectionchanged valuechanged nodechanged",V)},H=function(){var b,c,d,i=lb.commands,j=(f.toolbarExclude||"").split(","),k=f.toolbar.split("|");h=a('
    '),a.each(k,function(f,g){b=a('
    '),a.each(g.split(","),function(f,g){!i[g]||a.inArray(g,j)>-1||(d=i[g].shortcut?" ("+i[g].shortcut+")":"",c=e("toolbarButton",{name:g,dispName:lb._(i[g].tooltip||g)+d},!0),c.data("sceditor-txtmode",!!i[g].txtExec),c.data("sceditor-wysiwygmode",!!i[g].exec),c.click(function(){var b=a(this);return b.hasClass("disabled")||C(b,i[g]),Z(),!1}),i[g].tooltip&&c.attr("title",lb._(i[g].tooltip)),i[g].exec||c.addClass("disabled"),i[g].shortcut&&(lb.addShortcut(i[g].shortcut,g),c.attr("title",c.attr("title")+d)),b.append(c))}),b[0].firstChild&&h.append(b)}),a(f.toolbarContainer||g).append(h)},K=function(){a.each(lb.commands,function(b,c){c.keyPress&&ob.push(c.keyPress),c.forceNewLineAfter&&a.isArray(c.forceNewLineAfter)&&(qb=a.merge(qb,c.forceNewLineAfter)),c.state?rb.push({name:b,state:c.state}):"string"==typeof c.exec&&rb.push({name:b,state:c.exec})}),_()},L=function(){var d,e,h,i,j,k,l=a('
    '),m=a('
    '),n=0,o=0,p=0,q=0,r=g.width(),s=g.height(),t=!1,u=lb.rtl();d=f.resizeMinHeight||s/1.5,e=f.resizeMaxHeight||2.5*s,h=f.resizeMinWidth||r/1.25,i=f.resizeMaxWidth||1.25*r,j=function(a){"touchmove"===a.type&&(a=b.event);var c=q+(a.pageY-o),j=u?p-(a.pageX-n):p+(a.pageX-n);i>0&&j>i&&(j=i),e>0&&c>e&&(c=e),(!f.resizeWidth||h>j||i>0&&j>i)&&(j=!1),(!f.resizeHeight||d>c||e>0&&c>e)&&(c=!1),(j||c)&&(lb.dimensions(j,c),7>jb&&g.height(c)),a.preventDefault()},k=function(b){t&&(t=!1,m.hide(),g.removeClass("resizing").height("auto"),a(c).unbind("touchmove mousemove",j),a(c).unbind("touchend mouseup",k),b.preventDefault())},g.append(l),g.append(m.hide()),l.bind("touchstart mousedown",function(d){"touchstart"===d.type&&(d=b.event),n=d.pageX,o=d.pageY,p=g.width(),q=g.height(),t=!0,g.addClass("resizing"),m.show(),a(c).bind("touchmove mousemove",j),a(c).bind("touchend mouseup",k),7>jb&&g.height(q),d.preventDefault()})},M=function(){var b,d=f.emoticons,e=f.emoticonsRoot;a.isPlainObject(d)&&f.emoticonsEnabled&&a.each(d,function(f,g){a.each(g,function(a,g){e&&(g={url:e+(g.url||g),tooltip:g.tooltip||a},d[f][a]=g),b=c.createElement("img"),b.src=g.url||g,pb.push(b)})})},cb=function(){var b,c,d,e=l[0],h=k[0],i=!!f.autofocusEnd;if(g.is(":visible")){if(lb.sourceMode())d=n.value.length,n.setSelectionRange?n.setSelectionRange(d,d):n.createTextRange&&(b=n.createTextRange(),b.moveEnd("character",d),b.moveStart("character",d),r.selectRange(b));else{if(a.sceditor.dom.removeWhiteSpace(h),i)for((c=h.lastChild)||k.append(c=e.createElement("div"));c.lastChild;)c=c.lastChild,/br/i.test(c.nodeName)&&c.previousSibling&&(c=c.previousSibling);else c=h.firstChild;e.createRange?(b=e.createRange(),/br/i.test(c.nodeName)?b.setStartBefore(c):b.selectNodeContents(c),b.collapse(!1)):(b=h.createTextRange(),b.moveToElementText(3!==c.nodeType?c:c.parentNode),b.collapse(!1)),r.selectRange(b),i&&(l.scrollTop(h.scrollHeight),k.scrollTop(h.scrollHeight))}lb.focus()}},lb.readOnly=function(a){return"boolean"!=typeof a?"readonly"===m.attr("readonly"):(k[0].contentEditable=!a,a?m.attr("readonly","readonly"):m.removeAttr("readonly"),Y(a),this)},lb.rtl=function(a){var b=a?"rtl":"ltr";return"boolean"!=typeof a?"rtl"===m.attr("dir"):(k.attr("dir",b),m.attr("dir",b),g.removeClass("rtl").removeClass("ltr").addClass(b),this)},Y=function(b){var c=lb.inSourceMode();h.find(".sceditor-button").removeClass("disabled").each(function(){var d=a(this);b===!0||c&&!d.data("sceditor-txtmode")?d.addClass("disabled"):c||d.data("sceditor-wysiwygmode")||d.addClass("disabled")})},lb.width=function(a,b){return a||0===a?(lb.dimensions(a,null,b),this):g.width()},lb.dimensions=function(b,d,e){var j=8>jb||c.documentMode<8?2:0;return b=b||0===b?b:!1,d=d||0===d?d:!1,b===!1&&d===!1?{width:lb.width(),height:lb.height()}:("undefined"==typeof i.data("outerWidthOffset")&&lb.updateStyleCache(),b!==!1&&(e!==!1&&(f.width=b),d===!1&&(d=g.height(),e=!1),g.width(b),b&&b.toString().indexOf("%")>-1&&(b=g.width()),i.width(b-i.data("outerWidthOffset")),m.width(b-m.data("outerWidthOffset")),a.sceditor.ios&&k&&k.width(b-i.data("outerWidthOffset")-(k.outerWidth(!0)-k.width()))),d!==!1&&(e!==!1&&(f.height=d),d&&d.toString().indexOf("%")>-1&&(d=g.height(d).height(),g.height("auto")),d-=f.toolbarContainer?0:h.outerHeight(!0),i.height(d-i.data("outerHeightOffset")),m.height(d-j-m.data("outerHeightOffset"))),this)},lb.updateStyleCache=function(){i.data("outerWidthOffset",i.outerWidth(!0)-i.width()),m.data("outerWidthOffset",m.outerWidth(!0)-m.width()),i.data("outerHeightOffset",i.outerHeight(!0)-i.height()),m.data("outerHeightOffset",m.outerHeight(!0)-m.height())},lb.height=function(a,b){return a||0===a?(lb.dimensions(null,a,b),this):g.height()},lb.maximize=function(b){return"undefined"==typeof b?g.is(".sceditor-maximize"):(b=!!b,7>jb&&a("html, body").toggleClass("sceditor-maximize",b),g.toggleClass("sceditor-maximize",b),lb.width(b?"100%":f.width,!1),lb.height(b?"100%":f.height,!1),this)},lb.expandToContent=function(a){var b=g.height(),c=k[0].scrollHeight||l[0].documentElement.scrollHeight,d=b-i.height(),e=f.resizeMaxHeight||2*(f.height||nb.height());c+=d,a!==!0&&c>e&&(c=e),c>b&&lb.height(c)},lb.destroy=function(){t&&(t.destroy(),r=null,p=null,t=null,a(c).unbind("click",W),a(b).unbind("resize orientationChanged",X),a(mb.form).unbind("reset",T).unbind("submit",lb.updateOriginal),k.unbind(),l.unbind().find("*").remove(),m.unbind().remove(),h.remove(),g.unbind().find("*").unbind().remove(),g.remove(),nb.removeData("sceditor").removeData("sceditorbbcode").show(),y&&nb.attr("required","required"))},lb.createDropDown=function(b,c,d,e){var g,h=o&&o.is(".sceditor-"+c);lb.closeDropDown(),h||(e!==!1&&a(d).find(":not(input,textarea)").filter(function(){return 1===this.nodeType}).attr("unselectable","on"),g={top:b.offset().top,left:b.offset().left,marginTop:b.outerHeight()},a.extend(g,f.dropDownCss),o=a('
    ').css(g).append(d).appendTo(a("body")).on("click focusin",function(a){a.stopPropagation()}))},W=function(a){3!==a.which&&lb.closeDropDown()},O=function(a){var b,d,e,g=k[0],h=l[0],i=0,j=c.createElement("div"),m=h.createDocumentFragment();if(f.disablePasting)return!1;if(f.enablePasteFiltering){if(r.saveRange(),c.body.appendChild(j),a&&a.clipboardData&&a.clipboardData.getData&&((b=a.clipboardData.getData("text/html"))||(b=a.clipboardData.getData("text/plain"))))return j.innerHTML=b,P(g,j),!1;for(e=k.scrollTop()||l.scrollTop();g.firstChild;)m.appendChild(g.firstChild);return d=function(a,b){if(a.childNodes.length>0||i>25){for(;a.firstChild;)b.appendChild(a.firstChild);for(;m.firstChild;)a.appendChild(m.firstChild);k.scrollTop(e),l.scrollTop(e),b.childNodes.length>0?P(a,b):r.restoreRange()}else i++,setTimeout(function(){d(a,b)},20)},d(g,j),lb.focus(),!0}},P=function(b,c){a.sceditor.dom.fixNesting(c);var d=c.innerHTML;t.hasHandler("toSource")&&(d=t.callOnlyFirst("toSource",d,a(c))),c.parentNode.removeChild(c),t.hasHandler("toWysiwyg")&&(d=t.callOnlyFirst("toWysiwyg",d,!0)),r.restoreRange(),lb.wysiwygEditorInsertHtml(d,null,!0)},lb.closeDropDown=function(a){o&&(o.unbind().remove(),o=null),a===!0&&lb.focus()},N=function(){return j.contentDocument?j.contentDocument:j.contentWindow&&j.contentWindow.document?j.contentWindow.document:j.document?j.document:null},lb.wysiwygEditorInsertHtml=function(b,c,d){var e,f,g,h=i.height();lb.focus(),(d||!a(v).is("code")&&0===a(v).parents("code").length)&&(r.insertHTML(b,c),r.saveRange(),B(k[0]),e=k.find("#sceditor-end-marker").show(),f=k.scrollTop()||l.scrollTop(),g=a.sceditor.dom.getOffset(e[0]).top+1.5*e.outerHeight(!0)-h,e.hide(),(g>f||f>g+h)&&(k.scrollTop(g),l.scrollTop(g)),gb(!1),r.restoreRange(),_())},lb.wysiwygEditorInsertText=function(b,c){lb.wysiwygEditorInsertHtml(a.sceditor.escapeEntities(b),a.sceditor.escapeEntities(c))},lb.insertText=function(a,b){return lb.inSourceMode()?lb.sourceEditorInsertText(a,b):lb.wysiwygEditorInsertText(a,b),this},lb.sourceEditorInsertText=function(a,b){var d,e,f,g,h;h=n.scrollTop,n.focus(),"undefined"!=typeof n.selectionStart?(e=n.selectionStart,f=n.selectionEnd,g=a.length,b&&(a+=n.value.substring(e,f)+b),n.value=n.value.substring(0,e)+a+n.value.substring(f,n.value.length),n.selectionStart=e+a.length-(b?b.length:0),n.selectionEnd=n.selectionStart):"undefined"!=typeof c.selection.createRange?(d=c.selection.createRange(),b&&(a+=d.text+b),d.text=a,b&&d.moveEnd("character",0-b.length),d.moveStart("character",d.End-d.Start),d.select()):n.value+=a+b,n.scrollTop=h,n.focus(),gb()},lb.getRangeHelper=function(){return r},lb.sourceEditorCaret=function(a){var b={};return"undefined"!=typeof n.selectionStart?a?(n.selectionStart=a.start,n.selectionEnd=a.end):(b.start=n.selectionStart,b.end=n.selectionEnd):(range=c.selection.createRange(),a?(range.moveStart("character",a.start),range.moveEnd("character",a.end),range.select()):(b.start=range.Start,b.end=range.End)),a?this:b},lb.val=function(a,b){return"string"==typeof a?(lb.inSourceMode()?lb.setSourceEditorValue(a):(b!==!1&&t.hasHandler("toWysiwyg")&&(a=t.callOnlyFirst("toWysiwyg",a)),lb.setWysiwygEditorValue(a)),this):lb.inSourceMode()?lb.getSourceEditorValue(!1):lb.getWysiwygEditorValue()},lb.insert=function(b,c,d,e,f){if(lb.inSourceMode())lb.sourceEditorInsertText(b,c);else{if(c){var g=lb.getRangeHelper().selectedHtml(),h=a("
    ").appendTo(a("body")).hide().html(g);d!==!1&&t.hasHandler("toSource")&&(g=t.callOnlyFirst("toSource",g,h)),h.remove(),b+=g+c}d!==!1&&t.hasHandler("toWysiwyg")&&(b=t.callOnlyFirst("toWysiwyg",b,!0)),d!==!1&&f===!0&&(b=b.replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&")),lb.wysiwygEditorInsertHtml(b)}return this},lb.getWysiwygEditorValue=function(b){var c,d,e=r.hasSelection();return e?r.saveRange():p&&p.getBookmark&&(d=p.getBookmark()),a.sceditor.dom.fixNesting(k[0]),c=k.html(),b!==!1&&t.hasHandler("toSource")&&(c=t.callOnlyFirst("toSource",c,k)),e?(r.restoreRange(),p=null):d&&(p.moveToBookmark(d),p=null),c},lb.getBody=function(){return k},lb.getContentAreaContainer=function(){return i},lb.getSourceEditorValue=function(a){var b=m.val();return a!==!1&&t.hasHandler("toWysiwyg")&&(b=t.callOnlyFirst("toWysiwyg",b)),b},lb.setWysiwygEditorValue=function(a){a||(a="

    "+(jb?"":"
    ")+"

    "),k[0].innerHTML=a,B(k[0]),_(),gb()},lb.setSourceEditorValue=function(a){m.val(a),gb()},lb.updateOriginal=function(){nb.val(lb.val())},B=function(b){if(f.emoticonsEnabled&&!a(b).parents("code").length){var c=b.ownerDocument,d=[],g=[],h=a.extend({},f.emoticons.more,f.emoticons.dropdown,f.emoticons.hidden);a.each(h,function(b){f.emoticonsCompat&&(g[b]=new RegExp("(>|^|\\s| | | | | )"+a.sceditor.regexEscape(b)+"(\\s|$|<| | | | | )")),d.push(b)}),function i(b){for(b=b.firstChild;null!=b;){var j,k,l,m,n,o,p,q=b.parentNode,r=b.nodeValue;if(3!==b.nodeType)a(b).is("code")||i(b);else if(r)for(n=d.length;n--;)k=d[n],p=f.emoticonsCompat?r.search(g[k]):r.indexOf(k),p>-1&&(o=b.nextSibling,l=h[k],j=r.substr(p).split(k),r=r.substr(0,p)+j.shift(),b.nodeValue=r,m=a.sceditor.dom.parseHTML(e("emoticon",{key:k,url:l.url||l,tooltip:l.tooltip||k}),c),q.insertBefore(m[0],o),q.insertBefore(c.createTextNode(j.join(k)),o));b=b.nextSibling}}(b),f.emoticonsCompat&&(tb=k.find("img[data-sceditor-emoticon]"))}},lb.inSourceMode=function(){return g.hasClass("sourceMode")},lb.sourceMode=function(a){return"boolean"!=typeof a?lb.inSourceMode():((lb.inSourceMode()&&!a||!lb.inSourceMode()&&a)&&lb.toggleSourceMode(),this)},lb.toggleSourceMode=function(){(a.sceditor.isWysiwygSupported||!lb.inSourceMode())&&(lb.blur(),lb.inSourceMode()?lb.setWysiwygEditorValue(lb.getSourceEditorValue()):lb.setSourceEditorValue(lb.getWysiwygEditorValue()),p=null,m.toggle(),i.toggle(),lb.inSourceMode()?g.removeClass("sourceMode").addClass("wysiwygMode"):g.removeClass("wysiwygMode").addClass("sourceMode"),Y(),Z())},$=function(){return n.focus(),null!=n.selectionStart?n.value.substring(n.selectionStart,n.selectionEnd):c.selection.createRange?c.selection.createRange().text:void 0},C=function(b,c){return lb.inSourceMode()?void(c.txtExec&&(a.isArray(c.txtExec)?lb.sourceEditorInsertText.apply(lb,c.txtExec):c.txtExec.call(lb,b,$()))):void(c.exec&&(a.isFunction(c.exec)?c.exec.call(lb,b):lb.execCommand(c.exec,c.hasOwnProperty("execParam")?c.execParam:null)))},D=function(){jb&&(p=r.selectedRange())},lb.execCommand=function(b,c){var d=!1,e=a(r.parentNode());if(lb.focus(),!e.is("code")&&0===e.parents("code").length){try{d=l[0].execCommand(b,!1,c)}catch(f){}!d&&lb.commands[b]&&lb.commands[b].errorMessage&&alert(lb._(lb.commands[b].errorMessage))}},ab=function(){var b=function(){r&&!r.compare(w)&&(w=r.cloneSelected(),g.trigger(a.Event("selectionchanged"))),x=!1};x||(x=!0,jb?b():setTimeout(b,100))},bb=function(){var b,c=r.parentNode();u!==c&&(b=u,u=c,v=r.getFirstBlockParent(c),g.trigger(a.Event("nodechanged",{oldNode:b,newNode:u})))},lb.currentNode=function(){return u},lb.currentBlockNode=function(){return v},Z=function(a){var b,c,d,e,f,g=l[0],i=rb.length,j=lb.sourceMode();if(lb.sourceMode()||lb.readOnly())h.find(".sceditor-button").removeClass("active");else for(f=a?a.newNode:r.parentNode(),d=r.getFirstBlockParent(f);i--;)if(b=0,c=rb[i],e=h.find(".sceditor-button-"+c.name),j&&!e.data("sceditor-txtmode"))e.addClass("disabled");else if(j||e.data("sceditor-wysiwygmode")){if("string"==typeof c.state)try{b=g.queryCommandEnabled(c.state)?0:-1,b>-1&&(b=g.queryCommandState(c.state)?1:0)}catch(k){}else b=c.state.call(lb,f,d);0>b?e.addClass("disabled"):e.removeClass("disabled"),b>0?e.addClass("active"):e.removeClass("active")}else e.addClass("disabled")},S=function(b){var c,d;if(!b.originalEvent.defaultPrevented){if(lb.closeDropDown(),c=a(u),13===b.which&&(c.is("code,blockquote,pre")||0!==c.parents("code,blockquote,pre").length))return p=null,lb.wysiwygEditorInsertHtml("
    ",null,!0),!1;if(!c.is("code")&&0===c.parents("code").length)for(d=ob.length;d--;)ob[d].call(lb,b,j,m)}},_=function(){var b,c,d;a.sceditor.dom.rTraverse(k[0],function(e){return b=e.nodeName.toLowerCase(),a.inArray(b,qb)>-1&&(c=!0),3===e.nodeType&&!/^\s*$/.test(e.nodeValue)||"br"===b||kb&&!e.firstChild&&!a.sceditor.dom.isInline(e,!1)?(c&&(d=k[0].ownerDocument.createElement("div"),d.className="sceditor-nlf",d.innerHTML=kb?"":"
    ",k[0].appendChild(d)),!1):void 0})},T=function(){lb.val(nb.val())},U=function(){lb.closeDropDown(),p=null},X=function(){var a=f.height,b=f.width;lb.maximize()?lb.dimensions("100%","100%",!1):(a&&a.toString().indexOf("%")>-1||b&&b.toString().indexOf("%")>-1)&&lb.dimensions(b,a)},lb._=function(){var a,b=arguments;return q&&q[b[0]]&&(b[0]=q[b[0]]),b[0].replace(/\{(\d+)\}/g,function(c,d){return b[d-0+1]!==a?b[d-0+1]:"{"+d+"}"})},V=function(b){var c,d=a.extend({},b);t.call(d.type+"Event",b,lb),delete d.type,c=a.Event((b.target===n?"scesrc":"scewys")+b.type,d),g.trigger(c,lb),c.isDefaultPrevented()&&b.preventDefault(),c.isImmediatePropagationStopped()&&c.stopImmediatePropagation(),c.isPropagationStopped()&&c.stopPropagation()},lb.bind=function(b,c,d,e){b=b.split(" ");for(var f=b.length;f--;)a.isFunction(c)&&(d||g.bind("scewys"+b[f],c),e||g.bind("scesrc"+b[f],c),"valuechanged"===b[f]&&(gb.hasHandler=!0));return this},lb.unbind=function(b,c,d,e){b=b.split(" ");for(var f=b.length;f--;)a.isFunction(c)&&(d||g.unbind("scewys"+b[f],c),e||g.unbind("scesrc"+b[f],c));return this},lb.blur=function(b,c,d){return a.isFunction(b)?lb.bind("blur",b,c,d):lb.sourceMode()?m.blur():(s||(s=a('').appendTo(g)),s.removeAttr("disabled").show().focus().blur().hide().attr("disabled","disabled")),this},lb.focus=function(b,c,d){return a.isFunction(b)?lb.bind("focus",b,c,d):lb.inSourceMode()?n.focus():(j.contentWindow.focus(),k[0].focus(),p&&(r.selectRange(p),p=null)),this},lb.keyDown=function(a,b,c){return lb.bind("keydown",a,b,c)},lb.keyPress=function(a,b,c){return lb.bind("keypress",a,b,c)},lb.keyUp=function(a,b,c){return lb.bind("keyup",a,b,c)},lb.nodeChanged=function(a){return lb.bind("nodechanged",a,!1,!0)},lb.selectionChanged=function(a){return lb.bind("selectionchanged",a,!1,!0)},lb.valueChanged=function(a,b,c){return lb.bind("valuechanged",a,b,c)},db=function(b){var c=0,d=String.fromCharCode(b.which);if(!a(v).is("code")&&!a(v).parents("code").length)return lb.emoticonsCache||(lb.emoticonsCache=[],a.each(a.extend({},f.emoticons.more,f.emoticons.dropdown,f.emoticons.hidden),function(a,b){lb.emoticonsCache[c++]=[a,e("emoticon",{key:a,url:b.url||b,tooltip:b.tooltip||a})]}),lb.emoticonsCache.sort(function(a,b){return a[0].length-b[0].length}),lb.longestEmoticonCode=lb.emoticonsCache[lb.emoticonsCache.length-1][0].length),lb.getRangeHelper().raplaceKeyword(lb.emoticonsCache,!0,!0,lb.longestEmoticonCode,f.emoticonsCompat,d)?(f.emoticonsCompat&&(tb=k.find("img[data-sceditor-emoticon]")),/^\s$/.test(d)&&f.emoticonsCompat):void 0},eb=function(){if(tb.length){var b,c,d,e,f,g,h=lb.currentBlockNode(),i=!1,j=/[^\s\xA0\u2002\u2003\u2009\u00a0]+/;tb=a.map(tb,function(k){return k&&k.parentNode?a.contains(h,k)?(b=k.previousSibling,c=k.nextSibling,f=b.nodeValue,null===f&&(f=b.innerText||""),b&&j.test(b.nodeValue.slice(-1))||c&&j.test((c.nodeValue||"")[0])?(d=k.parentNode,e=r.cloneSelected(),g=e.startContainer,f+=a(k).data("sceditor-emoticon"),g===c?i=f.length+e.startOffset:g===h&&h.childNodes[e.startOffset]===c?i=f.length:g===b&&(i=e.startOffset),c&&3===c.nodeType||(c=d.insertBefore(d.ownerDocument.createTextNode(""),c)),c.insertData(0,f),d.removeChild(b),d.removeChild(k),i!==!1&&(e.setStart(c,i),e.collapse(!0),r.selectRange(e)),null):k):k:null})}},lb.emoticons=function(b){return b||b===!1?(f.emoticonsEnabled=b,b?(k.keypress(db),lb.sourceMode()||(r.saveRange(),B(k[0]),tb=k.find("img[data-sceditor-emoticon]"),gb(!1),r.restoreRange())):(k.find("img[data-sceditor-emoticon]").replaceWith(function(){return a(this).data("sceditor-emoticon")}),tb=[],k.unbind("keypress",db),gb()),this):f.emoticonsEnabled},lb.css=function(b){return z||(z=a('',toolbarButton:'
    {dispName}
    ',emoticon:'{key}',fontOpt:'{font}',sizeOpt:'{size}',pastetext:'
    ',table:'
    ',image:'
    ',email:'
    ',link:'
    ',youtubeMenu:'
    ',youtube:''},e=function(b,c,e){var f=d[b];return a.each(c,function(a,b){f=f.replace(new RegExp("\\{"+a+"\\}","g"),b)}),e&&(f=a(f)),f};a.sceditor=function(d,f){var g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,$,_,ab,bb,cb,db,eb,fb,gb,hb,ib,jb=a.sceditor.ie,kb=jb&&11>jb,lb=this,mb=d.get?d.get(0):d,nb=a(mb),ob=[],pb=[],qb=[],rb=[],sb={},tb=[];lb.commands=a.extend(!0,{},f.commands||a.sceditor.commands),lb.opts=f=a.extend({},a.sceditor.defaultOptions,f),A=function(){nb.data("sceditor",lb),a.each(f,function(b,c){a.isPlainObject(c)&&(f[b]=a.extend(!0,{},c))}),f.locale&&"en"!==f.locale&&G(),g=a('
    ').insertAfter(nb).css("z-index",f.zIndex),jb&&g.addClass("ie ie"+jb),y=!!nb.attr("required"),nb.removeAttr("required"),F(),M(),H(),E(),K(),I(),J(),a.sceditor.isWysiwygSupported||lb.toggleSourceMode(),Z();var d=function(){a(b).unbind("load",d),f.autofocus&&cb(),f.autoExpand&&lb.expandToContent(),X(),t.call("ready")};a(b).load(d),c.readyState&&"complete"===c.readyState&&d()},F=function(){var b=f.plugins;b=b?b.toString().split(","):[],t=new a.sceditor.PluginManager(lb),a.each(b,function(b,c){t.register(a.trim(c))})},G=function(){var b;q=a.sceditor.locale[f.locale],q||(b=f.locale.split("-"),q=a.sceditor.locale[b[0]]),q&&q.dateFormat&&(f.dateFormat=q.dateFormat)},E=function(){var c,d;m=a("").hide(),i=a(''),f.spellcheck||m.attr("spellcheck","false"),"https:"===b.location.protocol&&i.attr("src","javascript:false"),g.append(i).append(m),j=i[0],n=m[0],lb.dimensions(f.width||nb.width(),f.height||nb.height()),c=N(),c.open(),c.write(e("html",{spellcheck:f.spellcheck?"":'spellcheck="false"',charset:f.charset,style:f.style})),c.close(),l=a(c),k=a(c.body),lb.readOnly(!!f.readOnly),jb&&l.find("html").addClass("ie ie"+jb),(a.sceditor.ios||jb)&&(k.height("100%"),jb||k.bind("touchend",lb.focus)),r=new a.sceditor.rangeHelper(j.contentWindow),lb.val(nb.hide().val()),d=nb.attr("tabindex"),m.attr("tabindex",d),i.attr("tabindex",d)},I=function(){f.autoUpdate&&(k.bind("blur",lb.updateOriginal),m.bind("blur",lb.updateOriginal)),null===f.rtl&&(f.rtl="rtl"===m.css("direction")),lb.rtl(!!f.rtl),f.autoExpand&&l.bind("keyup",lb.expandToContent),f.resizeEnabled&&L(),g.attr("id",f.id),lb.emoticons(f.emoticonsEnabled)},J=function(){a(c).click(W),a(mb.form).bind("reset",T).submit(lb.updateOriginal),a(b).bind("resize orientationChanged",X),k.keypress(S).keydown(Q).keydown(R).keyup(_).bind("blur",hb).keyup(ib).bind("paste",O).bind(jb?"selectionchange":"keyup focus blur contextmenu mouseup touchend click",ab).bind("keydown keyup keypress focus blur contextmenu",V),f.emoticonsCompat&&b.getSelection&&k.keyup(eb),m.bind("blur",hb).keyup(ib).bind("keydown keyup keypress focus blur contextmenu",V).keydown(Q),l.mousedown(U).bind("blur",hb).bind(jb?"selectionchange":"focus blur contextmenu mouseup click",ab).bind("beforedeactivate keyup",D).keyup(_).focus(function(){p=null}),g.bind("selectionchanged",bb).bind("selectionchanged",Z).bind("selectionchanged valuechanged nodechanged",V)},H=function(){var b,c,d,i=lb.commands,j=(f.toolbarExclude||"").split(","),k=f.toolbar.split("|");h=a('
    '),a.each(k,function(f,g){b=a('
    '),a.each(g.split(","),function(f,g){!i[g]||a.inArray(g,j)>-1||(d=i[g].shortcut?" ("+i[g].shortcut+")":"",c=e("toolbarButton",{name:g,dispName:lb._(i[g].tooltip||g)+d},!0),c.data("sceditor-txtmode",!!i[g].txtExec),c.data("sceditor-wysiwygmode",!!i[g].exec),c.click(function(){var b=a(this);return b.hasClass("disabled")||C(b,i[g]),Z(),!1}),i[g].tooltip&&c.attr("title",lb._(i[g].tooltip)),i[g].exec||c.addClass("disabled"),i[g].shortcut&&(lb.addShortcut(i[g].shortcut,g),c.attr("title",c.attr("title")+d)),b.append(c))}),b[0].firstChild&&h.append(b)}),a(f.toolbarContainer||g).append(h)},K=function(){a.each(lb.commands,function(b,c){c.keyPress&&ob.push(c.keyPress),c.forceNewLineAfter&&a.isArray(c.forceNewLineAfter)&&(qb=a.merge(qb,c.forceNewLineAfter)),c.state?rb.push({name:b,state:c.state}):"string"==typeof c.exec&&rb.push({name:b,state:c.exec})}),_()},L=function(){var d,e,h,i,j,k,l=a('
    '),m=a('
    '),n=0,o=0,p=0,q=0,r=g.width(),s=g.height(),t=!1,u=lb.rtl();d=f.resizeMinHeight||s/1.5,e=f.resizeMaxHeight||2.5*s,h=f.resizeMinWidth||r/1.25,i=f.resizeMaxWidth||1.25*r,j=function(a){"touchmove"===a.type&&(a=b.event);var c=q+(a.pageY-o),j=u?p-(a.pageX-n):p+(a.pageX-n);i>0&&j>i&&(j=i),e>0&&c>e&&(c=e),(!f.resizeWidth||h>j||i>0&&j>i)&&(j=!1),(!f.resizeHeight||d>c||e>0&&c>e)&&(c=!1),(j||c)&&(lb.dimensions(j,c),7>jb&&g.height(c)),a.preventDefault()},k=function(b){t&&(t=!1,m.hide(),g.removeClass("resizing").height("auto"),a(c).unbind("touchmove mousemove",j),a(c).unbind("touchend mouseup",k),b.preventDefault())},g.append(l),g.append(m.hide()),l.bind("touchstart mousedown",function(d){"touchstart"===d.type&&(d=b.event),n=d.pageX,o=d.pageY,p=g.width(),q=g.height(),t=!0,g.addClass("resizing"),m.show(),a(c).bind("touchmove mousemove",j),a(c).bind("touchend mouseup",k),7>jb&&g.height(q),d.preventDefault()})},M=function(){var b,d=f.emoticons,e=f.emoticonsRoot;a.isPlainObject(d)&&f.emoticonsEnabled&&a.each(d,function(f,g){a.each(g,function(a,g){e&&(g={url:e+(g.url||g),tooltip:g.tooltip||a},d[f][a]=g),b=c.createElement("img"),b.src=g.url||g,pb.push(b)})})},cb=function(){var b,c,d,e=l[0],h=k[0],i=!!f.autofocusEnd;if(g.is(":visible")){if(lb.sourceMode())d=n.value.length,n.setSelectionRange?n.setSelectionRange(d,d):n.createTextRange&&(b=n.createTextRange(),b.moveEnd("character",d),b.moveStart("character",d),r.selectRange(b));else{if(a.sceditor.dom.removeWhiteSpace(h),i)for((c=h.lastChild)||k.append(c=e.createElement("div"));c.lastChild;)c=c.lastChild,/br/i.test(c.nodeName)&&c.previousSibling&&(c=c.previousSibling);else c=h.firstChild;e.createRange?(b=e.createRange(),/br/i.test(c.nodeName)?b.setStartBefore(c):b.selectNodeContents(c),b.collapse(!1)):(b=h.createTextRange(),b.moveToElementText(3!==c.nodeType?c:c.parentNode),b.collapse(!1)),r.selectRange(b),i&&(l.scrollTop(h.scrollHeight),k.scrollTop(h.scrollHeight))}lb.focus()}},lb.readOnly=function(a){return"boolean"!=typeof a?"readonly"===m.attr("readonly"):(k[0].contentEditable=!a,a?m.attr("readonly","readonly"):m.removeAttr("readonly"),Y(a),this)},lb.rtl=function(a){var b=a?"rtl":"ltr";return"boolean"!=typeof a?"rtl"===m.attr("dir"):(k.attr("dir",b),m.attr("dir",b),g.removeClass("rtl").removeClass("ltr").addClass(b),this)},Y=function(b){var c=lb.inSourceMode();h.find(".sceditor-button").removeClass("disabled").each(function(){var d=a(this);b===!0||c&&!d.data("sceditor-txtmode")?d.addClass("disabled"):c||d.data("sceditor-wysiwygmode")||d.addClass("disabled")})},lb.width=function(a,b){return a||0===a?(lb.dimensions(a,null,b),this):g.width()},lb.dimensions=function(b,d,e){var j=8>jb||c.documentMode<8?2:0;return b=b||0===b?b:!1,d=d||0===d?d:!1,b===!1&&d===!1?{width:lb.width(),height:lb.height()}:("undefined"==typeof i.data("outerWidthOffset")&&lb.updateStyleCache(),b!==!1&&(e!==!1&&(f.width=b),d===!1&&(d=g.height(),e=!1),g.width(b),b&&b.toString().indexOf("%")>-1&&(b=g.width()),i.width(b-i.data("outerWidthOffset")),m.width(b-m.data("outerWidthOffset")),a.sceditor.ios&&k&&k.width(b-i.data("outerWidthOffset")-(k.outerWidth(!0)-k.width()))),d!==!1&&(e!==!1&&(f.height=d),d&&d.toString().indexOf("%")>-1&&(d=g.height(d).height(),g.height("auto")),d-=f.toolbarContainer?0:h.outerHeight(!0),i.height(d-i.data("outerHeightOffset")),m.height(d-j-m.data("outerHeightOffset"))),this)},lb.updateStyleCache=function(){i.data("outerWidthOffset",i.outerWidth(!0)-i.width()),m.data("outerWidthOffset",m.outerWidth(!0)-m.width()),i.data("outerHeightOffset",i.outerHeight(!0)-i.height()),m.data("outerHeightOffset",m.outerHeight(!0)-m.height())},lb.height=function(a,b){return a||0===a?(lb.dimensions(null,a,b),this):g.height()},lb.maximize=function(b){return"undefined"==typeof b?g.is(".sceditor-maximize"):(b=!!b,7>jb&&a("html, body").toggleClass("sceditor-maximize",b),g.toggleClass("sceditor-maximize",b),lb.width(b?"100%":f.width,!1),lb.height(b?"100%":f.height,!1),this)},lb.expandToContent=function(a){var b=g.height(),c=k[0].scrollHeight||l[0].documentElement.scrollHeight,d=b-i.height(),e=f.resizeMaxHeight||2*(f.height||nb.height());c+=d,a!==!0&&c>e&&(c=e),c>b&&lb.height(c)},lb.destroy=function(){t&&(t.destroy(),r=null,p=null,t=null,a(c).unbind("click",W),a(b).unbind("resize orientationChanged",X),a(mb.form).unbind("reset",T).unbind("submit",lb.updateOriginal),k.unbind(),l.unbind().find("*").remove(),m.unbind().remove(),h.remove(),g.unbind().find("*").unbind().remove(),g.remove(),nb.removeData("sceditor").removeData("sceditorbbcode").show(),y&&nb.attr("required","required"))},lb.createDropDown=function(b,c,d,e){var g,h=o&&o.is(".sceditor-"+c);lb.closeDropDown(),h||(e!==!1&&a(d).find(":not(input,textarea)").filter(function(){return 1===this.nodeType}).attr("unselectable","on"),g={top:b.offset().top,left:b.offset().left,marginTop:b.outerHeight()},a.extend(g,f.dropDownCss),o=a('
    ').css(g).append(d).appendTo(a("body")).on("click focusin",function(a){a.stopPropagation()}))},W=function(a){3!==a.which&&lb.closeDropDown()},O=function(a){var b,d,e,g=k[0],h=l[0],i=0,j=c.createElement("div"),m=h.createDocumentFragment();if(f.disablePasting)return!1;if(f.enablePasteFiltering){if(r.saveRange(),c.body.appendChild(j),a&&a.clipboardData&&a.clipboardData.getData&&((b=a.clipboardData.getData("text/html"))||(b=a.clipboardData.getData("text/plain"))))return j.innerHTML=b,P(g,j),!1;for(e=k.scrollTop()||l.scrollTop();g.firstChild;)m.appendChild(g.firstChild);return d=function(a,b){if(a.childNodes.length>0||i>25){for(;a.firstChild;)b.appendChild(a.firstChild);for(;m.firstChild;)a.appendChild(m.firstChild);k.scrollTop(e),l.scrollTop(e),b.childNodes.length>0?P(a,b):r.restoreRange()}else i++,setTimeout(function(){d(a,b)},20)},d(g,j),lb.focus(),!0}},P=function(b,c){a.sceditor.dom.fixNesting(c);var d=c.innerHTML;t.hasHandler("toSource")&&(d=t.callOnlyFirst("toSource",d,a(c))),c.parentNode.removeChild(c),t.hasHandler("toWysiwyg")&&(d=t.callOnlyFirst("toWysiwyg",d,!0)),r.restoreRange(),lb.wysiwygEditorInsertHtml(d,null,!0)},lb.closeDropDown=function(a){o&&(o.unbind().remove(),o=null),a===!0&&lb.focus()},N=function(){return j.contentDocument?j.contentDocument:j.contentWindow&&j.contentWindow.document?j.contentWindow.document:j.document?j.document:null},lb.wysiwygEditorInsertHtml=function(b,c,d){var e,f,g,h=i.height();lb.focus(),(d||!a(v).is("code")&&0===a(v).parents("code").length)&&(r.insertHTML(b,c),r.saveRange(),B(k[0]),e=k.find("#sceditor-end-marker").show(),f=k.scrollTop()||l.scrollTop(),g=a.sceditor.dom.getOffset(e[0]).top+1.5*e.outerHeight(!0)-h,e.hide(),(g>f||f>g+h)&&(k.scrollTop(g),l.scrollTop(g)),gb(!1),r.restoreRange(),_())},lb.wysiwygEditorInsertText=function(b,c){lb.wysiwygEditorInsertHtml(a.sceditor.escapeEntities(b),a.sceditor.escapeEntities(c))},lb.insertText=function(a,b){return lb.inSourceMode()?lb.sourceEditorInsertText(a,b):lb.wysiwygEditorInsertText(a,b),this},lb.sourceEditorInsertText=function(a,b){var d,e,f,g,h;h=n.scrollTop,n.focus(),"undefined"!=typeof n.selectionStart?(e=n.selectionStart,f=n.selectionEnd,g=a.length,b&&(a+=n.value.substring(e,f)+b),n.value=n.value.substring(0,e)+a+n.value.substring(f,n.value.length),n.selectionStart=e+a.length-(b?b.length:0),n.selectionEnd=n.selectionStart):"undefined"!=typeof c.selection.createRange?(d=c.selection.createRange(),b&&(a+=d.text+b),d.text=a,b&&d.moveEnd("character",0-b.length),d.moveStart("character",d.End-d.Start),d.select()):n.value+=a+b,n.scrollTop=h,n.focus(),gb()},lb.getRangeHelper=function(){return r},lb.sourceEditorCaret=function(a){var b={};return"undefined"!=typeof n.selectionStart?a?(n.selectionStart=a.start,n.selectionEnd=a.end):(b.start=n.selectionStart,b.end=n.selectionEnd):(range=c.selection.createRange(),a?(range.moveStart("character",a.start),range.moveEnd("character",a.end),range.select()):(b.start=range.Start,b.end=range.End)),a?this:b},lb.val=function(a,b){return"string"==typeof a?(lb.inSourceMode()?lb.setSourceEditorValue(a):(b!==!1&&t.hasHandler("toWysiwyg")&&(a=t.callOnlyFirst("toWysiwyg",a)),lb.setWysiwygEditorValue(a)),this):lb.inSourceMode()?lb.getSourceEditorValue(!1):lb.getWysiwygEditorValue()},lb.insert=function(b,c,d,e,f){if(lb.inSourceMode())lb.sourceEditorInsertText(b,c);else{if(c){var g=lb.getRangeHelper().selectedHtml(),h=a("
    ").appendTo(a("body")).hide().html(g);d!==!1&&t.hasHandler("toSource")&&(g=t.callOnlyFirst("toSource",g,h)),h.remove(),b+=g+c}d!==!1&&t.hasHandler("toWysiwyg")&&(b=t.callOnlyFirst("toWysiwyg",b,!0)),d!==!1&&f===!0&&(b=b.replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&")),lb.wysiwygEditorInsertHtml(b)}return this},lb.getWysiwygEditorValue=function(b){var c,d,e=r.hasSelection();return e?r.saveRange():p&&p.getBookmark&&(d=p.getBookmark()),a.sceditor.dom.fixNesting(k[0]),c=k.html(),b!==!1&&t.hasHandler("toSource")&&(c=t.callOnlyFirst("toSource",c,k)),e?(r.restoreRange(),p=null):d&&(p.moveToBookmark(d),p=null),c},lb.getBody=function(){return k},lb.getContentAreaContainer=function(){return i},lb.getSourceEditorValue=function(a){var b=m.val();return a!==!1&&t.hasHandler("toWysiwyg")&&(b=t.callOnlyFirst("toWysiwyg",b)),b},lb.setWysiwygEditorValue=function(a){a||(a="

    "+(jb?"":"
    ")+"

    "),k[0].innerHTML=a,B(k[0]),_(),gb()},lb.setSourceEditorValue=function(a){m.val(a),gb()},lb.updateOriginal=function(){nb.val(lb.val())},B=function(b){if(f.emoticonsEnabled&&!a(b).parents("code").length){var c=b.ownerDocument,d=[],g=[],h=a.extend({},f.emoticons.more,f.emoticons.dropdown,f.emoticons.hidden);a.each(h,function(b){f.emoticonsCompat&&(g[b]=new RegExp("(>|^|\\s| | | | | )"+a.sceditor.regexEscape(b)+"(\\s|$|<| | | | | )")),d.push(b)}),function i(b){for(b=b.firstChild;null!=b;){var j,k,l,m,n,o,p,q=b.parentNode,r=b.nodeValue;if(3!==b.nodeType)a(b).is("code")||i(b);else if(r)for(n=d.length;n--;)k=d[n],p=f.emoticonsCompat?r.search(g[k]):r.indexOf(k),p>-1&&(o=b.nextSibling,l=h[k],j=r.substr(p).split(k),r=r.substr(0,p)+j.shift(),b.nodeValue=r,m=a.sceditor.dom.parseHTML(e("emoticon",{key:k,url:l.url||l,tooltip:l.tooltip||k}),c),q.insertBefore(m[0],o),q.insertBefore(c.createTextNode(j.join(k)),o));b=b.nextSibling}}(b),f.emoticonsCompat&&(tb=k.find("img[data-sceditor-emoticon]"))}},lb.inSourceMode=function(){return g.hasClass("sourceMode")},lb.sourceMode=function(a){return"boolean"!=typeof a?lb.inSourceMode():((lb.inSourceMode()&&!a||!lb.inSourceMode()&&a)&&lb.toggleSourceMode(),this)},lb.toggleSourceMode=function(){(a.sceditor.isWysiwygSupported||!lb.inSourceMode())&&(lb.blur(),lb.inSourceMode()?lb.setWysiwygEditorValue(lb.getSourceEditorValue()):lb.setSourceEditorValue(lb.getWysiwygEditorValue()),p=null,m.toggle(),i.toggle(),lb.inSourceMode()?g.removeClass("sourceMode").addClass("wysiwygMode"):g.removeClass("wysiwygMode").addClass("sourceMode"),Y(),Z())},$=function(){return n.focus(),null!=n.selectionStart?n.value.substring(n.selectionStart,n.selectionEnd):c.selection.createRange?c.selection.createRange().text:void 0},C=function(b,c){return lb.inSourceMode()?void(c.txtExec&&(a.isArray(c.txtExec)?lb.sourceEditorInsertText.apply(lb,c.txtExec):c.txtExec.call(lb,b,$()))):void(c.exec&&(a.isFunction(c.exec)?c.exec.call(lb,b):lb.execCommand(c.exec,c.hasOwnProperty("execParam")?c.execParam:null)))},D=function(){jb&&(p=r.selectedRange())},lb.execCommand=function(b,c){var d=!1,e=a(r.parentNode());if(lb.focus(),!e.is("code")&&0===e.parents("code").length){try{d=l[0].execCommand(b,!1,c)}catch(f){}!d&&lb.commands[b]&&lb.commands[b].errorMessage&&alert(lb._(lb.commands[b].errorMessage))}},ab=function(){var b=function(){r&&!r.compare(w)&&(w=r.cloneSelected(),g.trigger(a.Event("selectionchanged"))),x=!1};x||(x=!0,jb?b():setTimeout(b,100))},bb=function(){var b,c=r.parentNode();u!==c&&(b=u,u=c,v=r.getFirstBlockParent(c),g.trigger(a.Event("nodechanged",{oldNode:b,newNode:u})))},lb.currentNode=function(){return u},lb.currentBlockNode=function(){return v},Z=function(a){var b,c,d,e,f,g=l[0],i=rb.length,j=lb.sourceMode();if(lb.sourceMode()||lb.readOnly())h.find(".sceditor-button").removeClass("active");else for(f=a?a.newNode:r.parentNode(),d=r.getFirstBlockParent(f);i--;)if(b=0,c=rb[i],e=h.find(".sceditor-button-"+c.name),j&&!e.data("sceditor-txtmode"))e.addClass("disabled");else if(j||e.data("sceditor-wysiwygmode")){if("string"==typeof c.state)try{b=g.queryCommandEnabled(c.state)?0:-1,b>-1&&(b=g.queryCommandState(c.state)?1:0)}catch(k){}else b=c.state.call(lb,f,d);0>b?e.addClass("disabled"):e.removeClass("disabled"),b>0?e.addClass("active"):e.removeClass("active")}else e.addClass("disabled")},S=function(b){var c,d;if(!b.originalEvent.defaultPrevented){if(lb.closeDropDown(),c=a(u),13===b.which&&(c.is("code,blockquote,pre")||0!==c.parents("code,blockquote,pre").length))return p=null,lb.wysiwygEditorInsertHtml("
    ",null,!0),!1;if(!c.is("code")&&0===c.parents("code").length)for(d=ob.length;d--;)ob[d].call(lb,b,j,m)}},_=function(){var b,c,d;a.sceditor.dom.rTraverse(k[0],function(e){return b=e.nodeName.toLowerCase(),a.inArray(b,qb)>-1&&(c=!0),3===e.nodeType&&!/^\s*$/.test(e.nodeValue)||"br"===b||kb&&!e.firstChild&&!a.sceditor.dom.isInline(e,!1)?(c&&(d=k[0].ownerDocument.createElement("div"),d.className="sceditor-nlf",d.innerHTML=kb?"":"
    ",k[0].appendChild(d)),!1):void 0})},T=function(){lb.val(nb.val())},U=function(){lb.closeDropDown(),p=null},X=function(){var a=f.height,b=f.width;lb.maximize()?lb.dimensions("100%","100%",!1):(a&&a.toString().indexOf("%")>-1||b&&b.toString().indexOf("%")>-1)&&lb.dimensions(b,a)},lb._=function(){var a,b=arguments;return q&&q[b[0]]&&(b[0]=q[b[0]]),b[0].replace(/\{(\d+)\}/g,function(c,d){return b[d-0+1]!==a?b[d-0+1]:"{"+d+"}"})},V=function(b){var c,d=a.extend({},b);t.call(d.type+"Event",b,lb),delete d.type,c=a.Event((b.target===n?"scesrc":"scewys")+b.type,d),g.trigger(c,lb),c.isDefaultPrevented()&&b.preventDefault(),c.isImmediatePropagationStopped()&&c.stopImmediatePropagation(),c.isPropagationStopped()&&c.stopPropagation()},lb.bind=function(b,c,d,e){b=b.split(" ");for(var f=b.length;f--;)a.isFunction(c)&&(d||g.bind("scewys"+b[f],c),e||g.bind("scesrc"+b[f],c),"valuechanged"===b[f]&&(gb.hasHandler=!0));return this},lb.unbind=function(b,c,d,e){b=b.split(" ");for(var f=b.length;f--;)a.isFunction(c)&&(d||g.unbind("scewys"+b[f],c),e||g.unbind("scesrc"+b[f],c));return this},lb.blur=function(b,c,d){return a.isFunction(b)?lb.bind("blur",b,c,d):lb.sourceMode()?m.blur():(s||(s=a('').appendTo(g)),s.removeAttr("disabled").show().focus().blur().hide().attr("disabled","disabled")),this},lb.focus=function(b,c,d){return a.isFunction(b)?lb.bind("focus",b,c,d):lb.inSourceMode()?n.focus():(j.contentWindow.focus(),k[0].focus(),p&&(r.selectRange(p),p=null)),this},lb.keyDown=function(a,b,c){return lb.bind("keydown",a,b,c)},lb.keyPress=function(a,b,c){return lb.bind("keypress",a,b,c)},lb.keyUp=function(a,b,c){return lb.bind("keyup",a,b,c)},lb.nodeChanged=function(a){return lb.bind("nodechanged",a,!1,!0)},lb.selectionChanged=function(a){return lb.bind("selectionchanged",a,!1,!0)},lb.valueChanged=function(a,b,c){return lb.bind("valuechanged",a,b,c)},db=function(b){var c=0,d=String.fromCharCode(b.which);if(!a(v).is("code")&&!a(v).parents("code").length)return lb.emoticonsCache||(lb.emoticonsCache=[],a.each(a.extend({},f.emoticons.more,f.emoticons.dropdown,f.emoticons.hidden),function(a,b){lb.emoticonsCache[c++]=[a,e("emoticon",{key:a,url:b.url||b,tooltip:b.tooltip||a})]}),lb.emoticonsCache.sort(function(a,b){return a[0].length-b[0].length}),lb.longestEmoticonCode=lb.emoticonsCache[lb.emoticonsCache.length-1][0].length),lb.getRangeHelper().raplaceKeyword(lb.emoticonsCache,!0,!0,lb.longestEmoticonCode,f.emoticonsCompat,d)?(f.emoticonsCompat&&(tb=k.find("img[data-sceditor-emoticon]")),/^\s$/.test(d)&&f.emoticonsCompat):void 0},eb=function(){if(tb.length){var b,c,d,e,f,g,h=lb.currentBlockNode(),i=!1,j=/[^\s\xA0\u2002\u2003\u2009\u00a0]+/;tb=a.map(tb,function(k){return k&&k.parentNode?a.contains(h,k)?(b=k.previousSibling,c=k.nextSibling,f=b.nodeValue,null===f&&(f=b.innerText||""),b&&j.test(b.nodeValue.slice(-1))||c&&j.test((c.nodeValue||"")[0])?(d=k.parentNode,e=r.cloneSelected(),g=e.startContainer,f+=a(k).data("sceditor-emoticon"),g===c?i=f.length+e.startOffset:g===h&&h.childNodes[e.startOffset]===c?i=f.length:g===b&&(i=e.startOffset),c&&3===c.nodeType||(c=d.insertBefore(d.ownerDocument.createTextNode(""),c)),c.insertData(0,f),d.removeChild(b),d.removeChild(k),i!==!1&&(e.setStart(c,i),e.collapse(!0),r.selectRange(e)),null):k):k:null})}},lb.emoticons=function(b){return b||b===!1?(f.emoticonsEnabled=b,b?(k.keypress(db),lb.sourceMode()||(r.saveRange(),B(k[0]),tb=k.find("img[data-sceditor-emoticon]"),gb(!1),r.restoreRange())):(k.find("img[data-sceditor-emoticon]").replaceWith(function(){return a(this).data("sceditor-emoticon")}),tb=[],k.unbind("keypress",db),gb()),this):f.emoticonsEnabled},lb.css=function(b){return z||(z=a('',toolbarButton:'
    {dispName}
    ',emoticon:'{key}',fontOpt:'{font}',sizeOpt:'{size}',pastetext:'
    ',table:'
    ',image:'
    ',email:'
    ',link:'
    ',youtubeMenu:'
    ',youtube:''},e=function(b,c,e){var f=d[b];return a.each(c,function(a,b){f=f.replace(new RegExp("\\{"+a+"\\}","g"),b)}),e&&(f=a(f)),f};a.sceditor=function(d,f){var g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,$,_,ab,bb,cb,db,eb,fb,gb,hb,ib,jb=a.sceditor.ie,kb=jb&&11>jb,lb=this,mb=d.get?d.get(0):d,nb=a(mb),ob=[],pb=[],qb=[],rb=[],sb={},tb=[];lb.commands=a.extend(!0,{},f.commands||a.sceditor.commands),lb.opts=f=a.extend({},a.sceditor.defaultOptions,f),A=function(){nb.data("sceditor",lb),a.each(f,function(b,c){a.isPlainObject(c)&&(f[b]=a.extend(!0,{},c))}),f.locale&&"en"!==f.locale&&G(),g=a('
    ').insertAfter(nb).css("z-index",f.zIndex),jb&&g.addClass("ie ie"+jb),y=!!nb.attr("required"),nb.removeAttr("required"),F(),M(),H(),E(),K(),I(),J(),a.sceditor.isWysiwygSupported||lb.toggleSourceMode(),Z();var d=function(){a(b).unbind("load",d),f.autofocus&&cb(),f.autoExpand&&lb.expandToContent(),X(),t.call("ready")};a(b).load(d),c.readyState&&"complete"===c.readyState&&d()},F=function(){var b=f.plugins;b=b?b.toString().split(","):[],t=new a.sceditor.PluginManager(lb),a.each(b,function(b,c){t.register(a.trim(c))})},G=function(){var b;q=a.sceditor.locale[f.locale],q||(b=f.locale.split("-"),q=a.sceditor.locale[b[0]]),q&&q.dateFormat&&(f.dateFormat=q.dateFormat)},E=function(){var c,d;m=a("").hide(),i=a(''),f.spellcheck||m.attr("spellcheck","false"),"https:"===b.location.protocol&&i.attr("src","javascript:false"),g.append(i).append(m),j=i[0],n=m[0],lb.dimensions(f.width||nb.width(),f.height||nb.height()),c=N(),c.open(),c.write(e("html",{spellcheck:f.spellcheck?"":'spellcheck="false"',charset:f.charset,style:f.style})),c.close(),l=a(c),k=a(c.body),lb.readOnly(!!f.readOnly),jb&&l.find("html").addClass("ie ie"+jb),(a.sceditor.ios||jb)&&(k.height("100%"),jb||k.bind("touchend",lb.focus)),r=new a.sceditor.rangeHelper(j.contentWindow),lb.val(nb.hide().val()),d=nb.attr("tabindex"),m.attr("tabindex",d),i.attr("tabindex",d)},I=function(){f.autoUpdate&&(k.bind("blur",lb.updateOriginal),m.bind("blur",lb.updateOriginal)),null===f.rtl&&(f.rtl="rtl"===m.css("direction")),lb.rtl(!!f.rtl),f.autoExpand&&l.bind("keyup",lb.expandToContent),f.resizeEnabled&&L(),g.attr("id",f.id),lb.emoticons(f.emoticonsEnabled)},J=function(){a(c).click(W),a(mb.form).bind("reset",T).submit(lb.updateOriginal),a(b).bind("resize orientationChanged",X),k.keypress(S).keydown(Q).keydown(R).keyup(_).bind("blur",hb).keyup(ib).bind("paste",O).bind(jb?"selectionchange":"keyup focus blur contextmenu mouseup touchend click",ab).bind("keydown keyup keypress focus blur contextmenu",V),f.emoticonsCompat&&b.getSelection&&k.keyup(eb),m.bind("blur",hb).keyup(ib).bind("keydown keyup keypress focus blur contextmenu",V).keydown(Q),l.mousedown(U).bind("blur",hb).bind(jb?"selectionchange":"focus blur contextmenu mouseup click",ab).bind("beforedeactivate keyup",D).keyup(_).focus(function(){p=null}),g.bind("selectionchanged",bb).bind("selectionchanged",Z).bind("selectionchanged valuechanged nodechanged",V)},H=function(){var b,c,d,i=lb.commands,j=(f.toolbarExclude||"").split(","),k=f.toolbar.split("|");h=a('
    '),a.each(k,function(f,g){b=a('
    '),a.each(g.split(","),function(f,g){!i[g]||a.inArray(g,j)>-1||(d=i[g].shortcut?" ("+i[g].shortcut+")":"",c=e("toolbarButton",{name:g,dispName:lb._(i[g].tooltip||g)+d},!0),c.data("sceditor-txtmode",!!i[g].txtExec),c.data("sceditor-wysiwygmode",!!i[g].exec),c.click(function(){var b=a(this);return b.hasClass("disabled")||C(b,i[g]),Z(),!1}),i[g].tooltip&&c.attr("title",lb._(i[g].tooltip)),i[g].exec||c.addClass("disabled"),i[g].shortcut&&(lb.addShortcut(i[g].shortcut,g),c.attr("title",c.attr("title")+d)),b.append(c))}),b[0].firstChild&&h.append(b)}),a(f.toolbarContainer||g).append(h)},K=function(){a.each(lb.commands,function(b,c){c.keyPress&&ob.push(c.keyPress),c.forceNewLineAfter&&a.isArray(c.forceNewLineAfter)&&(qb=a.merge(qb,c.forceNewLineAfter)),c.state?rb.push({name:b,state:c.state}):"string"==typeof c.exec&&rb.push({name:b,state:c.exec})}),_()},L=function(){var d,e,h,i,j,k,l=a('
    '),m=a('
    '),n=0,o=0,p=0,q=0,r=g.width(),s=g.height(),t=!1,u=lb.rtl();d=f.resizeMinHeight||s/1.5,e=f.resizeMaxHeight||2.5*s,h=f.resizeMinWidth||r/1.25,i=f.resizeMaxWidth||1.25*r,j=function(a){"touchmove"===a.type&&(a=b.event);var c=q+(a.pageY-o),j=u?p-(a.pageX-n):p+(a.pageX-n);i>0&&j>i&&(j=i),e>0&&c>e&&(c=e),(!f.resizeWidth||h>j||i>0&&j>i)&&(j=!1),(!f.resizeHeight||d>c||e>0&&c>e)&&(c=!1),(j||c)&&(lb.dimensions(j,c),7>jb&&g.height(c)),a.preventDefault()},k=function(b){t&&(t=!1,m.hide(),g.removeClass("resizing").height("auto"),a(c).unbind("touchmove mousemove",j),a(c).unbind("touchend mouseup",k),b.preventDefault())},g.append(l),g.append(m.hide()),l.bind("touchstart mousedown",function(d){"touchstart"===d.type&&(d=b.event),n=d.pageX,o=d.pageY,p=g.width(),q=g.height(),t=!0,g.addClass("resizing"),m.show(),a(c).bind("touchmove mousemove",j),a(c).bind("touchend mouseup",k),7>jb&&g.height(q),d.preventDefault()})},M=function(){var b,d=f.emoticons,e=f.emoticonsRoot;a.isPlainObject(d)&&f.emoticonsEnabled&&a.each(d,function(f,g){a.each(g,function(a,g){e&&(g={url:e+(g.url||g),tooltip:g.tooltip||a},d[f][a]=g),b=c.createElement("img"),b.src=g.url||g,pb.push(b)})})},cb=function(){var b,c,d,e=l[0],h=k[0],i=!!f.autofocusEnd;if(g.is(":visible")){if(lb.sourceMode())d=n.value.length,n.setSelectionRange?n.setSelectionRange(d,d):n.createTextRange&&(b=n.createTextRange(),b.moveEnd("character",d),b.moveStart("character",d),r.selectRange(b));else{if(a.sceditor.dom.removeWhiteSpace(h),i)for((c=h.lastChild)||k.append(c=e.createElement("div"));c.lastChild;)c=c.lastChild,/br/i.test(c.nodeName)&&c.previousSibling&&(c=c.previousSibling);else c=h.firstChild;e.createRange?(b=e.createRange(),/br/i.test(c.nodeName)?b.setStartBefore(c):b.selectNodeContents(c),b.collapse(!1)):(b=h.createTextRange(),b.moveToElementText(3!==c.nodeType?c:c.parentNode),b.collapse(!1)),r.selectRange(b),i&&(l.scrollTop(h.scrollHeight),k.scrollTop(h.scrollHeight))}lb.focus()}},lb.readOnly=function(a){return"boolean"!=typeof a?"readonly"===m.attr("readonly"):(k[0].contentEditable=!a,a?m.attr("readonly","readonly"):m.removeAttr("readonly"),Y(a),this)},lb.rtl=function(a){var b=a?"rtl":"ltr";return"boolean"!=typeof a?"rtl"===m.attr("dir"):(k.attr("dir",b),m.attr("dir",b),g.removeClass("rtl").removeClass("ltr").addClass(b),this)},Y=function(b){var c=lb.inSourceMode();h.find(".sceditor-button").removeClass("disabled").each(function(){var d=a(this);b===!0||c&&!d.data("sceditor-txtmode")?d.addClass("disabled"):c||d.data("sceditor-wysiwygmode")||d.addClass("disabled")})},lb.width=function(a,b){return a||0===a?(lb.dimensions(a,null,b),this):g.width()},lb.dimensions=function(b,d,e){var j=8>jb||c.documentMode<8?2:0;return b=b||0===b?b:!1,d=d||0===d?d:!1,b===!1&&d===!1?{width:lb.width(),height:lb.height()}:("undefined"==typeof i.data("outerWidthOffset")&&lb.updateStyleCache(),b!==!1&&(e!==!1&&(f.width=b),d===!1&&(d=g.height(),e=!1),g.width(b),b&&b.toString().indexOf("%")>-1&&(b=g.width()),i.width(b-i.data("outerWidthOffset")),m.width(b-m.data("outerWidthOffset")),a.sceditor.ios&&k&&k.width(b-i.data("outerWidthOffset")-(k.outerWidth(!0)-k.width()))),d!==!1&&(e!==!1&&(f.height=d),d&&d.toString().indexOf("%")>-1&&(d=g.height(d).height(),g.height("auto")),d-=f.toolbarContainer?0:h.outerHeight(!0),i.height(d-i.data("outerHeightOffset")),m.height(d-j-m.data("outerHeightOffset"))),this)},lb.updateStyleCache=function(){i.data("outerWidthOffset",i.outerWidth(!0)-i.width()),m.data("outerWidthOffset",m.outerWidth(!0)-m.width()),i.data("outerHeightOffset",i.outerHeight(!0)-i.height()),m.data("outerHeightOffset",m.outerHeight(!0)-m.height())},lb.height=function(a,b){return a||0===a?(lb.dimensions(null,a,b),this):g.height()},lb.maximize=function(b){return"undefined"==typeof b?g.is(".sceditor-maximize"):(b=!!b,7>jb&&a("html, body").toggleClass("sceditor-maximize",b),g.toggleClass("sceditor-maximize",b),lb.width(b?"100%":f.width,!1),lb.height(b?"100%":f.height,!1),this)},lb.expandToContent=function(a){var b=g.height(),c=k[0].scrollHeight||l[0].documentElement.scrollHeight,d=b-i.height(),e=f.resizeMaxHeight||2*(f.height||nb.height());c+=d,a!==!0&&c>e&&(c=e),c>b&&lb.height(c)},lb.destroy=function(){t&&(t.destroy(),r=null,p=null,t=null,a(c).unbind("click",W),a(b).unbind("resize orientationChanged",X),a(mb.form).unbind("reset",T).unbind("submit",lb.updateOriginal),k.unbind(),l.unbind().find("*").remove(),m.unbind().remove(),h.remove(),g.unbind().find("*").unbind().remove(),g.remove(),nb.removeData("sceditor").removeData("sceditorbbcode").show(),y&&nb.attr("required","required"))},lb.createDropDown=function(b,c,d,e){var g,h=o&&o.is(".sceditor-"+c);lb.closeDropDown(),h||(e!==!1&&a(d).find(":not(input,textarea)").filter(function(){return 1===this.nodeType}).attr("unselectable","on"),g={top:b.offset().top,left:b.offset().left,marginTop:b.outerHeight()},a.extend(g,f.dropDownCss),o=a('
    ').css(g).append(d).appendTo(a("body")).on("click focusin",function(a){a.stopPropagation()}))},W=function(a){3!==a.which&&lb.closeDropDown()},O=function(a){var b,d,e,g=k[0],h=l[0],i=0,j=c.createElement("div"),m=h.createDocumentFragment();if(f.disablePasting)return!1;if(f.enablePasteFiltering){if(r.saveRange(),c.body.appendChild(j),a&&a.clipboardData&&a.clipboardData.getData&&((b=a.clipboardData.getData("text/html"))||(b=a.clipboardData.getData("text/plain"))))return j.innerHTML=b,P(g,j),!1;for(e=k.scrollTop()||l.scrollTop();g.firstChild;)m.appendChild(g.firstChild);return d=function(a,b){if(a.childNodes.length>0||i>25){for(;a.firstChild;)b.appendChild(a.firstChild);for(;m.firstChild;)a.appendChild(m.firstChild);k.scrollTop(e),l.scrollTop(e),b.childNodes.length>0?P(a,b):r.restoreRange()}else i++,setTimeout(function(){d(a,b)},20)},d(g,j),lb.focus(),!0}},P=function(b,c){a.sceditor.dom.fixNesting(c);var d=c.innerHTML;t.hasHandler("toSource")&&(d=t.callOnlyFirst("toSource",d,a(c))),c.parentNode.removeChild(c),t.hasHandler("toWysiwyg")&&(d=t.callOnlyFirst("toWysiwyg",d,!0)),r.restoreRange(),lb.wysiwygEditorInsertHtml(d,null,!0)},lb.closeDropDown=function(a){o&&(o.unbind().remove(),o=null),a===!0&&lb.focus()},N=function(){return j.contentDocument?j.contentDocument:j.contentWindow&&j.contentWindow.document?j.contentWindow.document:j.document?j.document:null},lb.wysiwygEditorInsertHtml=function(b,c,d){var e,f,g,h=i.height();lb.focus(),(d||!a(v).is("code")&&0===a(v).parents("code").length)&&(r.insertHTML(b,c),r.saveRange(),B(k[0]),e=k.find("#sceditor-end-marker").show(),f=k.scrollTop()||l.scrollTop(),g=a.sceditor.dom.getOffset(e[0]).top+1.5*e.outerHeight(!0)-h,e.hide(),(g>f||f>g+h)&&(k.scrollTop(g),l.scrollTop(g)),gb(!1),r.restoreRange(),_())},lb.wysiwygEditorInsertText=function(b,c){lb.wysiwygEditorInsertHtml(a.sceditor.escapeEntities(b),a.sceditor.escapeEntities(c))},lb.insertText=function(a,b){return lb.inSourceMode()?lb.sourceEditorInsertText(a,b):lb.wysiwygEditorInsertText(a,b),this},lb.sourceEditorInsertText=function(a,b){var d,e,f,g,h;h=n.scrollTop,n.focus(),"undefined"!=typeof n.selectionStart?(e=n.selectionStart,f=n.selectionEnd,g=a.length,b&&(a+=n.value.substring(e,f)+b),n.value=n.value.substring(0,e)+a+n.value.substring(f,n.value.length),n.selectionStart=e+a.length-(b?b.length:0),n.selectionEnd=n.selectionStart):"undefined"!=typeof c.selection.createRange?(d=c.selection.createRange(),b&&(a+=d.text+b),d.text=a,b&&d.moveEnd("character",0-b.length),d.moveStart("character",d.End-d.Start),d.select()):n.value+=a+b,n.scrollTop=h,n.focus(),gb()},lb.getRangeHelper=function(){return r},lb.sourceEditorCaret=function(a){var b={};return"undefined"!=typeof n.selectionStart?a?(n.selectionStart=a.start,n.selectionEnd=a.end):(b.start=n.selectionStart,b.end=n.selectionEnd):(range=c.selection.createRange(),a?(range.moveStart("character",a.start),range.moveEnd("character",a.end),range.select()):(b.start=range.Start,b.end=range.End)),a?this:b},lb.val=function(a,b){return"string"==typeof a?(lb.inSourceMode()?lb.setSourceEditorValue(a):(b!==!1&&t.hasHandler("toWysiwyg")&&(a=t.callOnlyFirst("toWysiwyg",a)),lb.setWysiwygEditorValue(a)),this):lb.inSourceMode()?lb.getSourceEditorValue(!1):lb.getWysiwygEditorValue()},lb.insert=function(b,c,d,e,f){if(lb.inSourceMode())lb.sourceEditorInsertText(b,c);else{if(c){var g=lb.getRangeHelper().selectedHtml(),h=a("
    ").appendTo(a("body")).hide().html(g);d!==!1&&t.hasHandler("toSource")&&(g=t.callOnlyFirst("toSource",g,h)),h.remove(),b+=g+c}d!==!1&&t.hasHandler("toWysiwyg")&&(b=t.callOnlyFirst("toWysiwyg",b,!0)),d!==!1&&f===!0&&(b=b.replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&")),lb.wysiwygEditorInsertHtml(b)}return this},lb.getWysiwygEditorValue=function(b){var c,d,e=r.hasSelection();return e?r.saveRange():p&&p.getBookmark&&(d=p.getBookmark()),a.sceditor.dom.fixNesting(k[0]),c=k.html(),b!==!1&&t.hasHandler("toSource")&&(c=t.callOnlyFirst("toSource",c,k)),e?(r.restoreRange(),p=null):d&&(p.moveToBookmark(d),p=null),c},lb.getBody=function(){return k},lb.getContentAreaContainer=function(){return i},lb.getSourceEditorValue=function(a){var b=m.val();return a!==!1&&t.hasHandler("toWysiwyg")&&(b=t.callOnlyFirst("toWysiwyg",b)),b},lb.setWysiwygEditorValue=function(a){a||(a="

    "+(jb?"":"
    ")+"

    "),k[0].innerHTML=a,B(k[0]),_(),gb()},lb.setSourceEditorValue=function(a){m.val(a),gb()},lb.updateOriginal=function(){nb.val(lb.val())},B=function(b){if(f.emoticonsEnabled&&!a(b).parents("code").length){var c=b.ownerDocument,d=[],g=[],h=a.extend({},f.emoticons.more,f.emoticons.dropdown,f.emoticons.hidden);a.each(h,function(b){f.emoticonsCompat&&(g[b]=new RegExp("(>|^|\\s| | | | | )"+a.sceditor.regexEscape(b)+"(\\s|$|<| | | | | )")),d.push(b)}),function i(b){for(b=b.firstChild;null!=b;){var j,k,l,m,n,o,p,q=b.parentNode,r=b.nodeValue;if(3!==b.nodeType)a(b).is("code")||i(b);else if(r)for(n=d.length;n--;)k=d[n],p=f.emoticonsCompat?r.search(g[k]):r.indexOf(k),p>-1&&(o=b.nextSibling,l=h[k],j=r.substr(p).split(k),r=r.substr(0,p)+j.shift(),b.nodeValue=r,m=a.sceditor.dom.parseHTML(e("emoticon",{key:k,url:l.url||l,tooltip:l.tooltip||k}),c),q.insertBefore(m[0],o),q.insertBefore(c.createTextNode(j.join(k)),o));b=b.nextSibling}}(b),f.emoticonsCompat&&(tb=k.find("img[data-sceditor-emoticon]"))}},lb.inSourceMode=function(){return g.hasClass("sourceMode")},lb.sourceMode=function(a){return"boolean"!=typeof a?lb.inSourceMode():((lb.inSourceMode()&&!a||!lb.inSourceMode()&&a)&&lb.toggleSourceMode(),this)},lb.toggleSourceMode=function(){(a.sceditor.isWysiwygSupported||!lb.inSourceMode())&&(lb.blur(),lb.inSourceMode()?lb.setWysiwygEditorValue(lb.getSourceEditorValue()):lb.setSourceEditorValue(lb.getWysiwygEditorValue()),p=null,m.toggle(),i.toggle(),lb.inSourceMode()?g.removeClass("sourceMode").addClass("wysiwygMode"):g.removeClass("wysiwygMode").addClass("sourceMode"),Y(),Z())},$=function(){return n.focus(),null!=n.selectionStart?n.value.substring(n.selectionStart,n.selectionEnd):c.selection.createRange?c.selection.createRange().text:void 0},C=function(b,c){return lb.inSourceMode()?void(c.txtExec&&(a.isArray(c.txtExec)?lb.sourceEditorInsertText.apply(lb,c.txtExec):c.txtExec.call(lb,b,$()))):void(c.exec&&(a.isFunction(c.exec)?c.exec.call(lb,b):lb.execCommand(c.exec,c.hasOwnProperty("execParam")?c.execParam:null)))},D=function(){jb&&(p=r.selectedRange())},lb.execCommand=function(b,c){var d=!1,e=a(r.parentNode());if(lb.focus(),!e.is("code")&&0===e.parents("code").length){try{d=l[0].execCommand(b,!1,c)}catch(f){}!d&&lb.commands[b]&&lb.commands[b].errorMessage&&alert(lb._(lb.commands[b].errorMessage))}},ab=function(){var b=function(){r&&!r.compare(w)&&(w=r.cloneSelected(),g.trigger(a.Event("selectionchanged"))),x=!1};x||(x=!0,jb?b():setTimeout(b,100))},bb=function(){var b,c=r.parentNode();u!==c&&(b=u,u=c,v=r.getFirstBlockParent(c),g.trigger(a.Event("nodechanged",{oldNode:b,newNode:u})))},lb.currentNode=function(){return u},lb.currentBlockNode=function(){return v},Z=function(a){var b,c,d,e,f,g=l[0],i=rb.length,j=lb.sourceMode();if(lb.sourceMode()||lb.readOnly())h.find(".sceditor-button").removeClass("active");else for(f=a?a.newNode:r.parentNode(),d=r.getFirstBlockParent(f);i--;)if(b=0,c=rb[i],e=h.find(".sceditor-button-"+c.name),j&&!e.data("sceditor-txtmode"))e.addClass("disabled");else if(j||e.data("sceditor-wysiwygmode")){if("string"==typeof c.state)try{b=g.queryCommandEnabled(c.state)?0:-1,b>-1&&(b=g.queryCommandState(c.state)?1:0)}catch(k){}else b=c.state.call(lb,f,d);0>b?e.addClass("disabled"):e.removeClass("disabled"),b>0?e.addClass("active"):e.removeClass("active")}else e.addClass("disabled")},S=function(b){var c,d;if(!b.originalEvent.defaultPrevented){if(lb.closeDropDown(),c=a(u),13===b.which&&(c.is("code,blockquote,pre")||0!==c.parents("code,blockquote,pre").length))return p=null,lb.wysiwygEditorInsertHtml("
    ",null,!0),!1;if(!c.is("code")&&0===c.parents("code").length)for(d=ob.length;d--;)ob[d].call(lb,b,j,m)}},_=function(){var b,c,d;a.sceditor.dom.rTraverse(k[0],function(e){return b=e.nodeName.toLowerCase(),a.inArray(b,qb)>-1&&(c=!0),3===e.nodeType&&!/^\s*$/.test(e.nodeValue)||"br"===b||kb&&!e.firstChild&&!a.sceditor.dom.isInline(e,!1)?(c&&(d=k[0].ownerDocument.createElement("div"),d.className="sceditor-nlf",d.innerHTML=kb?"":"
    ",k[0].appendChild(d)),!1):void 0})},T=function(){lb.val(nb.val())},U=function(){lb.closeDropDown(),p=null},X=function(){var a=f.height,b=f.width;lb.maximize()?lb.dimensions("100%","100%",!1):(a&&a.toString().indexOf("%")>-1||b&&b.toString().indexOf("%")>-1)&&lb.dimensions(b,a)},lb._=function(){var a,b=arguments;return q&&q[b[0]]&&(b[0]=q[b[0]]),b[0].replace(/\{(\d+)\}/g,function(c,d){return b[d-0+1]!==a?b[d-0+1]:"{"+d+"}"})},V=function(b){var c,d=a.extend({},b);t.call(d.type+"Event",b,lb),delete d.type,c=a.Event((b.target===n?"scesrc":"scewys")+b.type,d),g.trigger(c,lb),c.isDefaultPrevented()&&b.preventDefault(),c.isImmediatePropagationStopped()&&c.stopImmediatePropagation(),c.isPropagationStopped()&&c.stopPropagation()},lb.bind=function(b,c,d,e){b=b.split(" ");for(var f=b.length;f--;)a.isFunction(c)&&(d||g.bind("scewys"+b[f],c),e||g.bind("scesrc"+b[f],c),"valuechanged"===b[f]&&(gb.hasHandler=!0));return this},lb.unbind=function(b,c,d,e){b=b.split(" ");for(var f=b.length;f--;)a.isFunction(c)&&(d||g.unbind("scewys"+b[f],c),e||g.unbind("scesrc"+b[f],c));return this},lb.blur=function(b,c,d){return a.isFunction(b)?lb.bind("blur",b,c,d):lb.sourceMode()?m.blur():(s||(s=a('').appendTo(g)),s.removeAttr("disabled").show().focus().blur().hide().attr("disabled","disabled")),this},lb.focus=function(b,c,d){return a.isFunction(b)?lb.bind("focus",b,c,d):lb.inSourceMode()?n.focus():(j.contentWindow.focus(),k[0].focus(),p&&(r.selectRange(p),p=null)),this},lb.keyDown=function(a,b,c){return lb.bind("keydown",a,b,c)},lb.keyPress=function(a,b,c){return lb.bind("keypress",a,b,c)},lb.keyUp=function(a,b,c){return lb.bind("keyup",a,b,c)},lb.nodeChanged=function(a){return lb.bind("nodechanged",a,!1,!0)},lb.selectionChanged=function(a){return lb.bind("selectionchanged",a,!1,!0)},lb.valueChanged=function(a,b,c){return lb.bind("valuechanged",a,b,c)},db=function(b){var c=0,d=String.fromCharCode(b.which);if(!a(v).is("code")&&!a(v).parents("code").length)return lb.emoticonsCache||(lb.emoticonsCache=[],a.each(a.extend({},f.emoticons.more,f.emoticons.dropdown,f.emoticons.hidden),function(a,b){lb.emoticonsCache[c++]=[a,e("emoticon",{key:a,url:b.url||b,tooltip:b.tooltip||a})]}),lb.emoticonsCache.sort(function(a,b){return a[0].length-b[0].length}),lb.longestEmoticonCode=lb.emoticonsCache[lb.emoticonsCache.length-1][0].length),lb.getRangeHelper().raplaceKeyword(lb.emoticonsCache,!0,!0,lb.longestEmoticonCode,f.emoticonsCompat,d)?(f.emoticonsCompat&&(tb=k.find("img[data-sceditor-emoticon]")),/^\s$/.test(d)&&f.emoticonsCompat):void 0},eb=function(){if(tb.length){var b,c,d,e,f,g,h=lb.currentBlockNode(),i=!1,j=/[^\s\xA0\u2002\u2003\u2009\u00a0]+/;tb=a.map(tb,function(k){return k&&k.parentNode?a.contains(h,k)?(b=k.previousSibling,c=k.nextSibling,f=b.nodeValue,null===f&&(f=b.innerText||""),b&&j.test(b.nodeValue.slice(-1))||c&&j.test((c.nodeValue||"")[0])?(d=k.parentNode,e=r.cloneSelected(),g=e.startContainer,f+=a(k).data("sceditor-emoticon"),g===c?i=f.length+e.startOffset:g===h&&h.childNodes[e.startOffset]===c?i=f.length:g===b&&(i=e.startOffset),c&&3===c.nodeType||(c=d.insertBefore(d.ownerDocument.createTextNode(""),c)),c.insertData(0,f),d.removeChild(b),d.removeChild(k),i!==!1&&(e.setStart(c,i),e.collapse(!0),r.selectRange(e)),null):k):k:null})}},lb.emoticons=function(b){return b||b===!1?(f.emoticonsEnabled=b,b?(k.keypress(db),lb.sourceMode()||(r.saveRange(),B(k[0]),tb=k.find("img[data-sceditor-emoticon]"),gb(!1),r.restoreRange())):(k.find("img[data-sceditor-emoticon]").replaceWith(function(){return a(this).data("sceditor-emoticon")}),tb=[],k.unbind("keypress",db),gb()),this):f.emoticonsEnabled},lb.css=function(b){return z||(z=a('